From bd7651fa8cf8bcd2c6984b778a3e02f9808d0659 Mon Sep 17 00:00:00 2001 From: ashrafzarkanisala Date: Wed, 23 Oct 2024 01:15:17 +0300 Subject: [PATCH] push scroll bar and design enhancment --- .../view/access_management.dart | 37 ++++- lib/pages/common/curtain_toggle.dart | 8 +- lib/pages/common/custom_table.dart | 131 ++++++++++-------- .../text_field/custom_web_textfield.dart | 47 +++---- .../ac/view/ac_device_control.dart | 6 +- .../widgets/device_managment_body.dart | 3 +- .../gateway/view/gateway_view.dart | 75 +++++++--- .../shared/device_control_dialog.dart | 5 +- .../shared/device_controls_container.dart | 27 ++-- lib/utils/theme/theme.dart | 1 + pubspec.lock | 8 ++ pubspec.yaml | 1 + 12 files changed, 218 insertions(+), 131 deletions(-) diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index 8a6fa022..caa5fe28 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -15,8 +15,8 @@ import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/app_enum.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart'; -import 'package:syncrow_web/utils/style.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; +import 'package:syncrow_web/utils/style.dart'; import 'package:syncrow_web/web_layout/web_scaffold.dart'; class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { @@ -183,6 +183,14 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { isRequired: false, textFieldName: 'Name', description: '', + onSubmitted: (value) { + accessBloc.add(FilterDataEvent( + emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(), + selectedTabIndex: BlocProvider.of(context).selectedIndex, + passwordName: accessBloc.passwordName.text.toLowerCase(), + startTime: accessBloc.effectiveTimeTimeStamp, + endTime: accessBloc.expirationTimeTimeStamp)); + }, ), ), const SizedBox(width: 15), @@ -194,6 +202,14 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { isRequired: false, textFieldName: 'Authorizer', description: '', + onSubmitted: (value) { + accessBloc.add(FilterDataEvent( + emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(), + selectedTabIndex: BlocProvider.of(context).selectedIndex, + passwordName: accessBloc.passwordName.text.toLowerCase(), + startTime: accessBloc.effectiveTimeTimeStamp, + endTime: accessBloc.expirationTimeTimeStamp)); + }, ), ), const SizedBox(width: 15), @@ -239,12 +255,19 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { SizedBox( width: 300, child: CustomWebTextField( - controller: accessBloc.passwordName, - isRequired: true, - height: 40, - textFieldName: 'Name', - description: '', - ), + controller: accessBloc.passwordName, + isRequired: true, + height: 40, + textFieldName: 'Name', + description: '', + onSubmitted: (value) { + accessBloc.add(FilterDataEvent( + emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(), + selectedTabIndex: BlocProvider.of(context).selectedIndex, + passwordName: accessBloc.passwordName.text.toLowerCase(), + startTime: accessBloc.effectiveTimeTimeStamp, + endTime: accessBloc.expirationTimeTimeStamp)); + }), ), DateTimeWebWidget( icon: Assets.calendarIcon, diff --git a/lib/pages/common/curtain_toggle.dart b/lib/pages/common/curtain_toggle.dart index 305ede03..7b1551c5 100644 --- a/lib/pages/common/curtain_toggle.dart +++ b/lib/pages/common/curtain_toggle.dart @@ -26,9 +26,12 @@ class CurtainToggle extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ + const SizedBox( + height: 10, + ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, children: [ ClipOval( child: Container( @@ -41,6 +44,9 @@ class CurtainToggle extends StatelessWidget { ), ), ), + const SizedBox( + width: 20, + ), SizedBox( height: 20, width: 35, diff --git a/lib/pages/common/custom_table.dart b/lib/pages/common/custom_table.dart index 5b6692ae..10171c33 100644 --- a/lib/pages/common/custom_table.dart +++ b/lib/pages/common/custom_table.dart @@ -4,6 +4,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_managment_bloc.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; class DynamicTable extends StatefulWidget { final List headers; @@ -45,6 +46,8 @@ class DynamicTable extends StatefulWidget { class _DynamicTableState extends State { late List _selectedRows; bool _selectAll = false; + final ScrollController _verticalScrollController = ScrollController(); + final ScrollController _horizontalScrollController = ScrollController(); @override void initState() { @@ -102,68 +105,78 @@ class _DynamicTableState extends State { Widget build(BuildContext context) { return Container( decoration: widget.cellDecoration, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SizedBox( - width: widget.size.width, - child: Column( - children: [ - Container( - decoration: widget.headerDecoration ?? BoxDecoration(color: Colors.grey[200]), - child: Row( + child: Scrollbar( + controller: _verticalScrollController, + thumbVisibility: true, + trackVisibility: true, + child: Scrollbar( + controller: _horizontalScrollController, + thumbVisibility: false, + trackVisibility: false, + notificationPredicate: (notif) => notif.depth == 1, + child: SingleChildScrollView( + controller: _verticalScrollController, + child: SingleChildScrollView( + controller: _horizontalScrollController, + scrollDirection: Axis.horizontal, + child: SizedBox( + width: widget.size.width, + child: Column( children: [ - if (widget.withCheckBox) _buildSelectAllCheckbox(), - ...widget.headers.map((header) => _buildTableHeaderCell(header)), - ], - ), - ), - widget.isEmpty - ? Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, + Container( + decoration: widget.headerDecoration ?? + const BoxDecoration( + color: ColorsManager.boxColor, + ), + child: Row( children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, + if (widget.withCheckBox) _buildSelectAllCheckbox(), + ...widget.headers.map((header) => _buildTableHeaderCell(header)), + ], + ), + ), + widget.isEmpty + ? Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Column( + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, children: [ - SvgPicture.asset(Assets.emptyTable), - const SizedBox( - height: 15, + Column( + children: [ + SvgPicture.asset(Assets.emptyTable), + const SizedBox( + height: 15, + ), + Text( + widget.tableName == 'AccessManagement' ? 'No Password ' : 'No Devices', + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith(color: ColorsManager.grayColor), + ) + ], ), - Text( - // no password - widget.tableName == 'AccessManagement' ? 'No Password ' : 'No Devices', - style: - Theme.of(context).textTheme.bodySmall!.copyWith(color: ColorsManager.grayColor), - ) ], ), ], + ) + : Column( + children: List.generate(widget.data.length, (index) { + final row = widget.data[index]; + return Row( + children: [ + if (widget.withCheckBox) _buildRowCheckbox(index, widget.size.height * 0.08), + ...row.map((cell) => _buildTableCell(cell.toString(), widget.size.height * 0.08)), + ], + ); + }), ), - ], - ), - ) - : Expanded( - child: Container( - color: Colors.white, - child: ListView.builder( - shrinkWrap: true, - itemCount: widget.data.length, - itemBuilder: (context, index) { - final row = widget.data[index]; - return Row( - children: [ - if (widget.withCheckBox) _buildRowCheckbox(index, widget.size.height * 0.10), - ...row.map((cell) => _buildTableCell(cell.toString(), widget.size.height * 0.10)), - ], - ); - }, - ), - ), - ), - ], + ], + ), + ), + ), ), ), ), @@ -173,7 +186,6 @@ class _DynamicTableState extends State { Widget _buildSelectAllCheckbox() { return Container( width: 50, - padding: const EdgeInsets.all(8.0), decoration: const BoxDecoration( border: Border.symmetric( vertical: BorderSide(color: ColorsManager.boxDivider), @@ -198,6 +210,7 @@ class _DynamicTableState extends State { width: 1.0, ), ), + color: ColorsManager.whiteColors, ), alignment: Alignment.centerLeft, child: Center( @@ -219,15 +232,16 @@ class _DynamicTableState extends State { vertical: BorderSide(color: ColorsManager.boxDivider), ), ), + constraints: const BoxConstraints.expand(height: 40), alignment: Alignment.centerLeft, child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4), child: Text( title, - style: const TextStyle( + style: context.textTheme.titleSmall!.copyWith( + color: ColorsManager.grayColor, + fontSize: 12, fontWeight: FontWeight.w400, - fontSize: 13, - color: Color(0xFF999999), ), maxLines: 2, ), @@ -276,6 +290,7 @@ class _DynamicTableState extends State { width: 1.0, ), ), + color: Colors.white, ), alignment: Alignment.centerLeft, child: Text( @@ -286,7 +301,7 @@ class _DynamicTableState extends State { : (batteryLevel != null && batteryLevel > 20) ? ColorsManager.green : statusColor, - fontSize: 10, + fontSize: 13, fontWeight: FontWeight.w400), maxLines: 2, ), diff --git a/lib/pages/common/text_field/custom_web_textfield.dart b/lib/pages/common/text_field/custom_web_textfield.dart index 756463e2..d5c64e8d 100644 --- a/lib/pages/common/text_field/custom_web_textfield.dart +++ b/lib/pages/common/text_field/custom_web_textfield.dart @@ -13,6 +13,7 @@ class CustomWebTextField extends StatelessWidget { this.validator, this.hintText, this.height, + this.onSubmitted, }); final bool isRequired; @@ -22,6 +23,7 @@ class CustomWebTextField extends StatelessWidget { final String? Function(String?)? validator; final String? hintText; final double? height; + final ValueChanged? onSubmitted; @override Widget build(BuildContext context) { @@ -32,33 +34,29 @@ class CustomWebTextField extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - - Row( - children: [ - if (isRequired) - Text('* ', - style: Theme.of(context) - .textTheme.bodyMedium! - .copyWith(color: Colors.red), - ), + Row( + children: [ + if (isRequired) Text( - textFieldName, - style: Theme.of(context) - .textTheme.bodySmall! - .copyWith(color: Colors.black, fontSize: 13), + '* ', + style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: Colors.red), ), - ], - ), + Text( + textFieldName, + style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.black, fontSize: 13), + ), + ], + ), const SizedBox( width: 10, ), Expanded( child: Text( description ?? '', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontSize: 9, - fontWeight: FontWeight.w400, - color: ColorsManager.textGray), + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith(fontSize: 9, fontWeight: FontWeight.w400, color: ColorsManager.textGray), ), ), ], @@ -68,26 +66,23 @@ class CustomWebTextField extends StatelessWidget { ), Container( height: height ?? 35, - decoration: containerDecoration.copyWith( - color: const Color(0xFFF5F6F7), - boxShadow: [ + decoration: containerDecoration.copyWith(color: const Color(0xFFF5F6F7), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.3), spreadRadius: 2, blurRadius: 3, offset: const Offset(1, 1), // changes position of shadow ), - ] - ), + ]), child: TextFormField( validator: validator, controller: controller, style: const TextStyle(color: Colors.black), decoration: textBoxDecoration()!.copyWith( errorStyle: const TextStyle(height: 0), - hintStyle: context.textTheme.titleSmall! - .copyWith(color: Colors.grey, fontSize: 12), + hintStyle: context.textTheme.titleSmall!.copyWith(color: Colors.grey, fontSize: 12), hintText: hintText ?? 'Please enter'), + onFieldSubmitted: onSubmitted, ), ), ], diff --git a/lib/pages/device_managment/ac/view/ac_device_control.dart b/lib/pages/device_managment/ac/view/ac_device_control.dart index 37d3a402..5197d722 100644 --- a/lib/pages/device_managment/ac/view/ac_device_control.dart +++ b/lib/pages/device_managment/ac/view/ac_device_control.dart @@ -40,7 +40,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout { : 1, mainAxisExtent: 140, crossAxisSpacing: 12, - mainAxisSpacing: 12, + mainAxisSpacing: 16, ), children: [ ToggleWidget( @@ -81,6 +81,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ IconButton( + padding: const EdgeInsets.all(0), onPressed: () {}, icon: const Icon( Icons.remove, @@ -108,6 +109,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout { ), Text('m', style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor)), IconButton( + padding: const EdgeInsets.all(0), onPressed: () {}, icon: const Icon( Icons.add, @@ -127,7 +129,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout { deviceId: device.uuid!, code: 'child_lock', value: state.status.childLock, - label: 'Child Lock', + label: 'Lock', icon: state.status.childLock ? Assets.acLock : Assets.unlock, onChange: (value) { context.read().add( diff --git a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart index 2787c7b9..366775bf 100644 --- a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart +++ b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart @@ -8,7 +8,6 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_search_filters.dart'; import 'package:syncrow_web/pages/device_managment/shared/device_batch_control_dialog.dart'; import 'package:syncrow_web/pages/device_managment/shared/device_control_dialog.dart'; -import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/format_date_time.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; import 'package:syncrow_web/utils/style.dart'; @@ -132,7 +131,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { context.read().add(SelectDevice(selectedDevice)); }, withCheckBox: true, - size: context.screenSize, + size: MediaQuery.of(context).size, uuidIndex: 2, headers: const [ 'Device Name', diff --git a/lib/pages/device_managment/gateway/view/gateway_view.dart b/lib/pages/device_managment/gateway/view/gateway_view.dart index 2bfc6822..d674e4d8 100644 --- a/lib/pages/device_managment/gateway/view/gateway_view.dart +++ b/lib/pages/device_managment/gateway/view/gateway_view.dart @@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/device_managment/gateway/bloc/gate_way_bloc.da import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart'; import 'package:syncrow_web/pages/visitor_password/model/device_model.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; class GateWayControlsView extends StatelessWidget with HelperResponsiveLayout { @@ -25,25 +26,61 @@ class GateWayControlsView extends StatelessWidget with HelperResponsiveLayout { if (state is GatewayLoadingState) { return const Center(child: CircularProgressIndicator()); } else if (state is UpdateGatewayState) { - return GridView.builder( - padding: const EdgeInsets.symmetric(horizontal: 50), - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: isLarge || isExtraLarge - ? 3 - : isMedium - ? 2 - : 1, - mainAxisExtent: 140, - crossAxisSpacing: 12, - mainAxisSpacing: 12, - ), - itemCount: state.list.length, - itemBuilder: (context, index) { - final device = state.list[index]; - return _DeviceItem(device: device); - }, + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: const EdgeInsets.symmetric(horizontal: 50), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "Bluetooth Devices:", + style: context.textTheme.bodyMedium!.copyWith( + color: ColorsManager.grayColor, + ), + ), + const SizedBox(height: 12), + Text( + "No devices found", + style: context.textTheme.bodySmall!.copyWith( + color: ColorsManager.blackColor, + ), + ), + const SizedBox(height: 30), + Text( + "ZigBee Devices:", + style: context.textTheme.bodyMedium!.copyWith( + color: ColorsManager.grayColor, + ), + ), + ], + ), + ), + const SizedBox(height: 12), + GridView.builder( + padding: const EdgeInsets.symmetric(horizontal: 50), + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: isLarge || isExtraLarge + ? 3 + : isMedium + ? 2 + : 1, + mainAxisExtent: 140, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + ), + itemCount: state.list.length, + itemBuilder: (context, index) { + final device = state.list[index]; + return _DeviceItem(device: device); + }, + ), + ], ); } else { return const Center(child: Text('Error fetching status')); diff --git a/lib/pages/device_managment/shared/device_control_dialog.dart b/lib/pages/device_managment/shared/device_control_dialog.dart index 14878a46..d7c592d6 100644 --- a/lib/pages/device_managment/shared/device_control_dialog.dart +++ b/lib/pages/device_managment/shared/device_control_dialog.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/helper/route_controls_based_code.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart'; +import 'package:syncrow_web/pages/device_managment/shared/device_batch_control_dialog.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/format_date_time.dart'; @@ -31,7 +32,7 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode { children: [ const SizedBox(), Text( - device.productName ?? 'Device Control', + getBatchDialogName(device), style: TextStyle( fontWeight: FontWeight.bold, fontSize: 22, @@ -64,7 +65,7 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode { ), const SizedBox(height: 20), _buildDeviceInfoSection(), - const SizedBox(height: 20), + //const SizedBox(height: 20), //// BUILD DEVICE CONTROLS /// //// ROUTE TO SPECIFIC CONTROL VIEW BASED ON DEVICE CATEGORY diff --git a/lib/pages/device_managment/shared/device_controls_container.dart b/lib/pages/device_managment/shared/device_controls_container.dart index 4f1dea59..888563da 100644 --- a/lib/pages/device_managment/shared/device_controls_container.dart +++ b/lib/pages/device_managment/shared/device_controls_container.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:syncrow_web/utils/color_manager.dart'; class DeviceControlsContainer extends StatelessWidget { const DeviceControlsContainer({required this.child, this.padding, super.key}); @@ -8,21 +7,21 @@ class DeviceControlsContainer extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( - decoration: BoxDecoration( + return Card( + shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), - color: ColorsManager.greyColor.withOpacity(0.2), - - // boxShadow: [ - // BoxShadow( - // color: ColorsManager.blackColor.withOpacity(0.05), - // blurRadius: 6.0, - // offset: const Offset(0, 5), - // spreadRadius: 0) - // ], ), - padding: EdgeInsets.all(padding ?? 12), - child: child, + elevation: 3, + surfaceTintColor: Colors.transparent, + child: Container( + decoration: BoxDecoration( + color: Colors.grey.shade100, + borderRadius: BorderRadius.circular(20), + ), + padding: + EdgeInsets.symmetric(vertical: padding ?? 10, horizontal: padding ?? 16), //EdgeInsets.all(padding ?? 12), + child: child, + ), ); } } diff --git a/lib/utils/theme/theme.dart b/lib/utils/theme/theme.dart index 413f3243..5ac61afa 100644 --- a/lib/utils/theme/theme.dart +++ b/lib/utils/theme/theme.dart @@ -3,6 +3,7 @@ import 'package:syncrow_web/utils/color_manager.dart'; final myTheme = ThemeData( fontFamily: 'Aftika', + useMaterial3: true, textTheme: const TextTheme( bodySmall: TextStyle( fontSize: 13, diff --git a/pubspec.lock b/pubspec.lock index 2c9cb88c..155d063b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -613,6 +613,14 @@ packages: url: "https://pub.dev" source: hosted version: "14.2.5" + vs_scrollbar: + dependency: "direct main" + description: + name: vs_scrollbar + sha256: "6a2df5e2597064e8dbb8fc3679065d8e748d711fa979f045328c98b7100b1665" + url: "https://pub.dev" + source: hosted + version: "1.0.0" web: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index dfeb1ff9..6c74f448 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -49,6 +49,7 @@ dependencies: intl: ^0.19.0 dropdown_search: ^5.0.6 flutter_dotenv: ^5.1.0 + vs_scrollbar: ^1.0.0 dev_dependencies: flutter_test: