diff --git a/lib/pages/device_managment/device_setting/bloc/setting_bloc_bloc.dart b/lib/pages/device_managment/device_setting/bloc/setting_bloc_bloc.dart index e4d6a835..92d94a8f 100644 --- a/lib/pages/device_managment/device_setting/bloc/setting_bloc_bloc.dart +++ b/lib/pages/device_managment/device_setting/bloc/setting_bloc_bloc.dart @@ -10,26 +10,24 @@ import 'package:syncrow_web/services/space_mana_api.dart'; import 'package:syncrow_web/utils/snack_bar.dart'; part 'setting_bloc_event.dart'; -class SettingBlocBloc extends Bloc { +class SettingDeviceBloc extends Bloc { final String deviceId; - SettingBlocBloc({ + SettingDeviceBloc({ required this.deviceId, - }) : super(const SettingBlocInitial()) { - on(fetchDeviceInfo); - on(saveName); + }) : super(const DeviceSettingsInitial()) { + on(_fetchDeviceInfo); + on(_saveName); on(_changeName); - on(deleteDevice); - on(_fetchRooms); - on(_assignDevice); + on(_deleteDevice); + on(_fetchRooms); + on(_onAssignDevice); } - static String deviceName = ''; - final TextEditingController nameController = - TextEditingController(text: deviceName); + final TextEditingController nameController = TextEditingController(); List roomsList = []; bool isEditingName = false; bool _validateInputs() { - final nameError = fullNameValidator(nameController.text); + final nameError = _fullNameValidator(nameController.text); if (nameError != null) { CustomSnackBar.displaySnackBar(nameError); return true; @@ -37,7 +35,7 @@ class SettingBlocBloc extends Bloc { return false; } - String? fullNameValidator(String? value) { + String? _fullNameValidator(String? value) { if (value == null) return 'name is required'; final withoutExtraSpaces = value.replaceAll(RegExp(r"\s+"), ' ').trim(); if (withoutExtraSpaces.length < 2 || withoutExtraSpaces.length > 30) { @@ -49,69 +47,35 @@ class SettingBlocBloc extends Bloc { return null; } - Future saveName( - SaveNameEvent event, Emitter emit) async { + Future _saveName( + SettingBlocSaveName event, Emitter emit) async { if (_validateInputs()) return; try { - emit(SettingLoadingState()); + emit(DeviceSettingsLoading()); await DevicesManagementApi.putDeviceName( deviceId: deviceId, deviceName: nameController.text); add(DeviceSettingInitialInfo()); CustomSnackBar.displaySnackBar('Save Successfully'); - emit(UpdateSettingState(deviceName: nameController.text)); + emit(DeviceSettingsUpdate(deviceName: nameController.text)); } catch (e) { - emit(ErrorState(message: e.toString())); - } + emit(DeviceSettingsError(message: e.toString())); + } } - DeviceInfoModel deviceInfo = DeviceInfoModel( - activeTime: 0, - category: "", - categoryName: "", - createTime: 0, - gatewayId: "", - icon: "", - ip: "", - lat: "", - localKey: "", - lon: "", - model: "", - name: "", - nodeId: "", - online: false, - ownerId: "", - productName: "", - sub: false, - timeZone: "", - updateTime: 0, - uuid: "", - productUuid: "", - productType: "", - permissionType: "", - macAddress: "", - subspace: Subspace( - uuid: "", - createdAt: "", - updatedAt: "", - subspaceName: "", - ), - ); - - Future fetchDeviceInfo( + Future _fetchDeviceInfo( DeviceSettingInitialInfo event, Emitter emit) async { try { - emit(SettingLoadingState()); + emit(DeviceSettingsLoading()); var response = await DevicesManagementApi.getDeviceInfo(deviceId); - deviceInfo = DeviceInfoModel.fromJson(response); + DeviceInfoModel deviceInfo = DeviceInfoModel.fromJson(response); nameController.text = deviceInfo.name; - - emit(UpdateSettingState( + emit(DeviceSettingsUpdate( deviceName: nameController.text, deviceInfo: deviceInfo, roomsList: roomsList, )); } catch (e) { - emit(ErrorState(message: e.toString())); + emit(DeviceSettingsError(message: e.toString())); } } @@ -119,46 +83,50 @@ class SettingBlocBloc extends Bloc { final FocusNode focusNode = FocusNode(); void _changeName(ChangeNameEvent event, Emitter emit) { - emit(SettingLoadingState()); + emit(DeviceSettingsInitial( + deviceName: nameController.text, + deviceId: deviceId, + isEditingName: event.value ?? false, + editingNameValue: event.value?.toString() ?? '', + deviceInfo: state.deviceInfo, + )); editName = event.value!; if (editName) { Future.delayed(const Duration(milliseconds: 500), () { focusNode.requestFocus(); }); } else { - add(const SaveNameEvent()); + add(const SettingBlocSaveName()); focusNode.unfocus(); } - emit(UpdateSettingState( - deviceName: deviceName, - deviceInfo: deviceInfo, + emit(DeviceSettingsUpdate( + deviceName: nameController.text, + deviceInfo: state.deviceInfo, roomsList: roomsList, )); } - void deleteDevice( - DeleteDeviceEvent event, Emitter emit) async { + void _deleteDevice( + SettingBlocDeleteDevice event, Emitter emit) async { try { - emit(SettingLoadingState()); - await DevicesManagementApi.resetDevise(devicesUuid: deviceId); + emit(DeviceSettingsLoading()); + await DevicesManagementApi.resetDevice(devicesUuid: deviceId); CustomSnackBar.displaySnackBar('Reset Successfully'); - emit(UpdateSettingState( + emit(DeviceSettingsUpdate( deviceName: nameController.text, - deviceInfo: deviceInfo, + deviceInfo: state.deviceInfo, roomsList: roomsList, )); } catch (e) { - emit(ErrorState(message: e.toString())); + emit(DeviceSettingsError(message: e.toString())); return; } } - //=========================== assign device to room ========================== - - void _assignDevice( - AssignRoomEvent event, Emitter emit) async { + void _onAssignDevice( + SettingBlocAssignRoom event, Emitter emit) async { try { - emit(SettingLoadingState()); + emit(DeviceSettingsLoading()); final projectUuid = await ProjectManager.getProjectUUID() ?? ''; await CommunitySpaceManagementApi.assignDeviceToRoom( communityId: event.communityUuid, @@ -168,29 +136,29 @@ class SettingBlocBloc extends Bloc { projectId: projectUuid); add(DeviceSettingInitialInfo()); CustomSnackBar.displaySnackBar('Save Successfully'); - emit(SaveSelectionSuccessState()); + emit(DeviceSettingsSaveSelectionSuccess()); } catch (e) { - emit(ErrorState(message: e.toString())); + emit(DeviceSettingsError(message: e.toString())); return; } } void _fetchRooms( - FetchRoomsEvent event, Emitter emit) async { + SettingBlocFetchRooms event, Emitter emit) async { try { - emit(SettingLoadingState()); + emit(DeviceSettingsLoading()); final projectUuid = await ProjectManager.getProjectUUID() ?? ''; roomsList = await CommunitySpaceManagementApi.getSubSpaceBySpaceId( communityId: event.communityUuid, spaceId: event.spaceUuid, projectId: projectUuid); - emit(UpdateSettingState( + emit(DeviceSettingsUpdate( deviceName: nameController.text, - deviceInfo: deviceInfo, + deviceInfo: state.deviceInfo, roomsList: roomsList, )); } catch (e) { - emit(ErrorState(message: e.toString())); + emit(DeviceSettingsError(message: e.toString())); return; } } diff --git a/lib/pages/device_managment/device_setting/bloc/setting_bloc_event.dart b/lib/pages/device_managment/device_setting/bloc/setting_bloc_event.dart index 66d9e09f..ab62d8a0 100644 --- a/lib/pages/device_managment/device_setting/bloc/setting_bloc_event.dart +++ b/lib/pages/device_managment/device_setting/bloc/setting_bloc_event.dart @@ -6,40 +6,42 @@ abstract class SettingBlocEvent extends Equatable { List get props => []; } -class SaveDeviceName extends SettingBlocEvent { +class SettingBlocSaveDeviceName extends SettingBlocEvent { final String deviceName; final String deviceId; - const SaveDeviceName({required this.deviceName, required this.deviceId}); + const SettingBlocSaveDeviceName( + {required this.deviceName, required this.deviceId}); @override List get props => [deviceName, deviceId]; } -class StartEditingName extends SettingBlocEvent {} +class SettingBlocStartEditingName extends SettingBlocEvent {} -class CancelEditingName extends SettingBlocEvent {} +class SettingBlocCancelEditingName extends SettingBlocEvent {} -class ChangeEditingNameValue extends SettingBlocEvent { +class SettingBlocChangeEditingNameValue extends SettingBlocEvent { final String value; - const ChangeEditingNameValue(this.value); + const SettingBlocChangeEditingNameValue(this.value); @override List get props => [value]; } -class FetchRoomsEvent extends SettingBlocEvent { +class SettingBlocFetchRooms extends SettingBlocEvent { final String communityUuid; final String spaceUuid; - const FetchRoomsEvent({required this.communityUuid, required this.spaceUuid}); + const SettingBlocFetchRooms( + {required this.communityUuid, required this.spaceUuid}); @override List get props => [communityUuid, spaceUuid]; } -class SaveNameEvent extends SettingBlocEvent { - const SaveNameEvent(); +class SettingBlocSaveName extends SettingBlocEvent { + const SettingBlocSaveName(); } class DeviceSettingInitialInfo extends SettingBlocEvent {} @@ -49,14 +51,14 @@ class ChangeNameEvent extends SettingBlocEvent { const ChangeNameEvent({this.value}); } -class DeleteDeviceEvent extends SettingBlocEvent {} +class SettingBlocDeleteDevice extends SettingBlocEvent {} -class AssignRoomEvent extends SettingBlocEvent { +class SettingBlocAssignRoom extends SettingBlocEvent { final String communityUuid; final String spaceUuid; final String subSpaceUuid; - const AssignRoomEvent({ + const SettingBlocAssignRoom({ required this.communityUuid, required this.spaceUuid, required this.subSpaceUuid, @@ -65,3 +67,4 @@ class AssignRoomEvent extends SettingBlocEvent { @override List get props => [spaceUuid, communityUuid, subSpaceUuid]; } + diff --git a/lib/pages/device_managment/device_setting/bloc/setting_bloc_state.dart b/lib/pages/device_managment/device_setting/bloc/setting_bloc_state.dart index eb30b70a..55054c9a 100644 --- a/lib/pages/device_managment/device_setting/bloc/setting_bloc_state.dart +++ b/lib/pages/device_managment/device_setting/bloc/setting_bloc_state.dart @@ -3,32 +3,35 @@ import 'package:syncrow_web/pages/device_managment/device_setting/settings_model import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/sub_space_model.dart'; abstract class DeviceSettingsState extends Equatable { - const DeviceSettingsState(); + const DeviceSettingsState({this.deviceInfo}); + + final DeviceInfoModel? deviceInfo; @override - List get props => []; + List get props => [deviceInfo]; } -class SettingBlocInitial extends DeviceSettingsState { +class DeviceSettingsInitial extends DeviceSettingsState { final String deviceName; final String deviceId; final bool isEditingName; final String editingNameValue; - const SettingBlocInitial({ + const DeviceSettingsInitial({ this.deviceName = '', this.deviceId = '', this.isEditingName = false, this.editingNameValue = '', + super.deviceInfo, }); - SettingBlocInitial copyWith({ + DeviceSettingsInitial copyWith({ String? deviceName, String? deviceId, bool? isEditingName, String? editingNameValue, }) => - SettingBlocInitial( + DeviceSettingsInitial( deviceName: deviceName ?? this.deviceName, deviceId: deviceId ?? this.deviceId, isEditingName: isEditingName ?? this.isEditingName, @@ -40,36 +43,39 @@ class SettingBlocInitial extends DeviceSettingsState { [deviceName, deviceId, isEditingName, editingNameValue]; } -class SettingLoadingState extends DeviceSettingsState {} +class DeviceSettingsLoading extends DeviceSettingsState {} -class UpdateSettingState extends DeviceSettingsState { +class DeviceSettingsUpdate extends DeviceSettingsState { final String? deviceName; - final DeviceInfoModel? deviceInfo; - final List roomsList; + final List roomsList; - const UpdateSettingState({ + const DeviceSettingsUpdate({ this.deviceName, - this.deviceInfo, - this.roomsList = const [], + super.deviceInfo, + this.roomsList = const [], }); + + @override List get props => [deviceName, deviceInfo, roomsList]; } -class ErrorState extends DeviceSettingsState { +class DeviceSettingsError extends DeviceSettingsState { final String message; - const ErrorState({required this.message}); + const DeviceSettingsError({required this.message}); @override List get props => [message]; } -class FetchRoomsState extends DeviceSettingsState { +class DeviceSettingsFetchRooms extends DeviceSettingsState { final List roomsList; - const FetchRoomsState({required this.roomsList}); + const DeviceSettingsFetchRooms({required this.roomsList}); @override List get props => [roomsList]; } -class SaveSelectionSuccessState extends DeviceSettingsState {} +class DeviceSettingsSaveSelectionSuccess extends DeviceSettingsState {} + +class ChangeNameState extends DeviceSettingsState {} diff --git a/lib/pages/device_managment/device_setting/device_management_content.dart b/lib/pages/device_managment/device_setting/device_management_content.dart new file mode 100644 index 00000000..9c758341 --- /dev/null +++ b/lib/pages/device_managment/device_setting/device_management_content.dart @@ -0,0 +1,127 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart'; +import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/device_info_model.dart'; +import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/sub_space_model.dart'; +import 'package:syncrow_web/pages/device_managment/device_setting/sub_space_dialog.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; +import 'package:syncrow_web/web_layout/default_container.dart'; + +class DeviceManagementContent extends StatelessWidget { + const DeviceManagementContent({ + super.key, + required this.device, + required this.subSpaces, + required this.deviceInfo, + }); + + final AllDevicesModel device; + final List subSpaces; + final DeviceInfoModel deviceInfo; + + @override + Widget build(BuildContext context) { + Widget infoRow( + {required String label, + required String value, + Widget? trailing, + required Color? valueColor}) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 6.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + label, + style: context.theme.textTheme.bodyMedium!.copyWith( + fontSize: 14, + color: ColorsManager.grayColor, + ), + ), + Expanded( + child: Text( + value, + textAlign: TextAlign.end, + style: context.theme.textTheme.bodyMedium! + .copyWith(fontSize: 14, color: valueColor), + overflow: TextOverflow.ellipsis, + ), + ), + const SizedBox(width: 8), + trailing ?? const SizedBox.shrink(), + ], + ), + ); + } + + return DefaultContainer( + padding: EdgeInsets.zero, + child: Column( + children: [ + const SizedBox(height: 5), + Padding( + padding: const EdgeInsets.all(10.0), + child: InkWell( + onTap: () { + showSubSpaceDialog( + context, + communityUuid: device.community!.uuid!, + spaceUuid: device.spaces!.first.uuid!, + subSpaces: subSpaces, + selected: device.subspace!.uuid, + ); + }, + child: infoRow( + label: 'Sub-Space:', + value: deviceInfo.subspace.subspaceName, + valueColor: ColorsManager.textGray, + trailing: const Icon( + Icons.arrow_forward_ios, + size: 16, + color: ColorsManager.greyColor, + ), + ), + ), + ), + const Divider(color: ColorsManager.dividerColor), + Padding( + padding: const EdgeInsets.all(10.0), + child: infoRow( + label: 'Virtual Address:', + value: deviceInfo.productUuid, + valueColor: ColorsManager.blackColor, + trailing: InkWell( + onTap: () { + Clipboard.setData( + ClipboardData(text: device.productUuid ?? ''), + ); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Virtual Address copied to clipboard'), + ), + ); + }, + child: const Icon( + Icons.copy, + size: 16, + color: ColorsManager.greyColor, + ), + ), + ), + ), + const Divider(color: ColorsManager.dividerColor), + Padding( + padding: const EdgeInsets.all(10.0), + child: infoRow( + label: 'MAC Address:', + valueColor: ColorsManager.blackColor, + value: deviceInfo.macAddress, + ), + ), + const SizedBox(height: 5), + ], + ), + ); + } +} diff --git a/lib/pages/device_managment/device_setting/device_settings_panel.dart b/lib/pages/device_managment/device_setting/device_settings_panel.dart index 6d960a20..cebd80b3 100644 --- a/lib/pages/device_managment/device_setting/device_settings_panel.dart +++ b/lib/pages/device_managment/device_setting/device_settings_panel.dart @@ -1,13 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart'; import 'package:syncrow_web/pages/device_managment/device_setting/device_icon_type_helper.dart'; +import 'package:syncrow_web/pages/device_managment/device_setting/device_management_content.dart'; +import 'package:syncrow_web/pages/device_managment/device_setting/remove_device_widget.dart'; import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/device_info_model.dart'; import 'package:syncrow_web/pages/device_managment/device_setting/bloc/setting_bloc_bloc.dart'; import 'package:syncrow_web/pages/device_managment/device_setting/bloc/setting_bloc_state.dart'; -import 'package:syncrow_web/pages/device_managment/device_setting/sub_space_dialog.dart'; import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/sub_space_model.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; @@ -18,325 +18,164 @@ class DeviceSettingsPanel extends StatelessWidget { final VoidCallback? onClose; final AllDevicesModel device; const DeviceSettingsPanel({super.key, this.onClose, required this.device}); + @override Widget build(BuildContext context) { final sectionTitle = context.theme.textTheme.titleMedium!.copyWith( fontWeight: FontWeight.bold, color: ColorsManager.grayColor, ); - Widget infoRow( - {required String label, - required String value, - Widget? trailing, - required Color? valueColor}) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 6.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - label, - style: context.theme.textTheme.bodyMedium!.copyWith( - fontSize: 14, - color: ColorsManager.grayColor, - ), - ), - Expanded( - child: Text( - value, - textAlign: TextAlign.end, - style: context.theme.textTheme.bodyMedium! - .copyWith(fontSize: 14, color: valueColor), - overflow: TextOverflow.ellipsis, - ), - ), - const SizedBox(width: 8), - trailing ?? const SizedBox.shrink(), - ], - ), - ); - } - return BlocProvider( - create: (context) => SettingBlocBloc( + create: (context) => SettingDeviceBloc( deviceId: device.uuid ?? '', ) ..add(DeviceSettingInitialInfo()) - ..add(FetchRoomsEvent( + ..add(SettingBlocFetchRooms( communityUuid: device.community!.uuid!, spaceUuid: device.spaces!.first.uuid!, )), - child: BlocBuilder( - builder: (context, state) { - final iconPath = - DeviceIconTypeHelper.getDeviceIconByTypeCode(device.productType); - final _bloc = BlocProvider.of(context); - DeviceInfoModel deviceInfo = DeviceInfoModel.empty(); - List subSpaces = []; - if (state is UpdateSettingState) { - deviceInfo = state.deviceInfo!; - subSpaces = state.roomsList; - } - return Stack( - children: [ - Container( - width: MediaQuery.of(context).size.width * 0.3, - color: ColorsManager.grey25, - padding: - const EdgeInsets.symmetric(horizontal: 20, vertical: 24), - child: ListView( - children: [ - // Header - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + child: Builder( + builder: (context) { + return BlocBuilder( + builder: (context, state) { + final _bloc = context.read(); + final iconPath = DeviceIconTypeHelper.getDeviceIconByTypeCode( + device.productType); + final deviceInfo = state is DeviceSettingsUpdate + ? state.deviceInfo ?? DeviceInfoModel.empty() + : DeviceInfoModel.empty(); + final subSpaces = + state is DeviceSettingsUpdate ? state.roomsList ?? [] : []; + return Stack( + children: [ + Container( + width: MediaQuery.of(context).size.width * 0.3, + color: ColorsManager.grey25, + padding: const EdgeInsets.symmetric( + horizontal: 20, vertical: 24), + child: ListView( children: [ - IconButton( - icon: SvgPicture.asset(Assets.closeSettingsIcon), - onPressed: - onClose ?? () => Navigator.of(context).pop(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + icon: SvgPicture.asset(Assets.closeSettingsIcon), + onPressed: + onClose ?? () => Navigator.of(context).pop(), + ), + ], ), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Device Settings', - style: context.theme.textTheme.titleLarge!.copyWith( - fontWeight: FontWeight.bold, - color: ColorsManager.primaryColor, - ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Device Settings', + style: + context.theme.textTheme.titleLarge!.copyWith( + fontWeight: FontWeight.bold, + color: ColorsManager.primaryColor, + ), + ), + ], ), - ], - ), - const SizedBox(height: 24), - // Device Name + Icon - DefaultContainer( - child: Row( - children: [ - CircleAvatar( - radius: 40, - backgroundColor: - const Color.fromARGB(177, 213, 213, 213), - child: CircleAvatar( - backgroundColor: ColorsManager.whiteColors, - radius: 36, - child: SvgPicture.asset( - iconPath, - fit: BoxFit.cover, - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Device Name:', - style: context.textTheme.bodyMedium!.copyWith( - color: ColorsManager.grayColor, + const SizedBox(height: 24), + DefaultContainer( + child: Row( + children: [ + CircleAvatar( + radius: 40, + backgroundColor: + const Color.fromARGB(177, 213, 213, 213), + child: CircleAvatar( + backgroundColor: ColorsManager.whiteColors, + radius: 36, + child: SvgPicture.asset( + iconPath, + fit: BoxFit.cover, ), ), - TextFormField( - maxLength: 30, - style: const TextStyle( - color: ColorsManager.blackColor, - ), - textAlign: TextAlign.start, - focusNode: _bloc.focusNode, - controller: _bloc.nameController, - enabled: _bloc.editName, - onFieldSubmitted: (value) { - _bloc.add( - const ChangeNameEvent(value: false)); - }, - decoration: const InputDecoration( - border: InputBorder.none, - fillColor: Colors.white10, - counterText: '', - ), - ), - ], - ), - ), - const SizedBox(width: 8), - Visibility( - visible: _bloc.editName != true, - replacement: const SizedBox(), - child: GestureDetector( - onTap: () { - _bloc.add(const ChangeNameEvent(value: true)); - }, - child: SvgPicture.asset( - Assets.editNameIconSettings, - color: ColorsManager.grayColor, - height: 20, - width: 20, - ), - ), - ) - ], - ), - ), - const SizedBox(height: 32), - // Device Management - Text('Device Management', style: sectionTitle), - DefaultContainer( - padding: EdgeInsets.zero, - child: Column( - children: [ - const SizedBox(height: 5), - Padding( - padding: const EdgeInsets.all(10.0), - child: InkWell( - onTap: () { - showSubSpaceDialog( - context, - communityUuid: device.community!.uuid!, - spaceUuid: device.spaces!.first.uuid!, - subSpaces: subSpaces, - selected: device.subspace!.uuid, - ); - }, - child: infoRow( - label: 'Sub-Space:', - value: deviceInfo.subspace.subspaceName, - valueColor: ColorsManager.textGray, - trailing: const Icon( - Icons.arrow_forward_ios, - size: 16, - color: ColorsManager.greyColor, - ), ), - ), - ), - const Divider(color: ColorsManager.dividerColor), - Padding( - padding: const EdgeInsets.all(10.0), - child: infoRow( - label: 'Virtual Address:', - value: deviceInfo.productUuid, - valueColor: ColorsManager.blackColor, - trailing: InkWell( - onTap: () { - Clipboard.setData( - ClipboardData( - text: device.productUuid ?? ''), - ); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Virtual Address copied to clipboard'), - ), - ); - }, - child: const Icon( - Icons.copy, - size: 16, - color: ColorsManager.greyColor, - ), - ), - ), - ), - const Divider(color: ColorsManager.dividerColor), - Padding( - padding: const EdgeInsets.all(10.0), - child: infoRow( - label: 'MAC Address:', - valueColor: ColorsManager.blackColor, - value: deviceInfo.macAddress, - ), - ), - const SizedBox(height: 5), - ], - ), - ), - const SizedBox(height: 32), - - // Remove Device Button - SizedBox( - width: double.infinity, - child: InkWell( - onTap: () { - showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: Text( - 'Remove Device', - style: context.textTheme.bodyMedium!.copyWith( - fontWeight: FontWeight.w700, - color: ColorsManager.red, - ), - ), - content: Text( - 'Are you sure you want to remove this device?', - style: context.textTheme.bodyMedium!.copyWith( - color: ColorsManager.grayColor, - ), - ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: Text( - 'Cancel', + const SizedBox(width: 12), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Device Name:', style: context.textTheme.bodyMedium! .copyWith( color: ColorsManager.grayColor, ), ), - ), - TextButton( - onPressed: () { - _bloc.add(DeleteDeviceEvent()); - Navigator.of(context).pop(); - }, - child: Text( - 'Remove', - style: context.textTheme.bodyMedium! - .copyWith( - color: ColorsManager.red, + TextFormField( + maxLength: 30, + style: const TextStyle( + color: ColorsManager.blackColor, + ), + textAlign: TextAlign.start, + focusNode: _bloc.focusNode, + controller: _bloc.nameController, + enabled: _bloc.editName, + onFieldSubmitted: (value) { + _bloc.add(const ChangeNameEvent( + value: false)); + }, + decoration: const InputDecoration( + border: InputBorder.none, + fillColor: Colors.white10, + counterText: '', ), ), + ], + ), + ), + const SizedBox(width: 8), + Visibility( + visible: _bloc.editName != true, + replacement: const SizedBox(), + child: GestureDetector( + onTap: () { + _bloc.add( + const ChangeNameEvent(value: true)); + }, + child: SvgPicture.asset( + Assets.editNameIconSettings, + color: ColorsManager.grayColor, + height: 20, + width: 20, ), - ], - ); - }, - ); - }, - child: DefaultContainer( - padding: const EdgeInsets.all(25), - child: Center( - child: Text( - 'Remove Device', - style: context.textTheme.bodyMedium!.copyWith( - fontSize: 14, - color: ColorsManager.red, - fontWeight: FontWeight.w700), - ), + ), + ) + ], + ), + ), + const SizedBox(height: 32), + Text('Device Management', style: sectionTitle), + DeviceManagementContent( + device: device, + subSpaces: subSpaces.cast(), + deviceInfo: deviceInfo, + ), + const SizedBox(height: 32), + RemoveDeviceWidget(bloc: _bloc), + ], + ), + ), + if (state is DeviceSettingsLoading) + Positioned.fill( + child: Container( + color: Colors.black.withOpacity(0.1), + child: const Center( + child: CircularProgressIndicator( + color: ColorsManager.primaryColor, ), ), ), ), - ], - ), - ), - if (state is SettingLoadingState) - Positioned.fill( - child: Container( - color: Colors.black.withOpacity(0.1), - child: const Center( - child: CircularProgressIndicator( - color: ColorsManager.primaryColor, - ), - ), - ), - ), - ], + ], + ); + }, ); }, ), diff --git a/lib/pages/device_managment/device_setting/remove_device_widget.dart b/lib/pages/device_managment/device_setting/remove_device_widget.dart new file mode 100644 index 00000000..e65ee125 --- /dev/null +++ b/lib/pages/device_managment/device_setting/remove_device_widget.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'package:syncrow_web/pages/device_managment/device_setting/bloc/setting_bloc_bloc.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; +import 'package:syncrow_web/web_layout/default_container.dart'; + +class RemoveDeviceWidget extends StatelessWidget { + const RemoveDeviceWidget({ + super.key, + required SettingDeviceBloc bloc, + }) : _bloc = bloc; + + final SettingDeviceBloc _bloc; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: InkWell( + onTap: () { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text( + 'Remove Device', + style: context.textTheme.bodyMedium!.copyWith( + fontWeight: FontWeight.w700, + color: ColorsManager.red, + ), + ), + content: Text( + 'Are you sure you want to remove this device?', + style: context.textTheme.bodyMedium!.copyWith( + color: ColorsManager.grayColor, + ), + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text( + 'Cancel', + style: context.textTheme.bodyMedium!.copyWith( + color: ColorsManager.grayColor, + ), + ), + ), + TextButton( + onPressed: () { + _bloc.add(SettingBlocDeleteDevice()); + Navigator.of(context).pop(); + }, + child: Text( + 'Remove', + style: context.textTheme.bodyMedium!.copyWith( + color: ColorsManager.red, + ), + ), + ), + ], + ); + }, + ); + }, + child: DefaultContainer( + padding: const EdgeInsets.all(25), + child: Center( + child: Text( + 'Remove Device', + style: context.textTheme.bodyMedium!.copyWith( + fontSize: 14, + color: ColorsManager.red, + fontWeight: FontWeight.w700), + ), + ), + ), + ), + ); + } +} diff --git a/lib/pages/device_managment/device_setting/sub_space_dialog.dart b/lib/pages/device_managment/device_setting/sub_space_dialog.dart index f2fdfa3e..28350d4d 100644 --- a/lib/pages/device_managment/device_setting/sub_space_dialog.dart +++ b/lib/pages/device_managment/device_setting/sub_space_dialog.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/device_managment/device_setting/bloc/setting_bloc_bloc.dart'; import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/sub_space_model.dart'; +import 'package:syncrow_web/pages/device_managment/device_setting/subspace_dialog_buttons.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart'; @@ -77,71 +78,7 @@ class _SubSpaceDialogState extends State { }).toList(), const SizedBox(height: 12), const Divider(height: 1, thickness: 1), - SizedBox( - height: 50, - child: Row( - children: [ - Expanded( - child: Container( - decoration: const BoxDecoration( - border: Border( - right: BorderSide( - color: ColorsManager.dividerColor, - width: 0.5, - ), - ), - ), - child: TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: Text( - 'Cancel', - style: context.textTheme.bodyMedium?.copyWith( - color: ColorsManager.textGray, - fontSize: 18, - fontWeight: FontWeight.w500, - ), - ), - ), - ), - ), - Expanded( - child: Container( - decoration: const BoxDecoration( - border: Border( - left: BorderSide( - color: ColorsManager.dividerColor, - width: 0.5, - ), - ), - ), - child: TextButton( - onPressed: _selectedId == null - ? null - : () { - final selectedModel = widget.subSpaces - .firstWhere( - (space) => space.id == _selectedId, - orElse: () => SubSpaceModel( - id: null, name: '', devices: [])); - widget.onConfirmed(selectedModel); - Navigator.of(context).pop(); - }, - child: Text( - 'Confirm', - style: context.textTheme.bodyMedium?.copyWith( - color: ColorsManager.secondaryColor, - fontSize: 14, - fontWeight: FontWeight.w400, - ), - ), - ), - ), - ), - ], - ), - ), + SubSpaceDialogButtons(selectedId: _selectedId, widget: widget), ], ), ), @@ -164,8 +101,8 @@ void showSubSpaceDialog( selected: selected, onConfirmed: (selectedModel) { if (selectedModel != null) { - context.read().add( - AssignRoomEvent( + context.read().add( + SettingBlocAssignRoom( communityUuid: communityUuid, spaceUuid: spaceUuid, subSpaceUuid: selectedModel.id ?? '', diff --git a/lib/pages/device_managment/device_setting/subspace_dialog_buttons.dart b/lib/pages/device_managment/device_setting/subspace_dialog_buttons.dart new file mode 100644 index 00000000..80ece0cb --- /dev/null +++ b/lib/pages/device_managment/device_setting/subspace_dialog_buttons.dart @@ -0,0 +1,114 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/device_managment/device_setting/bloc/setting_bloc_bloc.dart'; +import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/sub_space_model.dart'; +import 'package:syncrow_web/pages/device_managment/device_setting/sub_space_dialog.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; + +class SubSpaceDialogButtons extends StatelessWidget { + const SubSpaceDialogButtons({ + super.key, + required String? selectedId, + required this.widget, + }) : _selectedId = selectedId; + + final String? _selectedId; + final SubSpaceDialog widget; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 50, + child: Row( + children: [ + Expanded( + child: Container( + decoration: const BoxDecoration( + border: Border( + right: BorderSide( + color: ColorsManager.dividerColor, + width: 0.5, + ), + ), + ), + child: TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text( + 'Cancel', + style: context.textTheme.bodyMedium?.copyWith( + color: ColorsManager.textGray, + fontSize: 18, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ), + Expanded( + child: Container( + decoration: const BoxDecoration( + border: Border( + left: BorderSide( + color: ColorsManager.dividerColor, + width: 0.5, + ), + ), + ), + child: TextButton( + onPressed: _selectedId == null + ? null + : () { + final selectedModel = widget.subSpaces.firstWhere( + (space) => space.id == _selectedId, + orElse: () => + SubSpaceModel(id: null, name: '', devices: [])); + widget.onConfirmed(selectedModel); + Navigator.of(context).pop(); + }, + child: Text( + 'Confirm', + style: context.textTheme.bodyMedium?.copyWith( + color: ColorsManager.secondaryColor, + fontSize: 14, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + ), + ], + ), + ); + } +} + +void showSubSpaceDialog( + BuildContext context, { + required List subSpaces, + String? selected, + required String communityUuid, + required String spaceUuid, +}) { + showDialog( + context: context, + barrierDismissible: true, + builder: (ctx) => SubSpaceDialog( + subSpaces: subSpaces, + selected: selected, + onConfirmed: (selectedModel) { + if (selectedModel != null) { + context.read().add( + SettingBlocAssignRoom( + communityUuid: communityUuid, + spaceUuid: spaceUuid, + subSpaceUuid: selectedModel.id ?? '', + ), + ); + } + }, + ), + ); +} diff --git a/lib/services/devices_mang_api.dart b/lib/services/devices_mang_api.dart index 4d5200d4..6f60e34f 100644 --- a/lib/services/devices_mang_api.dart +++ b/lib/services/devices_mang_api.dart @@ -370,7 +370,8 @@ class DevicesManagementApi { }); return response; } - static Future resetDevise({ + + static Future resetDevice({ String? devicesUuid, }) async { final response = await HTTPService().post( @@ -385,7 +386,4 @@ class DevicesManagementApi { ); return response; } - - - } diff --git a/lib/services/space_mana_api.dart b/lib/services/space_mana_api.dart index 31f3cebd..8f8d1d07 100644 --- a/lib/services/space_mana_api.dart +++ b/lib/services/space_mana_api.dart @@ -373,7 +373,6 @@ class CommunitySpaceManagementApi { required String spaceId, required String projectId}) async { try { - // Construct the API path final path = ApiEndpoints.listSubspace .replaceFirst('{communityUuid}', communityId) .replaceFirst('{spaceUuid}', spaceId) @@ -389,9 +388,6 @@ class CommunitySpaceManagementApi { for (var subspace in json['data']) { rooms.add(SubSpaceModel.fromJson(subspace)); } - } else { - debugPrint( - "Warning: 'data' key is missing or null in response JSON."); } return rooms; }, @@ -399,7 +395,7 @@ class CommunitySpaceManagementApi { return response; } catch (error, stackTrace) { - return []; // Return an empty list if there's an error + return []; } }