From 140f4ff5e20e4e4b760d1ee355c8437db691bc8e Mon Sep 17 00:00:00 2001 From: mohammad Date: Mon, 14 Apr 2025 09:57:25 +0300 Subject: [PATCH 1/7] Refactor AC device controls and toggle widget --- .../device_managment/ac/bloc/ac_bloc.dart | 21 ++++++++++++------- .../shared/toggle_widget.dart | 3 --- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/pages/device_managment/ac/bloc/ac_bloc.dart b/lib/pages/device_managment/ac/bloc/ac_bloc.dart index 076e9050..3da6e848 100644 --- a/lib/pages/device_managment/ac/bloc/ac_bloc.dart +++ b/lib/pages/device_managment/ac/bloc/ac_bloc.dart @@ -331,10 +331,13 @@ class AcBloc extends Bloc { try { final scaledValue = totalMinutes ~/ 6; - await DevicesManagementApi().deviceControl( - deviceId, - Status(code: 'countdown_time', value: scaledValue), - ); + Future.delayed(const Duration(seconds: 1), () async { + await DevicesManagementApi().deviceControl( + deviceId, + Status(code: 'countdown_time', value: scaledValue), + ); + }); + _startCountdownTimer(emit); emit(currentState.copyWith(isTimerActive: timerActive)); } catch (e) { @@ -342,10 +345,12 @@ class AcBloc extends Bloc { emit(AcsFailedState(error: e.toString())); } } else { - await DevicesManagementApi().deviceControl( - deviceId, - Status(code: 'countdown_time', value: 0), - ); + Future.delayed(const Duration(seconds: 1), () async { + await DevicesManagementApi().deviceControl( + deviceId, + Status(code: 'countdown_time', value: 0), + ); + }); _countdownTimer?.cancel(); scheduledHours = 0; scheduledMinutes = 0; diff --git a/lib/pages/device_managment/shared/toggle_widget.dart b/lib/pages/device_managment/shared/toggle_widget.dart index ad0ba8ad..4888572f 100644 --- a/lib/pages/device_managment/shared/toggle_widget.dart +++ b/lib/pages/device_managment/shared/toggle_widget.dart @@ -62,9 +62,6 @@ class ToggleWidget extends StatelessWidget { )), if (showToggle) Container( - height: 20, - width: 35, - padding: const EdgeInsets.only(right: 16, top: 10), child: CupertinoSwitch( value: value, activeColor: ColorsManager.dialogBlueTitle, From db84a9aa5ef3cf0b7d2ba0e8d44d35b37c0071a0 Mon Sep 17 00:00:00 2001 From: mohammad Date: Mon, 14 Apr 2025 16:03:34 +0300 Subject: [PATCH 2/7] fix a logic --- .../device_managment/ac/bloc/ac_bloc.dart | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/lib/pages/device_managment/ac/bloc/ac_bloc.dart b/lib/pages/device_managment/ac/bloc/ac_bloc.dart index 3da6e848..501d29d8 100644 --- a/lib/pages/device_managment/ac/bloc/ac_bloc.dart +++ b/lib/pages/device_managment/ac/bloc/ac_bloc.dart @@ -331,13 +331,14 @@ class AcBloc extends Bloc { try { final scaledValue = totalMinutes ~/ 6; - Future.delayed(const Duration(seconds: 1), () async { - await DevicesManagementApi().deviceControl( - deviceId, - Status(code: 'countdown_time', value: scaledValue), - ); - }); - + await _runDebounce( + isBatch: false, + deviceId: deviceId, + code: 'countdown_time', + value: scaledValue, + oldValue: scaledValue, + emit: emit, + ); _startCountdownTimer(emit); emit(currentState.copyWith(isTimerActive: timerActive)); } catch (e) { @@ -345,12 +346,14 @@ class AcBloc extends Bloc { emit(AcsFailedState(error: e.toString())); } } else { - Future.delayed(const Duration(seconds: 1), () async { - await DevicesManagementApi().deviceControl( - deviceId, - Status(code: 'countdown_time', value: 0), - ); - }); + await _runDebounce( + isBatch: false, + deviceId: deviceId, + code: 'countdown_time', + value: 0, + oldValue: 0, + emit: emit, + ); _countdownTimer?.cancel(); scheduledHours = 0; scheduledMinutes = 0; From 4849bb41ba1c4112d09b65493c2ff83b82841658 Mon Sep 17 00:00:00 2001 From: Abdullah Alassaf Date: Tue, 15 Apr 2025 02:13:00 +0300 Subject: [PATCH 3/7] Added function to single card, included tag and location to cards --- assets/icons/device_tag_ic.svg | 4 + .../all_devices/models/device_sub_space.dart | 18 + .../all_devices/models/device_tag_model.dart | 20 + .../all_devices/models/devices_model.dart | 154 +++--- .../functions_bloc/functions_bloc_bloc.dart | 1 + .../bloc/routine_bloc/routine_bloc.dart | 468 ++++++++---------- lib/pages/routines/widgets/dragable_card.dart | 85 +++- .../routines/widgets/routine_devices.dart | 6 +- .../one_gang_switch_dialog.dart | 43 +- lib/utils/constants/assets.dart | 176 +++---- 10 files changed, 469 insertions(+), 506 deletions(-) create mode 100644 assets/icons/device_tag_ic.svg create mode 100644 lib/pages/device_managment/all_devices/models/device_sub_space.dart create mode 100644 lib/pages/device_managment/all_devices/models/device_tag_model.dart diff --git a/assets/icons/device_tag_ic.svg b/assets/icons/device_tag_ic.svg new file mode 100644 index 00000000..830b6129 --- /dev/null +++ b/assets/icons/device_tag_ic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/lib/pages/device_managment/all_devices/models/device_sub_space.dart b/lib/pages/device_managment/all_devices/models/device_sub_space.dart new file mode 100644 index 00000000..96195f76 --- /dev/null +++ b/lib/pages/device_managment/all_devices/models/device_sub_space.dart @@ -0,0 +1,18 @@ +class DeviceSubSpace { + String? id; + String? createdAt; + String? updatedAt; + String? subspaceName; + bool? disabled; + + DeviceSubSpace({this.id, this.createdAt, this.updatedAt, this.subspaceName, this.disabled}); + + DeviceSubSpace.fromJson(Map json) { + id = json['uuid']?.toString() ?? ''; + createdAt = json['createdAt']?.toString() ?? ''; + updatedAt = json['updatedAt']?.toString() ?? ''; + subspaceName = json['subspaceName']?.toString() ?? ''; + subspaceName = json['subspaceName']?.toString() ?? ''; + disabled = json['disabled'] ?? false; + } +} diff --git a/lib/pages/device_managment/all_devices/models/device_tag_model.dart b/lib/pages/device_managment/all_devices/models/device_tag_model.dart new file mode 100644 index 00000000..12580d3f --- /dev/null +++ b/lib/pages/device_managment/all_devices/models/device_tag_model.dart @@ -0,0 +1,20 @@ +class DeviceTagModel { + String? id; + String? createdAt; + String? updatedAt; + String? name; + + DeviceTagModel({ + this.id, + this.createdAt, + this.updatedAt, + this.name, + }); + + DeviceTagModel.fromJson(Map json) { + id = json['uuid']?.toString() ?? ''; + createdAt = json['createdAt']?.toString() ?? ''; + updatedAt = json['updatedAt']?.toString() ?? ''; + name = json['name']?.toString() ?? ''; + } +} diff --git a/lib/pages/device_managment/all_devices/models/devices_model.dart b/lib/pages/device_managment/all_devices/models/devices_model.dart index 2ea085c5..c7c35eca 100644 --- a/lib/pages/device_managment/all_devices/models/devices_model.dart +++ b/lib/pages/device_managment/all_devices/models/devices_model.dart @@ -1,6 +1,8 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/device_community.model.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/device_space_model.dart'; +import 'package:syncrow_web/pages/device_managment/all_devices/models/device_sub_space.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/device_subspace.model.dart'; +import 'package:syncrow_web/pages/device_managment/all_devices/models/device_tag_model.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/room.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/unit.dart'; import 'package:syncrow_web/pages/routines/models/ac/ac_function.dart'; @@ -78,38 +80,41 @@ class AllDevicesModel { int? batteryLevel; String? productName; List? spaces; + List? deviceTags; + DeviceSubSpace? deviceSubSpace; - AllDevicesModel({ - this.room, - this.subspace, - this.unit, - this.community, - this.productUuid, - this.productType, - this.permissionType, - this.activeTime, - this.category, - this.categoryName, - this.createTime, - this.gatewayId, - this.icon, - this.ip, - this.lat, - this.localKey, - this.lon, - this.model, - this.name, - this.nodeId, - this.online, - this.ownerId, - this.sub, - this.timeZone, - this.updateTime, - this.uuid, - this.batteryLevel, - this.productName, - this.spaces, - }); + AllDevicesModel( + {this.room, + this.subspace, + this.unit, + this.community, + this.productUuid, + this.productType, + this.permissionType, + this.activeTime, + this.category, + this.categoryName, + this.createTime, + this.gatewayId, + this.icon, + this.ip, + this.lat, + this.localKey, + this.lon, + this.model, + this.name, + this.nodeId, + this.online, + this.ownerId, + this.sub, + this.timeZone, + this.updateTime, + this.uuid, + this.batteryLevel, + this.productName, + this.spaces, + this.deviceTags, + this.deviceSubSpace}); AllDevicesModel.fromJson(Map json) { room = (json['room'] != null && (json['room'] is Map)) @@ -147,12 +152,15 @@ class AllDevicesModel { updateTime = int.tryParse(json['updateTime']?.toString() ?? ''); uuid = json['uuid']?.toString(); batteryLevel = int.tryParse(json['battery']?.toString() ?? ''); - productName = json['productName']?.toString(); + deviceTags = json['deviceTag'] != null && json['deviceTag'] is List + ? (json['deviceTag'] as List).map((tag) => DeviceTagModel.fromJson(tag)).toList() + : []; + deviceSubSpace = json['subspace'] != null + ? DeviceSubSpace.fromJson(json['subspace']) + : DeviceSubSpace(subspaceName: ''); if (json['spaces'] != null && json['spaces'] is List) { - spaces = (json['spaces'] as List) - .map((space) => DeviceSpaceModel.fromJson(space)) - .toList(); + spaces = (json['spaces'] as List).map((space) => DeviceSpaceModel.fromJson(space)).toList(); } } @@ -200,8 +208,7 @@ SOS String tempIcon = ''; if (type == DeviceType.LightBulb) { tempIcon = Assets.lightBulb; - } else if (type == DeviceType.CeilingSensor || - type == DeviceType.WallSensor) { + } else if (type == DeviceType.CeilingSensor || type == DeviceType.WallSensor) { tempIcon = Assets.sensors; } else if (type == DeviceType.AC) { tempIcon = Assets.ac; @@ -248,76 +255,51 @@ SOS switch (productType) { case 'AC': return [ - SwitchFunction( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), - ModeFunction( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), - TempSetFunction( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), - CurrentTempFunction( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'), - LevelFunction( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), - ChildLockFunction( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), + SwitchFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), + ModeFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), + TempSetFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), + CurrentTempFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'), + LevelFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), + ChildLockFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), ]; case '1G': return [ OneGangSwitchFunction(deviceId: uuid ?? '', deviceName: name ?? ''), - OneGangCountdownFunction( - deviceId: uuid ?? '', deviceName: name ?? ''), + OneGangCountdownFunction(deviceId: uuid ?? '', deviceName: name ?? ''), ]; case '2G': return [ TwoGangSwitch1Function(deviceId: uuid ?? '', deviceName: name ?? ''), TwoGangSwitch2Function(deviceId: uuid ?? '', deviceName: name ?? ''), - TwoGangCountdown1Function( - deviceId: uuid ?? '', deviceName: name ?? ''), - TwoGangCountdown2Function( - deviceId: uuid ?? '', deviceName: name ?? ''), + TwoGangCountdown1Function(deviceId: uuid ?? '', deviceName: name ?? ''), + TwoGangCountdown2Function(deviceId: uuid ?? '', deviceName: name ?? ''), ]; case '3G': return [ - ThreeGangSwitch1Function( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), - ThreeGangSwitch2Function( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), - ThreeGangSwitch3Function( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), - ThreeGangCountdown1Function( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), - ThreeGangCountdown2Function( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), - ThreeGangCountdown3Function( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), + ThreeGangSwitch1Function(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), + ThreeGangSwitch2Function(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), + ThreeGangSwitch3Function(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), + ThreeGangCountdown1Function(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), + ThreeGangCountdown2Function(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), + ThreeGangCountdown3Function(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), ]; case 'WPS': return [ //IF Functions - PresenceStateFunction( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'), - CurrentDistanceFunction( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'), - IlluminanceValueFunction( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'), - PresenceTimeFunction( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'), + PresenceStateFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'), + CurrentDistanceFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'), + IlluminanceValueFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'), + PresenceTimeFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'), //THEN Functions - FarDetectionFunction( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'), - MotionSensitivityFunction( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'), - MotionLessSensitivityFunction( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'), - IndicatorFunction( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), - NoOneTimeFunction( - deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'), - + FarDetectionFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'), + MotionSensitivityFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'), + MotionLessSensitivityFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'), + IndicatorFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'), + NoOneTimeFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'), ]; case 'GW': return [ diff --git a/lib/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart b/lib/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart index a196ff27..bb4a7a1e 100644 --- a/lib/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart +++ b/lib/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart @@ -30,6 +30,7 @@ class FunctionBloc extends Bloc { condition: event.functionData.condition ?? existingData.condition, ); } else { + functions.clear(); functions.add(event.functionData); } diff --git a/lib/pages/routines/bloc/routine_bloc/routine_bloc.dart b/lib/pages/routines/bloc/routine_bloc/routine_bloc.dart index 2664d026..b698c19e 100644 --- a/lib/pages/routines/bloc/routine_bloc/routine_bloc.dart +++ b/lib/pages/routines/bloc/routine_bloc/routine_bloc.dart @@ -64,8 +64,7 @@ class RoutineBloc extends Bloc { TriggerSwitchTabsEvent event, Emitter emit, ) { - emit(state.copyWith( - routineTab: event.isRoutineTab, createRoutineView: false)); + emit(state.copyWith(routineTab: event.isRoutineTab, createRoutineView: false)); add(ResetRoutineState()); if (event.isRoutineTab) { add(const LoadScenes()); @@ -91,8 +90,8 @@ class RoutineBloc extends Bloc { final updatedIfItems = List>.from(state.ifItems); // Find the index of the item in teh current itemsList - int index = updatedIfItems.indexWhere( - (map) => map['uniqueCustomId'] == event.item['uniqueCustomId']); + int index = + updatedIfItems.indexWhere((map) => map['uniqueCustomId'] == event.item['uniqueCustomId']); // Replace the map if the index is valid if (index != -1) { updatedIfItems[index] = event.item; @@ -101,21 +100,18 @@ class RoutineBloc extends Bloc { } if (event.isTabToRun) { - emit(state.copyWith( - ifItems: updatedIfItems, isTabToRun: true, isAutomation: false)); + emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: true, isAutomation: false)); } else { - emit(state.copyWith( - ifItems: updatedIfItems, isTabToRun: false, isAutomation: true)); + emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: false, isAutomation: true)); } } - void _onAddToThenContainer( - AddToThenContainer event, Emitter emit) { + void _onAddToThenContainer(AddToThenContainer event, Emitter emit) { final currentItems = List>.from(state.thenItems); // Find the index of the item in teh current itemsList - int index = currentItems.indexWhere( - (map) => map['uniqueCustomId'] == event.item['uniqueCustomId']); + int index = + currentItems.indexWhere((map) => map['uniqueCustomId'] == event.item['uniqueCustomId']); // Replace the map if the index is valid if (index != -1) { currentItems[index] = event.item; @@ -126,45 +122,42 @@ class RoutineBloc extends Bloc { emit(state.copyWith(thenItems: currentItems)); } - void _onAddFunctionsToRoutine( - AddFunctionToRoutine event, Emitter emit) { + void _onAddFunctionsToRoutine(AddFunctionToRoutine event, Emitter emit) { try { if (event.functions.isEmpty) return; - List selectedFunction = - List.from(event.functions); + // List selectedFunction = List.from(event.functions); Map> currentSelectedFunctions = Map>.from(state.selectedFunctions); - if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) { - List currentFunctions = - List.from( - currentSelectedFunctions[event.uniqueCustomId] ?? []); - List functionCode = []; - for (int i = 0; i < selectedFunction.length; i++) { - for (int j = 0; j < currentFunctions.length; j++) { - if (selectedFunction[i].functionCode == - currentFunctions[j].functionCode) { - currentFunctions[j] = selectedFunction[i]; - if (!functionCode.contains(currentFunctions[j].functionCode)) { - functionCode.add(currentFunctions[j].functionCode); - } - } - } - } + // if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) { + // List currentFunctions = + // List.from(currentSelectedFunctions[event.uniqueCustomId] ?? []); - for (int i = 0; i < functionCode.length; i++) { - selectedFunction - .removeWhere((code) => code.functionCode == functionCode[i]); - } + // List functionCode = []; + // for (int i = 0; i < selectedFunction.length; i++) { + // for (int j = 0; j < currentFunctions.length; j++) { + // if (selectedFunction[i].functionCode == currentFunctions[j].functionCode) { + // currentFunctions[j] = selectedFunction[i]; + // if (!functionCode.contains(currentFunctions[j].functionCode)) { + // functionCode.add(currentFunctions[j].functionCode); + // } + // } + // } + // } - currentSelectedFunctions[event.uniqueCustomId] = - List.from(currentFunctions)..addAll(selectedFunction); - } else { - currentSelectedFunctions[event.uniqueCustomId] = - List.from(event.functions); - } + // for (int i = 0; i < functionCode.length; i++) { + // selectedFunction.removeWhere((code) => code.functionCode == functionCode[i]); + // } + + // currentSelectedFunctions[event.uniqueCustomId] = List.from(currentFunctions) + // ..addAll(selectedFunction); + // } else { + // currentSelectedFunctions[event.uniqueCustomId] = List.from(event.functions); + // } + + currentSelectedFunctions[event.uniqueCustomId] = List.from(event.functions); emit(state.copyWith(selectedFunctions: currentSelectedFunctions)); } catch (e) { @@ -172,30 +165,24 @@ class RoutineBloc extends Bloc { } } - Future _onLoadScenes( - LoadScenes event, Emitter emit) async { + Future _onLoadScenes(LoadScenes event, Emitter emit) async { emit(state.copyWith(isLoading: true, errorMessage: null)); List scenes = []; try { BuildContext context = NavigationService.navigatorKey.currentContext!; var createRoutineBloc = context.read(); final projectUuid = await ProjectManager.getProjectUUID() ?? ''; - if (createRoutineBloc.selectedSpaceId == '' && - createRoutineBloc.selectedCommunityId == '') { + if (createRoutineBloc.selectedSpaceId == '' && createRoutineBloc.selectedCommunityId == '') { var spaceBloc = context.read(); for (var communityId in spaceBloc.state.selectedCommunities) { - List spacesList = - spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? []; + List spacesList = spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? []; for (var spaceId in spacesList) { - scenes.addAll( - await SceneApi.getScenes(spaceId, communityId, projectUuid)); + scenes.addAll(await SceneApi.getScenes(spaceId, communityId, projectUuid)); } } } else { scenes.addAll(await SceneApi.getScenes( - createRoutineBloc.selectedSpaceId, - createRoutineBloc.selectedCommunityId, - projectUuid)); + createRoutineBloc.selectedSpaceId, createRoutineBloc.selectedCommunityId, projectUuid)); } emit(state.copyWith( @@ -212,8 +199,7 @@ class RoutineBloc extends Bloc { } } - Future _onLoadAutomation( - LoadAutomation event, Emitter emit) async { + Future _onLoadAutomation(LoadAutomation event, Emitter emit) async { emit(state.copyWith(isLoading: true, errorMessage: null)); List automations = []; final projectId = await ProjectManager.getProjectUUID() ?? ''; @@ -221,23 +207,17 @@ class RoutineBloc extends Bloc { BuildContext context = NavigationService.navigatorKey.currentContext!; var createRoutineBloc = context.read(); try { - - if (createRoutineBloc.selectedSpaceId == '' && - createRoutineBloc.selectedCommunityId == '') { + if (createRoutineBloc.selectedSpaceId == '' && createRoutineBloc.selectedCommunityId == '') { var spaceBloc = context.read(); for (var communityId in spaceBloc.state.selectedCommunities) { - List spacesList = - spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? []; + List spacesList = spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? []; for (var spaceId in spacesList) { - automations.addAll( - await SceneApi.getAutomation(spaceId, communityId, projectId)); + automations.addAll(await SceneApi.getAutomation(spaceId, communityId, projectId)); } } } else { automations.addAll(await SceneApi.getAutomation( - createRoutineBloc.selectedSpaceId, - createRoutineBloc.selectedCommunityId, - projectId)); + createRoutineBloc.selectedSpaceId, createRoutineBloc.selectedCommunityId, projectId)); } emit(state.copyWith( automations: automations, @@ -253,16 +233,14 @@ class RoutineBloc extends Bloc { } } - FutureOr _onSearchRoutines( - SearchRoutines event, Emitter emit) async { + FutureOr _onSearchRoutines(SearchRoutines event, Emitter emit) async { emit(state.copyWith(isLoading: true, errorMessage: null)); await Future.delayed(const Duration(seconds: 1)); emit(state.copyWith(isLoading: false, errorMessage: null)); emit(state.copyWith(searchText: event.query)); } - FutureOr _onAddSelectedIcon( - AddSelectedIcon event, Emitter emit) { + FutureOr _onAddSelectedIcon(AddSelectedIcon event, Emitter emit) { emit(state.copyWith(selectedIcon: event.icon)); } @@ -276,8 +254,7 @@ class RoutineBloc extends Bloc { return actions.last['deviceId'] == 'delay'; } - Future _onCreateScene( - CreateSceneEvent event, Emitter emit) async { + Future _onCreateScene(CreateSceneEvent event, Emitter emit) async { try { // Check if first action is delay // if (_isFirstActionDelay(state.thenItems)) { @@ -290,8 +267,7 @@ class RoutineBloc extends Bloc { if (_isLastActionDelay(state.thenItems)) { emit(state.copyWith( - errorMessage: - 'A delay condition cannot be the only or the last action', + errorMessage: 'A delay condition cannot be the only or the last action', isLoading: false, )); return; @@ -367,8 +343,7 @@ class RoutineBloc extends Bloc { } } - Future _onCreateAutomation( - CreateAutomationEvent event, Emitter emit) async { + Future _onCreateAutomation(CreateAutomationEvent event, Emitter emit) async { try { final projectUuid = await ProjectManager.getProjectUUID() ?? ''; if (state.routineName == null || state.routineName!.isEmpty) { @@ -390,8 +365,7 @@ class RoutineBloc extends Bloc { if (_isLastActionDelay(state.thenItems)) { emit(state.copyWith( - errorMessage: - 'A delay condition cannot be the only or the last action', + errorMessage: 'A delay condition cannot be the only or the last action', isLoading: false, )); CustomSnackBar.redSnackBar('Cannot have delay as the last action'); @@ -482,8 +456,7 @@ class RoutineBloc extends Bloc { actions: actions, ); - final result = - await SceneApi.createAutomation(createAutomationModel, projectUuid); + final result = await SceneApi.createAutomation(createAutomationModel, projectUuid); if (result['success']) { add(ResetRoutineState()); add(const LoadAutomation()); @@ -504,21 +477,17 @@ class RoutineBloc extends Bloc { } } - FutureOr _onRemoveDragCard( - RemoveDragCard event, Emitter emit) { + FutureOr _onRemoveDragCard(RemoveDragCard event, Emitter emit) { if (event.isFromThen) { final thenItems = List>.from(state.thenItems); - final selectedFunctions = - Map>.from(state.selectedFunctions); + final selectedFunctions = Map>.from(state.selectedFunctions); thenItems.removeAt(event.index); selectedFunctions.remove(event.key); - emit(state.copyWith( - thenItems: thenItems, selectedFunctions: selectedFunctions)); + emit(state.copyWith(thenItems: thenItems, selectedFunctions: selectedFunctions)); } else { final ifItems = List>.from(state.ifItems); - final selectedFunctions = - Map>.from(state.selectedFunctions); + final selectedFunctions = Map>.from(state.selectedFunctions); ifItems.removeAt(event.index); selectedFunctions.remove(event.key); @@ -529,8 +498,7 @@ class RoutineBloc extends Bloc { isAutomation: false, isTabToRun: false)); } else { - emit(state.copyWith( - ifItems: ifItems, selectedFunctions: selectedFunctions)); + emit(state.copyWith(ifItems: ifItems, selectedFunctions: selectedFunctions)); } } } @@ -542,141 +510,138 @@ class RoutineBloc extends Bloc { )); } - FutureOr _onEffectiveTimeEvent( - EffectiveTimePeriodEvent event, Emitter emit) { + FutureOr _onEffectiveTimeEvent(EffectiveTimePeriodEvent event, Emitter emit) { emit(state.copyWith(effectiveTime: event.effectiveTime)); } - FutureOr _onSetRoutineName( - SetRoutineName event, Emitter emit) { + FutureOr _onSetRoutineName(SetRoutineName event, Emitter emit) { emit(state.copyWith( routineName: event.name, )); } - ( - List>, - List>, - Map> - ) _createCardData( - List actions, - List? conditions, - Map> currentFunctions, - bool isTabToRun, - ) { - final ifItems = isTabToRun - ? [ - { - 'entityId': 'tab_to_run', - 'uniqueCustomId': const Uuid().v4(), - 'deviceId': 'tab_to_run', - 'title': 'Tab to run', - 'productType': 'tab_to_run', - 'imagePath': Assets.tabToRun, - } - ] - : conditions?.map((condition) { - final matchingDevice = state.devices.firstWhere( - (device) => device.uuid == condition.entityId, - orElse: () => AllDevicesModel( - uuid: condition.entityId, - name: condition.entityId, - productType: condition.entityType, - ), - ); + // ( + // List>, + // List>, + // Map> + // ) _createCardData( + // List actions, + // List? conditions, + // Map> currentFunctions, + // bool isTabToRun, + // ) { + // final ifItems = isTabToRun + // ? [ + // { + // 'entityId': 'tab_to_run', + // 'uniqueCustomId': const Uuid().v4(), + // 'deviceId': 'tab_to_run', + // 'title': 'Tab to run', + // 'productType': 'tab_to_run', + // 'imagePath': Assets.tabToRun, + // } + // ] + // : conditions?.map((condition) { + // final matchingDevice = state.devices.firstWhere( + // (device) => device.uuid == condition.entityId, + // orElse: () => AllDevicesModel( + // uuid: condition.entityId, + // name: condition.entityId, + // productType: condition.entityType, + // ), + // ); - final cardData = { - 'entityId': condition.entityId, - 'uniqueCustomId': const Uuid().v4(), - 'deviceId': condition.entityId, - 'title': matchingDevice.name ?? condition.entityId, - 'productType': condition.entityType, - 'imagePath': - matchingDevice.getDefaultIcon(condition.entityType), - }; + // final cardData = { + // 'entityId': condition.entityId, + // 'uniqueCustomId': const Uuid().v4(), + // 'deviceId': condition.entityId, + // 'title': matchingDevice.name ?? condition.entityId, + // 'productType': condition.entityType, + // 'imagePath': + // matchingDevice.getDefaultIcon(condition.entityType), + // }; - final functions = matchingDevice.functions; + // final functions = matchingDevice.functions; - for (var function in functions) { - if (function.code == condition.expr.statusCode) { - currentFunctions[cardData['uniqueCustomId'] ?? ''] = [ - DeviceFunctionData( - entityId: condition.entityId, - functionCode: condition.expr.statusCode, - value: condition.expr.statusValue, - operationName: function.operationName, - ), - ]; - break; - } - } + // for (var function in functions) { + // if (function.code == condition.expr.statusCode) { + // currentFunctions[cardData['uniqueCustomId'] ?? ''] = [ + // DeviceFunctionData( + // entityId: condition.entityId, + // functionCode: condition.expr.statusCode, + // value: condition.expr.statusValue, + // operationName: function.operationName, + // ), + // ]; + // break; + // } + // } - return cardData; - }).toList() ?? - []; + // return cardData; + // }).toList() ?? + // []; - final thenItems = actions.map((action) { - final matchingDevice = state.devices.firstWhere( - (device) => device.uuid == action.entityId, - orElse: () => AllDevicesModel( - uuid: action.entityId, - name: action.entityId, - productType: action.productType, - ), - ); + // final thenItems = actions.map((action) { + // final matchingDevice = state.devices.firstWhere( + // (device) => device.uuid == action.entityId, + // orElse: () => AllDevicesModel( + // uuid: action.entityId, + // name: action.entityId, + // productType: action.productType, + // ), + // ); - final cardData = { - 'entityId': action.entityId, - 'uniqueCustomId': const Uuid().v4(), - 'deviceId': - action.actionExecutor == 'delay' ? 'delay' : action.entityId, - 'title': action.actionExecutor == 'delay' - ? 'Delay' - : (matchingDevice.name ?? 'Device'), - 'productType': action.productType, - 'imagePath': matchingDevice.getDefaultIcon(action.productType), - }; + // final cardData = { + // 'entityId': action.entityId, + // 'uniqueCustomId': const Uuid().v4(), + // 'deviceId': + // action.actionExecutor == 'delay' ? 'delay' : action.entityId, + // 'title': action.actionExecutor == 'delay' + // ? 'Delay' + // : (matchingDevice.name ?? 'Device'), + // 'productType': action.productType, + // 'imagePath': matchingDevice.getDefaultIcon(action.productType), + // }; - final functions = matchingDevice.functions; + // final functions = matchingDevice.functions; - if (action.executorProperty != null && action.actionExecutor != 'delay') { - final functionCode = action.executorProperty!.functionCode; - for (var function in functions) { - if (function.code == functionCode) { - currentFunctions[cardData['uniqueCustomId'] ?? ''] = [ - DeviceFunctionData( - entityId: action.entityId, - functionCode: functionCode ?? '', - value: action.executorProperty!.functionValue, - operationName: function.operationName, - ), - ]; - break; - } - } - } else if (action.actionExecutor == 'delay') { - final delayFunction = DelayFunction( - deviceId: action.entityId, - deviceName: 'Delay', - ); - currentFunctions[cardData['uniqueCustomId'] ?? ''] = [ - DeviceFunctionData( - entityId: action.entityId, - functionCode: 'delay', - value: action.executorProperty?.delaySeconds ?? 0, - operationName: delayFunction.operationName, - ), - ]; - } + // if (action.executorProperty != null && action.actionExecutor != 'delay') { + // final functionCode = action.executorProperty!.functionCode; + // for (var function in functions) { + // if (function.code == functionCode) { + // currentFunctions[cardData['uniqueCustomId'] ?? ''] = [ + // DeviceFunctionData( + // entityId: action.entityId, + // functionCode: functionCode ?? '', + // value: action.executorProperty!.functionValue, + // operationName: function.operationName, + // ), + // ]; + // break; + // } + // } + // } else if (action.actionExecutor == 'delay') { + // final delayFunction = DelayFunction( + // deviceId: action.entityId, + // deviceName: 'Delay', + // ); + // currentFunctions[cardData['uniqueCustomId'] ?? ''] = [ + // DeviceFunctionData( + // entityId: action.entityId, + // functionCode: 'delay', + // value: action.executorProperty?.delaySeconds ?? 0, + // operationName: delayFunction.operationName, + // ), + // ]; + // } - return cardData; - }).toList(); + // return cardData; + // }).toList(); - return (thenItems, ifItems, currentFunctions); - } + // return (thenItems, ifItems, currentFunctions); + // } - Future _onGetSceneDetails( - GetSceneDetails event, Emitter emit) async { + Future _onGetSceneDetails(GetSceneDetails event, Emitter emit) async { try { emit(state.copyWith( isLoading: true, @@ -724,12 +689,10 @@ class RoutineBloc extends Bloc { if (!deviceCards.containsKey(deviceId)) { deviceCards[deviceId] = { 'entityId': action.entityId, - 'deviceId': - action.actionExecutor == 'delay' ? 'delay' : action.entityId, - 'uniqueCustomId': - action.type == 'automation' || action.actionExecutor == 'delay' - ? const Uuid().v4() - : action.entityId, + 'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId, + 'uniqueCustomId': action.type == 'automation' || action.actionExecutor == 'delay' + ? const Uuid().v4() + : action.entityId, 'title': action.actionExecutor == 'delay' ? 'Delay' : action.type == 'automation' @@ -764,16 +727,15 @@ class RoutineBloc extends Bloc { ), ); // emit(state.copyWith(automationActionExecutor: action.actionExecutor)); - } else if (action.executorProperty != null && - action.actionExecutor != 'delay') { - if (!updatedFunctions.containsKey(uniqueCustomId)) { - updatedFunctions[uniqueCustomId] = []; - } + } else if (action.executorProperty != null && action.actionExecutor != 'delay') { + // if (!updatedFunctions.containsKey(uniqueCustomId)) { + // updatedFunctions[uniqueCustomId] = []; + // } final functions = matchingDevice?.functions; final functionCode = action.executorProperty?.functionCode; for (DeviceFunction function in functions ?? []) { if (function.code == functionCode) { - updatedFunctions[uniqueCustomId]!.add( + updatedFunctions[const Uuid().v4()]!.add( DeviceFunctionData( entityId: action.entityId, functionCode: functionCode ?? '', @@ -837,8 +799,7 @@ class RoutineBloc extends Bloc { } } - FutureOr _onResetRoutineState( - ResetRoutineState event, Emitter emit) { + FutureOr _onResetRoutineState(ResetRoutineState event, Emitter emit) { emit(state.copyWith( ifItems: [], thenItems: [], @@ -861,6 +822,7 @@ class RoutineBloc extends Bloc { isUpdate: false, createRoutineView: false)); } + FutureOr _deleteScene(DeleteScene event, Emitter emit) async { try { final projectId = await ProjectManager.getProjectUUID() ?? ''; @@ -900,7 +862,7 @@ class RoutineBloc extends Bloc { )); } } - + // FutureOr _deleteAutomation(DeleteAutomation event, Emitter emit) { // try { // emit(state.copyWith(isLoading: true)); @@ -915,8 +877,7 @@ class RoutineBloc extends Bloc { // } // } - FutureOr _fetchDevices( - FetchDevicesInRoutine event, Emitter emit) async { + FutureOr _fetchDevices(FetchDevicesInRoutine event, Emitter emit) async { emit(state.copyWith(isLoading: true)); try { final projectUuid = await ProjectManager.getProjectUUID() ?? ''; @@ -925,21 +886,17 @@ class RoutineBloc extends Bloc { var createRoutineBloc = context.read(); var spaceBloc = context.read(); - if (createRoutineBloc.selectedSpaceId == '' && - createRoutineBloc.selectedCommunityId == '') { + if (createRoutineBloc.selectedSpaceId == '' && createRoutineBloc.selectedCommunityId == '') { for (var communityId in spaceBloc.state.selectedCommunities) { - List spacesList = - spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? []; + List spacesList = spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? []; for (var spaceId in spacesList) { - devices.addAll(await DevicesManagementApi() - .fetchDevices(communityId, spaceId, projectUuid)); + devices.addAll( + await DevicesManagementApi().fetchDevices(communityId, spaceId, projectUuid)); } } } else { devices.addAll(await DevicesManagementApi().fetchDevices( - createRoutineBloc.selectedCommunityId, - createRoutineBloc.selectedSpaceId, - projectUuid)); + createRoutineBloc.selectedCommunityId, createRoutineBloc.selectedSpaceId, projectUuid)); } emit(state.copyWith(isLoading: false, devices: devices)); @@ -948,8 +905,7 @@ class RoutineBloc extends Bloc { } } - FutureOr _onUpdateScene( - UpdateScene event, Emitter emit) async { + FutureOr _onUpdateScene(UpdateScene event, Emitter emit) async { try { // Check if first action is delay // if (_isFirstActionDelay(state.thenItems)) { @@ -963,8 +919,7 @@ class RoutineBloc extends Bloc { if (_isLastActionDelay(state.thenItems)) { emit(state.copyWith( - errorMessage: - 'A delay condition cannot be the only or the last action', + errorMessage: 'A delay condition cannot be the only or the last action', isLoading: false, )); return; @@ -1017,8 +972,7 @@ class RoutineBloc extends Bloc { actions: actions, ); - final result = - await SceneApi.updateScene(createSceneModel, state.sceneId ?? ''); + final result = await SceneApi.updateScene(createSceneModel, state.sceneId ?? ''); if (result['success']) { add(ResetRoutineState()); add(const LoadScenes()); @@ -1037,8 +991,7 @@ class RoutineBloc extends Bloc { } } - FutureOr _onUpdateAutomation( - UpdateAutomation event, Emitter emit) async { + FutureOr _onUpdateAutomation(UpdateAutomation event, Emitter emit) async { try { if (state.routineName == null || state.routineName!.isEmpty) { emit(state.copyWith( @@ -1253,15 +1206,13 @@ class RoutineBloc extends Bloc { ), ); - final deviceId = action.actionExecutor == 'delay' - ? '${action.entityId}_delay' - : action.entityId; + final deviceId = + action.actionExecutor == 'delay' ? '${action.entityId}_delay' : action.entityId; if (!deviceThenCards.containsKey(deviceId)) { deviceThenCards[deviceId] = { 'entityId': action.entityId, - 'deviceId': - action.actionExecutor == 'delay' ? 'delay' : action.entityId, + 'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId, 'uniqueCustomId': const Uuid().v4(), 'title': action.actionExecutor == 'delay' ? 'Delay' @@ -1281,7 +1232,7 @@ class RoutineBloc extends Bloc { : action.type == 'automation' ? 'automation' : 'action', - 'icon': action.icon ?? '' + 'icon': action.icon ?? '', }; } @@ -1292,8 +1243,7 @@ class RoutineBloc extends Bloc { updatedFunctions[uniqueCustomId] = []; } - if (action.executorProperty != null && - action.actionExecutor != 'delay') { + if (action.executorProperty != null && action.actionExecutor != 'delay') { final functions = matchingDevice.functions; final functionCode = action.executorProperty!.functionCode; for (var function in functions) { @@ -1335,14 +1285,10 @@ class RoutineBloc extends Bloc { } } - final ifItems = deviceIfCards.values - .where((card) => card['type'] == 'condition') - .toList(); + final ifItems = deviceIfCards.values.where((card) => card['type'] == 'condition').toList(); final thenItems = deviceThenCards.values .where((card) => - card['type'] == 'action' || - card['type'] == 'automation' || - card['type'] == 'scene') + card['type'] == 'action' || card['type'] == 'automation' || card['type'] == 'scene') .toList(); emit(state.copyWith( @@ -1364,8 +1310,7 @@ class RoutineBloc extends Bloc { } } - Future _onSceneTrigger( - SceneTrigger event, Emitter emit) async { + Future _onSceneTrigger(SceneTrigger event, Emitter emit) async { emit(state.copyWith(loadingSceneId: event.sceneId)); try { @@ -1407,29 +1352,24 @@ class RoutineBloc extends Bloc { if (success) { final updatedAutomations = await SceneApi.getAutomationByUnitId( - event.automationStatusUpdate.spaceUuid, - event.communityId, - projectId); + event.automationStatusUpdate.spaceUuid, event.communityId, projectId); // Remove from loading set safely - final updatedLoadingIds = {...state.loadingAutomationIds!} - ..remove(event.automationId); + final updatedLoadingIds = {...state.loadingAutomationIds!}..remove(event.automationId); emit(state.copyWith( automations: updatedAutomations, loadingAutomationIds: updatedLoadingIds, )); } else { - final updatedLoadingIds = {...state.loadingAutomationIds!} - ..remove(event.automationId); + final updatedLoadingIds = {...state.loadingAutomationIds!}..remove(event.automationId); emit(state.copyWith( loadingAutomationIds: updatedLoadingIds, errorMessage: 'Update failed', )); } } catch (e) { - final updatedLoadingIds = {...state.loadingAutomationIds!} - ..remove(event.automationId); + final updatedLoadingIds = {...state.loadingAutomationIds!}..remove(event.automationId); emit(state.copyWith( loadingAutomationIds: updatedLoadingIds, errorMessage: 'Update error: ${e.toString()}', diff --git a/lib/pages/routines/widgets/dragable_card.dart b/lib/pages/routines/widgets/dragable_card.dart index 77786429..039732b0 100644 --- a/lib/pages/routines/widgets/dragable_card.dart +++ b/lib/pages/routines/widgets/dragable_card.dart @@ -6,6 +6,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart'; import 'package:syncrow_web/pages/routines/models/device_functions.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 DraggableCard extends StatelessWidget { @@ -70,7 +71,7 @@ class DraggableCard extends StatelessWidget { child: Container( padding: padding ?? const EdgeInsets.all(16), width: 110, - height: deviceFunctions.isEmpty ? 123 : null, + height: deviceFunctions.isEmpty ? 160 : 170, child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, @@ -78,6 +79,7 @@ class DraggableCard extends StatelessWidget { children: [ Column( mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( height: 50, @@ -101,19 +103,82 @@ class DraggableCard extends StatelessWidget { const SizedBox(height: 8), Padding( padding: const EdgeInsets.symmetric(horizontal: 3), - child: Text( - deviceData['title'] ?? deviceData['name'] ?? title, - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - maxLines: 2, - style: context.textTheme.bodySmall?.copyWith( - color: ColorsManager.blackColor, - fontSize: 12, + child: Flexible( + child: Text( + deviceData['title'] ?? deviceData['name'] ?? title, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + maxLines: 2, + style: context.textTheme.bodySmall?.copyWith( + color: ColorsManager.blackColor, + fontSize: 12, + ), ), ), ), + const SizedBox( + height: 4, + ), + Visibility( + visible: deviceData['tag'] != null, + child: Row( + spacing: 2, + children: [ + SizedBox( + width: 8, height: 8, child: SvgPicture.asset(Assets.deviceTagIcon)), + Flexible( + child: Text( + deviceData['tag'] ?? '', + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + maxLines: 2, + style: context.textTheme.bodySmall?.copyWith( + color: ColorsManager.lightGreyColor, + fontSize: 9, + fontWeight: FontWeight.w400, + ), + ), + ), + ], + ), + ), + Visibility( + visible: deviceData['subSpace'] != null || deviceData['subSpace'] != '', + child: const SizedBox( + height: 4, + ), + ), + Visibility( + visible: deviceData['subSpace'] != null || deviceData['subSpace'] != '', + child: Row( + spacing: 2, + children: [ + SizedBox( + width: 8, + height: 8, + child: SvgPicture.asset(Assets.spaceLocationIcon)), + Flexible( + child: Text( + deviceData['subSpace'] ?? '', + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + maxLines: 2, + style: context.textTheme.bodySmall?.copyWith( + color: ColorsManager.lightGreyColor, + fontSize: 9, + fontWeight: FontWeight.w400, + ), + ), + ), + ], + ), + ), ], ), + if (deviceFunctions.isNotEmpty) + const SizedBox( + height: 4, + ), if (deviceFunctions.isNotEmpty) ...deviceFunctions.map((function) => Row( mainAxisSize: MainAxisSize.min, @@ -123,7 +188,7 @@ class DraggableCard extends StatelessWidget { '${function.operationName}: ${_formatFunctionValue(function)}', style: context.textTheme.bodySmall?.copyWith( fontSize: 9, - color: ColorsManager.textGray, + color: ColorsManager.lightGreyColor, height: 1.2, ), maxLines: 2, diff --git a/lib/pages/routines/widgets/routine_devices.dart b/lib/pages/routines/widgets/routine_devices.dart index 84fd44c0..f22c8ae3 100644 --- a/lib/pages/routines/widgets/routine_devices.dart +++ b/lib/pages/routines/widgets/routine_devices.dart @@ -51,12 +51,12 @@ class _RoutineDevicesState extends State { 'productType': device.productType, 'functions': device.functions, 'uniqueCustomId': '', + 'tag': device.deviceTags!.isNotEmpty ? device.deviceTags![0].name : '', + 'subSpace': device.deviceSubSpace?.subspaceName ?? '', }; if (state.searchText != null && state.searchText!.isNotEmpty) { - return device.name! - .toLowerCase() - .contains(state.searchText!.toLowerCase()) + return device.name!.toLowerCase().contains(state.searchText!.toLowerCase()) ? DraggableCard( imagePath: deviceData['imagePath'] as String, title: deviceData['title'] as String, diff --git a/lib/pages/routines/widgets/routine_dialogs/one_gang_switch_dialog.dart b/lib/pages/routines/widgets/routine_dialogs/one_gang_switch_dialog.dart index d0fcde28..5bc374a3 100644 --- a/lib/pages/routines/widgets/routine_dialogs/one_gang_switch_dialog.dart +++ b/lib/pages/routines/widgets/routine_dialogs/one_gang_switch_dialog.dart @@ -5,7 +5,6 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart'; import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart'; import 'package:syncrow_web/pages/routines/helper/duration_format_helper.dart'; -import 'package:syncrow_web/pages/routines/models/ac/ac_function.dart'; import 'package:syncrow_web/pages/routines/models/device_functions.dart'; import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart'; import 'package:syncrow_web/pages/routines/models/gang_switches/one_gang_switch/one_gang_switch.dart'; @@ -25,23 +24,21 @@ class OneGangSwitchHelper { required String uniqueCustomId, required bool removeComparetors, }) async { - List oneGangFunctions = - functions.whereType().toList(); + List oneGangFunctions = functions.whereType().toList(); return showDialog?>( context: context, builder: (BuildContext context) { return BlocProvider( - create: (_) => FunctionBloc() - ..add(InitializeFunctions(deviceSelectedFunctions ?? [])), + create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])), child: AlertDialog( contentPadding: EdgeInsets.zero, content: BlocBuilder( builder: (context, state) { final selectedFunction = state.selectedFunction; final selectedOperationName = state.selectedOperationName; - final selectedFunctionData = state.addedFunctions - .firstWhere((f) => f.functionCode == selectedFunction, + final selectedFunctionData = + state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction, orElse: () => DeviceFunctionData( entityId: '', functionCode: selectedFunction ?? '', @@ -88,12 +85,9 @@ class OneGangSwitchHelper { color: ColorsManager.textGray, ), onTap: () { - context - .read() - .add(SelectFunction( + context.read().add(SelectFunction( functionCode: function.code, - operationName: - function.operationName, + operationName: function.operationName, )); }, ); @@ -226,11 +220,11 @@ class OneGangSwitchHelper { selectedFunctionData, ), const SizedBox(height: 20), - _buildCountDownDisplay(context, initialValue, device, operationName, - selectedFunctionData, selectCode), + _buildCountDownDisplay( + context, initialValue, device, operationName, selectedFunctionData, selectCode), const SizedBox(height: 20), - _buildCountDownSlider(context, initialValue, device, operationName, - selectedFunctionData, selectCode), + _buildCountDownSlider( + context, initialValue, device, operationName, selectedFunctionData, selectCode), ], ); } @@ -271,8 +265,7 @@ class OneGangSwitchHelper { minHeight: 40.0, minWidth: 40.0, ), - isSelected: - conditions.map((c) => c == (currentCondition ?? "==")).toList(), + isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(), children: conditions.map((c) => Text(c)).toList(), ); } @@ -320,8 +313,7 @@ class OneGangSwitchHelper { value: (initialValue ?? 0).toDouble(), min: operationalValues.minValue?.toDouble() ?? 0.0, max: operationalValues.maxValue?.toDouble() ?? 0.0, - divisions: (((operationalValues.maxValue ?? 0) - - (operationalValues.minValue ?? 0)) / + divisions: (((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) / (operationalValues.stepValue ?? 1)) .round(), onChanged: (value) { @@ -373,13 +365,9 @@ class OneGangSwitchHelper { style: context.textTheme.bodyMedium, ), trailing: Icon( - isSelected - ? Icons.radio_button_checked - : Icons.radio_button_unchecked, + isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked, size: 24, - color: isSelected - ? ColorsManager.primaryColorWithOpacity - : ColorsManager.textGray, + color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray, ), onTap: () { if (!isSelected) { @@ -391,8 +379,7 @@ class OneGangSwitchHelper { operationName: operationName, value: value.value, condition: selectedFunctionData?.condition, - valueDescription: - selectedFunctionData?.valueDescription, + valueDescription: selectedFunctionData?.valueDescription, ), ), ); diff --git a/lib/utils/constants/assets.dart b/lib/utils/constants/assets.dart index d9788ee8..12d699b4 100644 --- a/lib/utils/constants/assets.dart +++ b/lib/utils/constants/assets.dart @@ -13,12 +13,10 @@ class Assets { static const String rightLine = "assets/images/right_line.png"; static const String google = "assets/images/google.svg"; static const String facebook = "assets/images/facebook.svg"; - static const String invisiblePassword = - "assets/images/Password_invisible.svg"; + static const String invisiblePassword = "assets/images/Password_invisible.svg"; static const String visiblePassword = "assets/images/password_visible.svg"; static const String accessIcon = "assets/images/access_icon.svg"; - static const String spaseManagementIcon = - "assets/images/spase_management_icon.svg"; + static const String spaseManagementIcon = "assets/images/spase_management_icon.svg"; static const String devicesIcon = "assets/images/devices_icon.svg"; static const String moveinIcon = "assets/images/movein_icon.svg"; static const String constructionIcon = "assets/images/construction_icon.svg"; @@ -31,15 +29,13 @@ class Assets { static const String emptyTable = "assets/images/empty_table.svg"; // General assets - static const String motionlessDetection = - "assets/icons/motionless_detection.svg"; + static const String motionlessDetection = "assets/icons/motionless_detection.svg"; static const String acHeating = "assets/icons/ac_heating.svg"; static const String acPowerOff = "assets/icons/ac_power_off.svg"; static const String acFanMiddle = "assets/icons/ac_fan_middle.svg"; static const String switchAlarmSound = "assets/icons/switch_alarm_sound.svg"; static const String resetOff = "assets/icons/reset_off.svg"; - static const String sensitivityOperationIcon = - "assets/icons/sesitivity_operation_icon.svg"; + static const String sensitivityOperationIcon = "assets/icons/sesitivity_operation_icon.svg"; static const String motionDetection = "assets/icons/motion_detection.svg"; static const String freezing = "assets/icons/freezing.svg"; static const String indicator = "assets/icons/indicator.svg"; @@ -60,8 +56,7 @@ class Assets { static const String celsiusDegrees = "assets/icons/celsius_degrees.svg"; static const String masterState = "assets/icons/master_state.svg"; static const String acPower = "assets/icons/ac_power.svg"; - static const String farDetectionFunction = - "assets/icons/far_detection_function.svg"; + static const String farDetectionFunction = "assets/icons/far_detection_function.svg"; static const String nobodyTime = "assets/icons/nobody_time.svg"; // Automation functions @@ -69,47 +64,33 @@ class Assets { "assets/icons/automation_functions/temp_password_unlock.svg"; static const String doorlockNormalOpen = "assets/icons/automation_functions/doorlock_normal_open.svg"; - static const String doorbell = - "assets/icons/automation_functions/doorbell.svg"; + static const String doorbell = "assets/icons/automation_functions/doorbell.svg"; static const String remoteUnlockViaApp = "assets/icons/automation_functions/remote_unlock_via_app.svg"; - static const String doubleLock = - "assets/icons/automation_functions/double_lock.svg"; - static const String selfTestResult = - "assets/icons/automation_functions/self_test_result.svg"; - static const String lockAlarm = - "assets/icons/automation_functions/lock_alarm.svg"; - static const String presenceState = - "assets/icons/automation_functions/presence_state.svg"; - static const String currentTemp = - "assets/icons/automation_functions/current_temp.svg"; - static const String presence = - "assets/icons/automation_functions/presence.svg"; + static const String doubleLock = "assets/icons/automation_functions/double_lock.svg"; + static const String selfTestResult = "assets/icons/automation_functions/self_test_result.svg"; + static const String lockAlarm = "assets/icons/automation_functions/lock_alarm.svg"; + static const String presenceState = "assets/icons/automation_functions/presence_state.svg"; + static const String currentTemp = "assets/icons/automation_functions/current_temp.svg"; + static const String presence = "assets/icons/automation_functions/presence.svg"; static const String residualElectricity = "assets/icons/automation_functions/residual_electricity.svg"; - static const String hijackAlarm = - "assets/icons/automation_functions/hijack_alarm.svg"; - static const String passwordUnlock = - "assets/icons/automation_functions/password_unlock.svg"; + static const String hijackAlarm = "assets/icons/automation_functions/hijack_alarm.svg"; + static const String passwordUnlock = "assets/icons/automation_functions/password_unlock.svg"; static const String remoteUnlockRequest = "assets/icons/automation_functions/remote_unlock_req.svg"; - static const String cardUnlock = - "assets/icons/automation_functions/card_unlock.svg"; + static const String cardUnlock = "assets/icons/automation_functions/card_unlock.svg"; static const String motion = "assets/icons/automation_functions/motion.svg"; static const String fingerprintUnlock = "assets/icons/automation_functions/fingerprint_unlock.svg"; // Presence Sensor Assets static const String sensorMotionIcon = "assets/icons/sensor_motion_ic.svg"; - static const String sensorPresenceIcon = - "assets/icons/sensor_presence_ic.svg"; + static const String sensorPresenceIcon = "assets/icons/sensor_presence_ic.svg"; static const String sensorVacantIcon = "assets/icons/sensor_vacant_ic.svg"; - static const String illuminanceRecordIcon = - "assets/icons/illuminance_record_ic.svg"; - static const String presenceRecordIcon = - "assets/icons/presence_record_ic.svg"; - static const String helpDescriptionIcon = - "assets/icons/help_description_ic.svg"; + static const String illuminanceRecordIcon = "assets/icons/illuminance_record_ic.svg"; + static const String presenceRecordIcon = "assets/icons/presence_record_ic.svg"; + static const String helpDescriptionIcon = "assets/icons/help_description_ic.svg"; static const String lightPulp = "assets/icons/light_pulb.svg"; static const String acDevice = "assets/icons/ac_device.svg"; @@ -159,12 +140,10 @@ class Assets { static const String unit = 'assets/icons/unit_icon.svg'; static const String villa = 'assets/icons/villa_icon.svg'; static const String iconEdit = 'assets/icons/icon_edit_icon.svg'; - static const String textFieldSearch = - 'assets/icons/textfield_search_icon.svg'; + static const String textFieldSearch = 'assets/icons/textfield_search_icon.svg'; static const String roundedAddIcon = 'assets/icons/rounded_add_icon.svg'; static const String addIcon = 'assets/icons/add_icon.svg'; - static const String smartThermostatIcon = - 'assets/icons/smart_thermostat_icon.svg'; + static const String smartThermostatIcon = 'assets/icons/smart_thermostat_icon.svg'; static const String smartLightIcon = 'assets/icons/smart_light_icon.svg'; static const String presenceSensor = 'assets/icons/presence_sensor.svg'; static const String Gang3SwitchIcon = 'assets/icons/3_Gang_switch_icon.svg'; @@ -212,8 +191,7 @@ class Assets { //assets/icons/water_leak_normal.svg static const String waterLeakNormal = 'assets/icons/water_leak_normal.svg'; //assets/icons/water_leak_detected.svg - static const String waterLeakDetected = - 'assets/icons/water_leak_detected.svg'; + static const String waterLeakDetected = 'assets/icons/water_leak_detected.svg'; //assets/icons/automation_records.svg static const String automationRecords = 'assets/icons/automation_records.svg'; @@ -280,64 +258,40 @@ class Assets { static const String delay = 'assets/icons/routine/delay.svg'; // Assets for functions_icons - static const String assetsSensitivityFunction = - "assets/icons/functions_icons/sensitivity.svg"; + static const String assetsSensitivityFunction = "assets/icons/functions_icons/sensitivity.svg"; static const String assetsSensitivityOperationIcon = "assets/icons/functions_icons/sesitivity_operation_icon.svg"; - static const String assetsAcPower = - "assets/icons/functions_icons/ac_power.svg"; - static const String assetsAcPowerOFF = - "assets/icons/functions_icons/ac_power_off.svg"; - static const String assetsChildLock = - "assets/icons/functions_icons/child_lock.svg"; - static const String assetsFreezing = - "assets/icons/functions_icons/freezing.svg"; - static const String assetsFanSpeed = - "assets/icons/functions_icons/fan_speed.svg"; - static const String assetsAcCooling = - "assets/icons/functions_icons/ac_cooling.svg"; - static const String assetsAcHeating = - "assets/icons/functions_icons/ac_heating.svg"; - static const String assetsCelsiusDegrees = - "assets/icons/functions_icons/celsius_degrees.svg"; - static const String assetsTempreture = - "assets/icons/functions_icons/tempreture.svg"; - static const String assetsAcFanLow = - "assets/icons/functions_icons/ac_fan_low.svg"; - static const String assetsAcFanMiddle = - "assets/icons/functions_icons/ac_fan_middle.svg"; - static const String assetsAcFanHigh = - "assets/icons/functions_icons/ac_fan_high.svg"; - static const String assetsAcFanAuto = - "assets/icons/functions_icons/ac_fan_auto.svg"; - static const String assetsSceneChildLock = - "assets/icons/functions_icons/scene_child_lock.svg"; + static const String assetsAcPower = "assets/icons/functions_icons/ac_power.svg"; + static const String assetsAcPowerOFF = "assets/icons/functions_icons/ac_power_off.svg"; + static const String assetsChildLock = "assets/icons/functions_icons/child_lock.svg"; + static const String assetsFreezing = "assets/icons/functions_icons/freezing.svg"; + static const String assetsFanSpeed = "assets/icons/functions_icons/fan_speed.svg"; + static const String assetsAcCooling = "assets/icons/functions_icons/ac_cooling.svg"; + static const String assetsAcHeating = "assets/icons/functions_icons/ac_heating.svg"; + static const String assetsCelsiusDegrees = "assets/icons/functions_icons/celsius_degrees.svg"; + static const String assetsTempreture = "assets/icons/functions_icons/tempreture.svg"; + static const String assetsAcFanLow = "assets/icons/functions_icons/ac_fan_low.svg"; + static const String assetsAcFanMiddle = "assets/icons/functions_icons/ac_fan_middle.svg"; + static const String assetsAcFanHigh = "assets/icons/functions_icons/ac_fan_high.svg"; + static const String assetsAcFanAuto = "assets/icons/functions_icons/ac_fan_auto.svg"; + static const String assetsSceneChildLock = "assets/icons/functions_icons/scene_child_lock.svg"; static const String assetsSceneChildUnlock = "assets/icons/functions_icons/scene_child_unlock.svg"; - static const String assetsSceneRefresh = - "assets/icons/functions_icons/scene_refresh.svg"; - static const String assetsLightCountdown = - "assets/icons/functions_icons/light_countdown.svg"; - static const String assetsFarDetection = - "assets/icons/functions_icons/far_detection.svg"; + static const String assetsSceneRefresh = "assets/icons/functions_icons/scene_refresh.svg"; + static const String assetsLightCountdown = "assets/icons/functions_icons/light_countdown.svg"; + static const String assetsFarDetection = "assets/icons/functions_icons/far_detection.svg"; static const String assetsFarDetectionFunction = "assets/icons/functions_icons/far_detection_function.svg"; - static const String assetsIndicator = - "assets/icons/functions_icons/indicator.svg"; - static const String assetsMotionDetection = - "assets/icons/functions_icons/motion_detection.svg"; + static const String assetsIndicator = "assets/icons/functions_icons/indicator.svg"; + static const String assetsMotionDetection = "assets/icons/functions_icons/motion_detection.svg"; static const String assetsMotionlessDetection = "assets/icons/functions_icons/motionless_detection.svg"; - static const String assetsNobodyTime = - "assets/icons/functions_icons/nobody_time.svg"; - static const String assetsFactoryReset = - "assets/icons/functions_icons/factory_reset.svg"; - static const String assetsMasterState = - "assets/icons/functions_icons/master_state.svg"; + static const String assetsNobodyTime = "assets/icons/functions_icons/nobody_time.svg"; + static const String assetsFactoryReset = "assets/icons/functions_icons/factory_reset.svg"; + static const String assetsMasterState = "assets/icons/functions_icons/master_state.svg"; static const String assetsSwitchAlarmSound = "assets/icons/functions_icons/switch_alarm_sound.svg"; - static const String assetsResetOff = - "assets/icons/functions_icons/reset_off.svg"; + static const String assetsResetOff = "assets/icons/functions_icons/reset_off.svg"; // Assets for automation_functions static const String assetsCardUnlock = @@ -368,8 +322,7 @@ class Assets { "assets/icons/functions_icons/automation_functions/self_test_result.svg"; static const String assetsPresence = "assets/icons/functions_icons/automation_functions/presence.svg"; - static const String assetsMotion = - "assets/icons/functions_icons/automation_functions/motion.svg"; + static const String assetsMotion = "assets/icons/functions_icons/automation_functions/motion.svg"; static const String assetsCurrentTemp = "assets/icons/functions_icons/automation_functions/current_temp.svg"; static const String assetsPresenceState = @@ -381,16 +334,12 @@ class Assets { static const String activeUser = 'assets/icons/active_user.svg'; static const String deActiveUser = 'assets/icons/deactive_user.svg'; static const String invitedIcon = 'assets/icons/invited_icon.svg'; - static const String rectangleCheckBox = - 'assets/icons/rectangle_check_box.png'; + static const String rectangleCheckBox = 'assets/icons/rectangle_check_box.png'; static const String CheckBoxChecked = 'assets/icons/box_checked.png'; static const String emptyBox = 'assets/icons/empty_box.png'; - static const String completeProcessIcon = - 'assets/icons/compleate_process_icon.svg'; - static const String currentProcessIcon = - 'assets/icons/current_process_icon.svg'; - static const String uncomplete_ProcessIcon = - 'assets/icons/uncompleate_process_icon.svg'; + static const String completeProcessIcon = 'assets/icons/compleate_process_icon.svg'; + static const String currentProcessIcon = 'assets/icons/current_process_icon.svg'; + static const String uncomplete_ProcessIcon = 'assets/icons/uncompleate_process_icon.svg'; static const String wrongProcessIcon = 'assets/icons/wrong_process_icon.svg'; static const String arrowForward = 'assets/icons/arrow_forward.svg'; static const String arrowDown = 'assets/icons/arrow_down.svg'; @@ -403,17 +352,14 @@ class Assets { static const String duplicate = 'assets/icons/duplicate.svg'; static const String spaceDelete = 'assets/icons/space_delete.svg'; - static const String deleteSpaceLinkIcon = - 'assets/icons/delete_space_link_icon.svg'; + static const String deleteSpaceLinkIcon = 'assets/icons/delete_space_link_icon.svg'; static const String spaceLinkIcon = 'assets/icons/space_link_icon.svg'; static const String successIcon = 'assets/icons/success_icon.svg'; static const String spaceLocationIcon = 'assets/icons/spaseLocationIcon.svg'; static const String scenesPlayIcon = 'assets/icons/scenesPlayIcon.png'; - static const String scenesPlayIconCheck = - 'assets/icons/scenesPlayIconCheck.png'; + static const String scenesPlayIconCheck = 'assets/icons/scenesPlayIconCheck.png'; static const String presenceStateIcon = 'assets/icons/presence_state.svg'; - static const String currentDistanceIcon = - 'assets/icons/current_distance_icon.svg'; + static const String currentDistanceIcon = 'assets/icons/current_distance_icon.svg'; static const String farDetectionIcon = 'assets/icons/far_detection_icon.svg'; static const String motionDetectionSensitivityIcon = @@ -423,11 +369,11 @@ class Assets { 'assets/icons/motionless_detection_sensitivity_icon.svg'; static const String IndicatorIcon = 'assets/icons/Indicator_icon.svg'; - static const String motionDetectionSensitivityValueIcon = 'assets/icons/motion_detection_sensitivity_value_icon.svg'; - static const String presenceTimeIcon = 'assets/icons/presence_time_icon.svg'; - static const String IlluminanceIcon = 'assets/icons/Illuminance_icon.svg'; - static const String gear = 'assets/icons/gear.svg'; - static const String activeBell='assets/icons/active_bell.svg'; - - + static const String motionDetectionSensitivityValueIcon = + 'assets/icons/motion_detection_sensitivity_value_icon.svg'; + static const String presenceTimeIcon = 'assets/icons/presence_time_icon.svg'; + static const String IlluminanceIcon = 'assets/icons/Illuminance_icon.svg'; + static const String gear = 'assets/icons/gear.svg'; + static const String activeBell = 'assets/icons/active_bell.svg'; + static const String deviceTagIcon = 'assets/icons/device_tag_ic.svg'; } From dba89027e365e65fbfc85c82d2922d66db6734f8 Mon Sep 17 00:00:00 2001 From: Abdullah Alassaf Date: Tue, 15 Apr 2025 11:09:48 +0300 Subject: [PATCH 4/7] Updated the if statement for the tag and the location --- lib/pages/routines/widgets/dragable_card.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pages/routines/widgets/dragable_card.dart b/lib/pages/routines/widgets/dragable_card.dart index 039732b0..7395d2d6 100644 --- a/lib/pages/routines/widgets/dragable_card.dart +++ b/lib/pages/routines/widgets/dragable_card.dart @@ -120,7 +120,7 @@ class DraggableCard extends StatelessWidget { height: 4, ), Visibility( - visible: deviceData['tag'] != null, + visible: deviceData['tag'] != null && deviceData['tag'] != '', child: Row( spacing: 2, children: [ @@ -143,13 +143,13 @@ class DraggableCard extends StatelessWidget { ), ), Visibility( - visible: deviceData['subSpace'] != null || deviceData['subSpace'] != '', + visible: deviceData['subSpace'] != null && deviceData['subSpace'] != '', child: const SizedBox( height: 4, ), ), Visibility( - visible: deviceData['subSpace'] != null || deviceData['subSpace'] != '', + visible: deviceData['subSpace'] != null && deviceData['subSpace'] != '', child: Row( spacing: 2, children: [ From 616adccfdda7fd8611a4a5e1c2eb36d896439644 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Tue, 15 Apr 2025 12:58:20 +0300 Subject: [PATCH 5/7] Applied the correct scenario of tapping add community icon button. --- .../widgets/sidebar_add_community_button.dart | 23 ++----------- .../all_spaces/widgets/sidebar_header.dart | 11 +++++-- .../all_spaces/widgets/sidebar_widget.dart | 32 ++++++++++++++++--- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/lib/pages/spaces_management/all_spaces/widgets/sidebar_add_community_button.dart b/lib/pages/spaces_management/all_spaces/widgets/sidebar_add_community_button.dart index 5c769d48..ae1eb2bf 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/sidebar_add_community_button.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/sidebar_add_community_button.dart @@ -1,19 +1,15 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart'; -import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart'; -import 'package:syncrow_web/pages/spaces_management/create_community/view/create_community_dialog.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; class SidebarAddCommunityButton extends StatelessWidget { const SidebarAddCommunityButton({ - required this.existingCommunityNames, + required this.onTap, super.key, }); - final List existingCommunityNames; + final void Function() onTap; @override Widget build(BuildContext context) { @@ -30,22 +26,9 @@ class SidebarAddCommunityButton extends StatelessWidget { ), ), ), - onPressed: () => _showCreateCommunityDialog(context), + onPressed: onTap, icon: SvgPicture.asset(Assets.addIcon), ), ); } - - void _showCreateCommunityDialog(BuildContext context) => showDialog( - context: context, - builder: (context) => CreateCommunityDialog( - isEditMode: false, - existingCommunityNames: existingCommunityNames, - onCreateCommunity: (name, description) { - context.read().add( - CreateCommunityEvent(name, description, context), - ); - }, - ), - ); } diff --git a/lib/pages/spaces_management/all_spaces/widgets/sidebar_header.dart b/lib/pages/spaces_management/all_spaces/widgets/sidebar_header.dart index 135be109..1706d51a 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/sidebar_header.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/sidebar_header.dart @@ -5,9 +5,12 @@ import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/style.dart'; class SidebarHeader extends StatelessWidget { - const SidebarHeader({required this.existingCommunityNames, super.key}); + const SidebarHeader({ + required this.onAddCommunity, + super.key, + }); - final List existingCommunityNames; + final void Function() onAddCommunity; @override Widget build(BuildContext context) { @@ -23,7 +26,9 @@ class SidebarHeader extends StatelessWidget { color: ColorsManager.blackColor, ), ), - SidebarAddCommunityButton(existingCommunityNames: existingCommunityNames), + SidebarAddCommunityButton( + onTap: onAddCommunity, + ), ], ), ); diff --git a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart index 35bb8ad2..b30a8c96 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart @@ -8,6 +8,7 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/community_tile.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/sidebar_header.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/space_tile_widget.dart'; +import 'package:syncrow_web/pages/spaces_management/create_community/view/create_community_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_event.dart'; import 'package:syncrow_web/utils/style.dart'; @@ -94,10 +95,7 @@ class _SidebarWidgetState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - SidebarHeader( - existingCommunityNames: - widget.communities.map((community) => community.name).toList(), - ), + SidebarHeader(onAddCommunity: _onAddCommunity), CustomSearchBar( onSearchChanged: (query) => setState(() => _searchQuery = query), ), @@ -179,4 +177,30 @@ class _SidebarWidgetState extends State { ), ); } + + void _onAddCommunity() => _selectedId?.isNotEmpty ?? true + ? _clearSelection() + : _showCreateCommunityDialog(); + + void _clearSelection() { + setState(() => _selectedId = ''); + context.read().add( + NewCommunityEvent(communities: widget.communities), + ); + } + + void _showCreateCommunityDialog() { + showDialog( + context: context, + builder: (context) => CreateCommunityDialog( + isEditMode: false, + existingCommunityNames: widget.communities.map((e) => e.name).toList(), + onCreateCommunity: (name, description) { + context.read().add( + CreateCommunityEvent(name, description, context), + ); + }, + ), + ); + } } From 7dcaa20da12ace15f71e1a9693a4bd9dc031f490 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Tue, 15 Apr 2025 13:06:30 +0300 Subject: [PATCH 6/7] Enhanced the code and look of `DialogFooter` buttons. --- lib/pages/routines/widgets/dialog_footer.dart | 62 +++++++++---------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/lib/pages/routines/widgets/dialog_footer.dart b/lib/pages/routines/widgets/dialog_footer.dart index 15db9732..e5a548f7 100644 --- a/lib/pages/routines/widgets/dialog_footer.dart +++ b/lib/pages/routines/widgets/dialog_footer.dart @@ -8,12 +8,12 @@ class DialogFooter extends StatelessWidget { final int? dialogWidth; const DialogFooter({ - Key? key, + super.key, required this.onCancel, required this.onConfirm, required this.isConfirmEnabled, this.dialogWidth, - }) : super(key: key); + }); @override Widget build(BuildContext context) { @@ -28,21 +28,19 @@ class DialogFooter extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - Expanded( - child: _buildFooterButton( - context, - 'Cancel', - onCancel, - ), + _buildFooterButton( + context: context, + text: 'Cancel', + onTap: onCancel, ), if (isConfirmEnabled) ...[ Container(width: 1, height: 50, color: ColorsManager.greyColor), - Expanded( - child: _buildFooterButton( - context, - 'Confirm', - onConfirm, - ), + _buildFooterButton( + context: context, + text: 'Confirm', + onTap: onConfirm, + textColor: + isConfirmEnabled ? ColorsManager.primaryColorWithOpacity : Colors.red, ), ], ], @@ -50,24 +48,24 @@ class DialogFooter extends StatelessWidget { ); } - Widget _buildFooterButton( - BuildContext context, - String text, - VoidCallback? onTap, - ) { - return GestureDetector( - onTap: onTap, - child: SizedBox( - height: 50, - child: Center( - child: Text( - text, - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: text == 'Confirm' - ? ColorsManager.primaryColorWithOpacity - : ColorsManager.textGray, - ), - ), + Widget _buildFooterButton({ + required BuildContext context, + required String text, + required VoidCallback? onTap, + Color? textColor, + }) { + return Expanded( + child: TextButton( + style: TextButton.styleFrom( + foregroundColor: ColorsManager.primaryColorWithOpacity, + disabledForegroundColor: ColorsManager.primaryColor, + ), + onPressed: onTap, + child: Text( + text, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: textColor ?? ColorsManager.textGray, + ), ), ), ); From 1bfab8cc768557c5da701f7d997b837beaf0bc68 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Tue, 15 Apr 2025 14:38:06 +0300 Subject: [PATCH 7/7] SP-1189-Fix tapping ok and nothing happening bug by taking the action out of the widget. --- .../widgets/loaded_space_widget.dart | 7 + .../all_spaces/widgets/sidebar_widget.dart | 8 +- .../views/create_subspace_model_dialog.dart | 231 ++++-------------- .../create_subspace_model_chips_box.dart | 64 +++++ .../create_subspace_model_footer_buttons.dart | 53 ++++ .../widgets/subspace_chip.dart | 58 +++++ .../widgets/subspaces_textfield.dart | 68 ++++++ 7 files changed, 297 insertions(+), 192 deletions(-) create mode 100644 lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_chips_box.dart create mode 100644 lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_footer_buttons.dart create mode 100644 lib/pages/spaces_management/create_subspace_model/widgets/subspace_chip.dart create mode 100644 lib/pages/spaces_management/create_subspace_model/widgets/subspaces_textfield.dart diff --git a/lib/pages/spaces_management/all_spaces/widgets/loaded_space_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/loaded_space_widget.dart index 66b2d6da..5ef9c79b 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/loaded_space_widget.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/loaded_space_widget.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart'; @@ -107,6 +109,11 @@ class _LoadedSpaceViewState extends State { selectedSpaceUuid: widget.selectedSpace?.uuid ?? widget.selectedCommunity?.uuid ?? '', + onCreateCommunity: (name, description) { + context.read().add( + CreateCommunityEvent(name, description, context), + ); + }, ), CommunityStructureArea( selectedCommunity: widget.selectedCommunity, diff --git a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart index b30a8c96..3eb1c001 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart @@ -16,9 +16,11 @@ import 'package:syncrow_web/utils/style.dart'; class SidebarWidget extends StatefulWidget { final List communities; final String? selectedSpaceUuid; + final void Function(String name, String description) onCreateCommunity; const SidebarWidget({ required this.communities, + required this.onCreateCommunity, this.selectedSpaceUuid, super.key, }); @@ -195,11 +197,7 @@ class _SidebarWidgetState extends State { builder: (context) => CreateCommunityDialog( isEditMode: false, existingCommunityNames: widget.communities.map((e) => e.name).toList(), - onCreateCommunity: (name, description) { - context.read().add( - CreateCommunityEvent(name, description, context), - ); - }, + onCreateCommunity: widget.onCreateCommunity, ), ); } diff --git a/lib/pages/spaces_management/create_subspace_model/views/create_subspace_model_dialog.dart b/lib/pages/spaces_management/create_subspace_model/views/create_subspace_model_dialog.dart index 7a39891b..66acdf3d 100644 --- a/lib/pages/spaces_management/create_subspace_model/views/create_subspace_model_dialog.dart +++ b/lib/pages/spaces_management/create_subspace_model/views/create_subspace_model_dialog.dart @@ -1,12 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_web/pages/common/buttons/cancel_button.dart'; -import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_event.dart'; import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_state.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_chips_box.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_footer_buttons.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; class CreateSubSpaceModelDialog extends StatelessWidget { final bool isEdit; @@ -14,211 +15,67 @@ class CreateSubSpaceModelDialog extends StatelessWidget { final List? existingSubSpaces; final void Function(List newSubspaces)? onUpdate; - const CreateSubSpaceModelDialog( - {Key? key, - required this.isEdit, - required this.dialogTitle, - this.existingSubSpaces, - this.onUpdate}) - : super(key: key); + const CreateSubSpaceModelDialog({ + required this.isEdit, + required this.dialogTitle, + this.existingSubSpaces, + this.onUpdate, + super.key, + }); @override Widget build(BuildContext context) { final screenWidth = MediaQuery.of(context).size.width; - final textController = TextEditingController(); return Dialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), child: BlocProvider( - create: (_) { + create: (context) { final bloc = SubSpaceModelBloc(); if (existingSubSpaces != null) { - for (var subSpace in existingSubSpaces!) { + for (final subSpace in existingSubSpaces ?? []) { bloc.add(AddSubSpaceModel(subSpace)); } } return bloc; }, child: BlocBuilder( - builder: (context, state) { - return Container( - color: ColorsManager.whiteColors, - child: SizedBox( - width: screenWidth * 0.3, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - dialogTitle, - style: Theme.of(context) - .textTheme - .headlineLarge - ?.copyWith(color: ColorsManager.blackColor), - ), - const SizedBox(height: 16), - Container( - width: screenWidth * 0.35, - padding: const EdgeInsets.symmetric( - vertical: 10.0, horizontal: 16.0), - decoration: BoxDecoration( - color: ColorsManager.boxColor, - borderRadius: BorderRadius.circular(10), - ), - child: Wrap( - spacing: 8.0, - runSpacing: 8.0, - children: [ - ...state.subSpaces.asMap().entries.map( - (entry) { - final index = entry.key; - final subSpace = entry.value; - - final lowerName = - subSpace.subspaceName.toLowerCase(); - - final duplicateIndices = state.subSpaces - .asMap() - .entries - .where((e) => - e.value.subspaceName.toLowerCase() == - lowerName) - .map((e) => e.key) - .toList(); - final isDuplicate = - duplicateIndices.length > 1 && - duplicateIndices.indexOf(index) != 0; - - return Chip( - label: Text(subSpace.subspaceName, - style: Theme.of(context) - .textTheme - .bodySmall - ?.copyWith( - color: ColorsManager.spaceColor, - )), - backgroundColor: ColorsManager.whiteColors, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - side: BorderSide( - color: isDuplicate - ? ColorsManager.red - : ColorsManager.transparentColor, - width: 0, - ), - ), - deleteIcon: Container( - width: 24, - height: 24, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: ColorsManager.lightGrayColor, - width: 1.5, - ), - ), - child: const Icon( - Icons.close, - size: 16, - color: ColorsManager.lightGrayColor, - ), - ), - onDeleted: () => context - .read() - .add(RemoveSubSpaceModel(subSpace)), - ); - }, - ), - SizedBox( - width: 200, - child: TextField( - controller: textController, - decoration: InputDecoration( - border: InputBorder.none, - hintText: state.subSpaces.isEmpty - ? 'Please enter the name' - : null, - hintStyle: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - color: ColorsManager - .lightGrayColor)), - onSubmitted: (value) { - if (value.trim().isNotEmpty) { - context.read().add( - AddSubSpaceModel( - SubspaceTemplateModel( - subspaceName: value.trim(), - disabled: false))); - textController.clear(); - } - }, - style: Theme.of(context) - .textTheme - .bodyMedium - ?.copyWith( - color: ColorsManager.blackColor)), - ), - ], - ), - ), - if (state.errorMessage.isNotEmpty) - Padding( - padding: const EdgeInsets.only(bottom: 16.0), - child: Text(state.errorMessage, - style: Theme.of(context) - .textTheme - .bodySmall - ?.copyWith( - color: ColorsManager.red, - )), - ), - const SizedBox(height: 16), - Row( - children: [ - Expanded( - child: CancelButton( - label: 'Cancel', - onPressed: () async { - Navigator.of(context).pop(); - }, - ), - ), - const SizedBox(width: 10), - Expanded( - child: DefaultButton( - onPressed: (state.errorMessage.isNotEmpty) - ? null - : () async { - final subSpaces = context - .read() - .state - .subSpaces; - Navigator.of(context).pop(); - if (onUpdate != null) { - onUpdate!(subSpaces); - } - }, - backgroundColor: ColorsManager.secondaryColor, - borderRadius: 10, - foregroundColor: state.errorMessage.isNotEmpty - ? ColorsManager.whiteColorsWithOpacity - : ColorsManager.whiteColors, - child: const Text('OK'), - ), - ), - ], - ), - ], + builder: (context, state) => Container( + color: ColorsManager.whiteColors, + width: screenWidth * 0.3, + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + dialogTitle, + style: context.textTheme.headlineLarge?.copyWith( + color: ColorsManager.blackColor, + ), + ), + const SizedBox(height: 16), + CreateSubspaceModelChipsBox(subSpaces: state.subSpaces), + if (state.errorMessage.isNotEmpty) + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Text( + state.errorMessage, + style: context.textTheme.bodySmall?.copyWith( + color: ColorsManager.red, + ), ), ), - )); - }, + const SizedBox(height: 16), + CreateSubspaceModelFooterButtons( + onUpdate: onUpdate, + errorMessage: state.errorMessage, + ), + ], + ), + ), ), ), ); diff --git a/lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_chips_box.dart b/lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_chips_box.dart new file mode 100644 index 00000000..a18fc8d8 --- /dev/null +++ b/lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_chips_box.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/widgets/subspace_chip.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/widgets/subspaces_textfield.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; + +class CreateSubspaceModelChipsBox extends StatelessWidget { + const CreateSubspaceModelChipsBox({ + required this.subSpaces, + super.key, + }); + + final List subSpaces; + + @override + Widget build(BuildContext context) { + final screenWidth = MediaQuery.of(context).size.width; + + return Container( + width: screenWidth * 0.35, + padding: const EdgeInsets.symmetric( + vertical: 10, + horizontal: 16, + ), + decoration: BoxDecoration( + color: ColorsManager.boxColor, + borderRadius: BorderRadius.circular(10), + ), + child: Wrap( + spacing: 8, + runSpacing: 8, + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + ...subSpaces.asMap().entries.map( + (entry) { + final index = entry.key; + final subSpace = entry.value; + + final lowerName = subSpace.subspaceName.toLowerCase(); + + final duplicateIndices = subSpaces + .asMap() + .entries + .where((e) => e.value.subspaceName.toLowerCase() == lowerName) + .map((e) => e.key) + .toList(); + final isDuplicate = duplicateIndices.length > 1 && + duplicateIndices.indexOf(index) != 0; + + return SubspaceChip( + subSpace: subSpace, + isDuplicate: isDuplicate, + ); + }, + ), + SubspacesTextfield( + hintText: subSpaces.isEmpty ? 'Please enter the name' : null, + ), + ], + ), + ); + } +} diff --git a/lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_footer_buttons.dart b/lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_footer_buttons.dart new file mode 100644 index 00000000..a8dcf89c --- /dev/null +++ b/lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_footer_buttons.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/common/buttons/cancel_button.dart'; +import 'package:syncrow_web/pages/common/buttons/default_button.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; + +class CreateSubspaceModelFooterButtons extends StatelessWidget { + const CreateSubspaceModelFooterButtons({ + required this.onUpdate, + required this.errorMessage, + super.key, + }); + + final void Function(List newSubspaces)? onUpdate; + final String errorMessage; + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Expanded( + child: CancelButton( + label: 'Cancel', + onPressed: () => Navigator.of(context).pop(), + ), + ), + const SizedBox(width: 10), + Expanded( + child: DefaultButton( + onPressed: errorMessage.isEmpty + ? () { + Navigator.of(context).pop(); + if (onUpdate != null) { + final subSpaces = + context.read().state.subSpaces; + onUpdate!(subSpaces); + } + } + : null, + backgroundColor: ColorsManager.secondaryColor, + borderRadius: 10, + foregroundColor: errorMessage.isNotEmpty + ? ColorsManager.whiteColorsWithOpacity + : ColorsManager.whiteColors, + child: const Text('OK'), + ), + ), + ], + ); + } +} diff --git a/lib/pages/spaces_management/create_subspace_model/widgets/subspace_chip.dart b/lib/pages/spaces_management/create_subspace_model/widgets/subspace_chip.dart new file mode 100644 index 00000000..b54e0712 --- /dev/null +++ b/lib/pages/spaces_management/create_subspace_model/widgets/subspace_chip.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_event.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; + +class SubspaceChip extends StatelessWidget { + const SubspaceChip({ + required this.subSpace, + required this.isDuplicate, + super.key, + }); + + final SubspaceTemplateModel subSpace; + final bool isDuplicate; + + @override + Widget build(BuildContext context) { + return Chip( + label: Text( + subSpace.subspaceName, + style: context.textTheme.bodySmall?.copyWith( + color: isDuplicate ? ColorsManager.red : ColorsManager.spaceColor, + ), + ), + backgroundColor: ColorsManager.whiteColors, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + color: isDuplicate ? ColorsManager.red : ColorsManager.transparentColor, + width: 0, + ), + ), + deleteIcon: Container( + padding: const EdgeInsetsDirectional.all(1), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: ColorsManager.lightGrayColor, + width: 1.5, + ), + ), + child: const FittedBox( + fit: BoxFit.scaleDown, + child: Icon( + Icons.close, + color: ColorsManager.lightGrayColor, + ), + ), + ), + onDeleted: () => context.read().add( + RemoveSubSpaceModel(subSpace), + ), + ); + } +} diff --git a/lib/pages/spaces_management/create_subspace_model/widgets/subspaces_textfield.dart b/lib/pages/spaces_management/create_subspace_model/widgets/subspaces_textfield.dart new file mode 100644 index 00000000..d654b960 --- /dev/null +++ b/lib/pages/spaces_management/create_subspace_model/widgets/subspaces_textfield.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_event.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; + +class SubspacesTextfield extends StatefulWidget { + const SubspacesTextfield({ + required this.hintText, + super.key, + }); + + final String? hintText; + + @override + State createState() => _SubspacesTextfieldState(); +} + +class _SubspacesTextfieldState extends State { + late final TextEditingController _controller; + @override + void initState() { + _controller = TextEditingController(); + super.initState(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return SizedBox( + width: 100, + child: TextField( + controller: _controller, + decoration: InputDecoration( + border: InputBorder.none, + hintText: widget.hintText, + hintStyle: context.textTheme.bodySmall?.copyWith( + color: ColorsManager.lightGrayColor, + ), + ), + onSubmitted: (value) { + final trimmedValue = value.trim(); + if (trimmedValue.isNotEmpty) { + context.read().add( + AddSubSpaceModel( + SubspaceTemplateModel( + subspaceName: trimmedValue, + disabled: false, + ), + ), + ); + _controller.clear(); + } + }, + style: context.textTheme.bodyMedium?.copyWith( + color: ColorsManager.blackColor, + ), + ), + ); + } +}