diff --git a/assets/icons/offToggleSwitchSmall.svg b/assets/icons/offToggleSwitchSmall.svg
new file mode 100644
index 0000000..44167b3
--- /dev/null
+++ b/assets/icons/offToggleSwitchSmall.svg
@@ -0,0 +1,18 @@
+
diff --git a/assets/icons/toggleSwitchSmall.svg b/assets/icons/toggleSwitchSmall.svg
new file mode 100644
index 0000000..dc3f4a6
--- /dev/null
+++ b/assets/icons/toggleSwitchSmall.svg
@@ -0,0 +1,18 @@
+
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index d865a3f..1edaab5 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -289,12 +289,12 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS:
- device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
+ device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342
Firebase: 374a441a91ead896215703a674d58cdb3e9d772b
- firebase_analytics: a5c6ef5a435d22870fe3cfdcb424f390f56ff752
- firebase_core: 2337982fb78ee4d8d91e608b0a3d4f44346a93c8
- firebase_crashlytics: 3b6a9a9cbdc5ab92afaf9b206e52c79c2321a0d4
- firebase_database: 8ba35f32ce38e53d81ac61fbe12e0e1b9277fe0f
+ firebase_analytics: 07bd7cfbac54bfcdccf2bb2530f9a65486f7ef3f
+ firebase_core: feb37e79f775c2bd08dd35e02d83678291317e10
+ firebase_crashlytics: 609a5f6f4a2f5af9e40a68182e0c1be3ca2a02f6
+ firebase_database: adc9efd0b70cdc8d1e6f3c9f6bb054a625c4f45d
FirebaseAnalytics: 7114c698cac995602e3b1b96663473e50d54d6e7
FirebaseAppCheckInterop: 347aa09a805219a31249b58fc956888e9fcb314b
FirebaseCore: 48b0dd707581cf9c1a1220da68223fb0a562afaa
@@ -307,23 +307,23 @@ SPEC CHECKSUMS:
FirebaseSessions: 9529d14180868e29a8da164b3a729c036204918b
FirebaseSharedSwift: a4e5dfca3e210633bb3a3dfb94176c019211948b
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
- flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418
+ flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
GoogleAppMeasurement: 6a9e6317b6a6d810ad03d4a66564ca6c4c5818a3
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
- image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
+ image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
leveldb-library: cc8b8f8e013647a295ad3f8cd2ddf49a6f19be19
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
- onesignal_flutter: d86795eb74c65854b23169f131b4fb1ca3146659
+ onesignal_flutter: 5ce68a29861960168e81101cb1bd685d264361de
OneSignalXCFramework: bdf74fdc06888f9466dc21e826fe1549ed143095
- path_provider_foundation: 608fcb11be570ce83519b076ab6a1fffe2474f05
- permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
+ path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
+ permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
- share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
- shared_preferences_foundation: 0b09b969fb36da5551c0bc4a2dbd9d0ff9387478
- sqflite: c35dad70033b8862124f8337cc994a809fcd9fa3
- url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
+ share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
+ shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
+ sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
+ url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
PODFILE CHECKSUM: deba6d843ff3cf709e6e9051ce6601a587b24105
diff --git a/lib/features/app_layout/bloc/home_cubit.dart b/lib/features/app_layout/bloc/home_cubit.dart
index dc951ab..adad8c4 100644
--- a/lib/features/app_layout/bloc/home_cubit.dart
+++ b/lib/features/app_layout/bloc/home_cubit.dart
@@ -7,10 +7,10 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:onesignal_flutter/onesignal_flutter.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:share_plus/share_plus.dart';
+import 'package:syncrow_app/features/app_layout/model/permission_model.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/app_layout/view/widgets/app_bar_home_dropdown.dart';
import 'package:syncrow_app/features/auth/model/user_model.dart';
-import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart';
@@ -30,23 +30,30 @@ import 'package:syncrow_app/services/api/profile_api.dart';
import 'package:syncrow_app/services/api/spaces_api.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
-
part 'home_state.dart';
class HomeCubit extends Cubit {
HomeCubit._() : super(HomeInitial()) {
// checkIfNotificationPermissionGranted();
- fetchUserInfo();
- if (selectedSpace == null) {
- fetchUnitsByUserId();
- // .then((value) {
- // if (selectedSpace != null) {
- // fetchRoomsByUnitId(selectedSpace!);
- // }
- // });
- }
+ fetchUserInfo().then(
+ (value) {
+ if (selectedSpace == null) {
+ fetchUnitsByUserId();
+ fetchPermissions();
+
+ // .then((value) {
+ // if (selectedSpace != null) {
+ // fetchRoomsByUnitId(selectedSpace!);
+ // }
+ // });
+ }
+ },
+ );
}
static UserModel? user;
+
+ List? permissionModel = [];
+
static HomeCubit? _instance;
static HomeCubit getInstance() {
// If an instance already exists, return it
@@ -56,15 +63,88 @@ class HomeCubit extends Cubit {
Future fetchUserInfo() async {
try {
+ emit(HomeLoading());
var uuid =
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
user = await ProfileApi().fetchUserInfo(uuid);
- emit(HomeUserInfoLoaded(user!)); // Emit state after fetching user info
+ emit(HomeUserInfoLoaded(user!));
} catch (e) {
return;
}
}
+ static bool manageSupSpace = false;
+ static bool manageScene = false;
+ static bool manageDeviceLocation = false;
+ static bool visitorPasswordManagement = false;
+ String errorMsg = '';
+
+ Future fetchPermissions() async {
+ try {
+ emit(HomeLoading());
+ final response = await ProfileApi().fetchPermissions(user!.role!.uuid);
+ permissionModel = PermissionModel.fromJsonList(response);
+ hasViewPermission();
+ emit(PermissionsRoleLoaded(permissionModel!));
+ } catch (e) {
+ emit(HomeError(e.toString()));
+ }
+ }
+
+ void hasViewPermission() {
+ emit(HomeLoading());
+
+ manageSupSpace = hasPermission(
+ permissionModel!,
+ 'SPACE_MANAGEMENT',
+ 'MANAGE_SPACE',
+ 'ASSIGN_USER_TO_SPACE',
+ );
+ manageScene = hasPermission(
+ permissionModel!,
+ 'AUTOMATION_MANAGEMENT',
+ 'MANAGE_SCENES',
+ 'UPDATE',
+ );
+ manageDeviceLocation = hasPermission(
+ permissionModel!,
+ 'DEVICE_MANAGEMENT',
+ 'MANAGE_DEVICE',
+ 'LOCATION_UPDATE',
+ );
+ visitorPasswordManagement = hasPermission(
+ permissionModel!,
+ 'VISITOR_PASSWORD_MANAGEMENT',
+ 'MANAGE_VISITOR_PASSWORD',
+ 'VIEW',
+ );
+ emit(HomePermissionUpdated());
+ }
+
+ bool hasPermission(List permissions, String mainTitle,
+ String subTitle, String finalTitle) {
+ try {
+ final mainOption = permissions.firstWhere(
+ (perm) => perm.title == mainTitle,
+ );
+
+ final subOption = mainOption.subOptions.firstWhere(
+ (sub) => sub.title == subTitle,
+ );
+
+ if (subOption.subOptions == null) {
+ return false;
+ }
+
+ final finalOption = subOption.subOptions!.firstWhere(
+ (finalSub) => finalSub.title == finalTitle,
+ );
+ return finalOption.isChecked == true;
+ } catch (e) {
+ return false;
+ }
+ }
+
void emitSafe(HomeState newState) {
final cubit = this;
if (!cubit.isClosed) {
@@ -89,7 +169,7 @@ class HomeCubit extends Cubit {
static HomeCubit get(context) => BlocProvider.of(context);
- List? spaces;
+ List spaces = [];
SpaceModel? selectedSpace;
@@ -182,8 +262,10 @@ class HomeCubit extends Cubit {
if (index == 0) {
unselectRoom();
+ } else if (index == 1) {
+ unselectRoom1();
} else {
- selectedRoom = selectedSpace!.subspaces[index - 1];
+ selectedRoom = selectedSpace!.subspaces[index - 2];
emitSafe(RoomSelected(selectedRoom!));
}
}
@@ -197,8 +279,10 @@ class HomeCubit extends Cubit {
if (index <= 0) {
unselectRoom();
+ } else if (index == 1) {
+ unselectRoom1();
} else {
- selectedRoom = selectedSpace!.subspaces[index - 1];
+ selectedRoom = selectedSpace!.subspaces[index - 2];
emitSafe(RoomSelected(selectedRoom!));
}
}
@@ -220,6 +304,23 @@ class HomeCubit extends Cubit {
emitSafe(RoomUnSelected());
}
+ unselectRoom1() {
+ // selectedRoom = null;
+ devicesPageController.animateToPage(
+ 1,
+ duration: duration,
+ curve: Curves.linear,
+ );
+
+ roomsPageController.animateToPage(
+ 1,
+ duration: duration,
+ curve: Curves.linear,
+ );
+
+ emitSafe(RoomUnSelected());
+ }
+
//////////////////////////////////////// API ////////////////////////////////////////
generateInvitation(SpaceModel unit) async {
try {
@@ -261,15 +362,16 @@ class HomeCubit extends Cubit {
emitSafe(GetSpacesLoading());
try {
spaces = await SpacesAPI.getSpacesByUserId();
+ emitSafe(GetSpacesSuccess(spaces));
} catch (failure) {
emitSafe(GetSpacesError("No units found"));
return;
}
- if (spaces != null && spaces!.isNotEmpty) {
- selectedSpace = spaces!.first;
+ if (spaces.isNotEmpty) {
+ selectedSpace = spaces.first;
await fetchRoomsByUnitId(selectedSpace!);
- emitSafe(GetSpacesSuccess(spaces!));
+ emitSafe(GetSpacesSuccess(spaces));
} else {
emitSafe(GetSpacesError("No spaces found"));
}
@@ -298,20 +400,21 @@ class HomeCubit extends Cubit {
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
var res = await SpacesAPI.activationCodeSpace(
activationCode: activationCode, userUuid: uuid);
+
if (res['success'] == true) {
fetchUserInfo();
fetchUnitsByUserId();
}
emitSafe(GetSpacesSuccess(spaces!));
+
return res['success'];
} on DioException catch (e) {
final errorMessage = e.response?.data['error']['message'];
- emitSafe(ActivationError(errMessage: errorMessage));
- return false;
- } catch (e) {
- emitSafe(ActivationError(errMessage: e.toString()));
+ errorMsg = e.response?.data['error']['message'];
+ emitSafe(ActivationError(errMessage: errorMsg));
return false;
}
+
}
/////////////////////////////////////// Nav ///////////////////////////////////////
@@ -378,42 +481,44 @@ class HomeCubit extends Cubit {
// ),
// onPressed: () {},
// ),
- IconButton(
- icon: const Icon(
- Icons.add,
- size: 32,
- ),
- style: ButtonStyle(
- foregroundColor:
- WidgetStateProperty.all(ColorsManager.textPrimaryColor),
- ),
- onPressed: () {
- Navigator.pushNamed(
- NavigationService.navigatorKey.currentContext!,
- Routes.sceneTasksRoute,
- arguments: SceneSettingsRouteArguments(
- sceneType: '',
- sceneId: '',
- sceneName: '',
- ),
- );
- NavigationService.navigatorKey.currentContext!
- .read()
- .add(const ClearTaskListEvent());
- NavigationService.navigatorKey.currentContext!
- .read()
- .add(const SceneTypeEvent(CreateSceneEnum.none));
- NavigationService.navigatorKey.currentContext!
- .read()
- .add(const SmartSceneClearEvent());
- BlocProvider.of(
- NavigationService.navigatorKey.currentState!.context)
- .add(ResetEffectivePeriod());
- NavigationService.navigatorKey.currentContext!
- .read()
- .add(const ClearTabToRunSetting());
- },
- ),
+ manageScene
+ ? IconButton(
+ icon: const Icon(
+ Icons.add,
+ size: 32,
+ ),
+ style: ButtonStyle(
+ foregroundColor:
+ WidgetStateProperty.all(ColorsManager.textPrimaryColor),
+ ),
+ onPressed: () {
+ Navigator.pushNamed(
+ NavigationService.navigatorKey.currentContext!,
+ Routes.sceneTasksRoute,
+ arguments: SceneSettingsRouteArguments(
+ sceneType: '',
+ sceneId: '',
+ sceneName: '',
+ ),
+ );
+ NavigationService.navigatorKey.currentContext!
+ .read()
+ .add(const ClearTaskListEvent());
+ NavigationService.navigatorKey.currentContext!
+ .read()
+ .add(const SceneTypeEvent(CreateSceneEnum.none));
+ NavigationService.navigatorKey.currentContext!
+ .read()
+ .add(const SmartSceneClearEvent());
+ BlocProvider.of(
+ NavigationService.navigatorKey.currentState!.context)
+ .add(ResetEffectivePeriod());
+ NavigationService.navigatorKey.currentContext!
+ .read()
+ .add(const ClearTabToRunSetting());
+ },
+ )
+ : const SizedBox(),
// IconButton(
// icon: const Icon(
// Icons.more_vert,
@@ -503,3 +608,28 @@ BottomNavigationBarItem defaultBottomNavBarItem(
label: label,
);
}
+
+
+// class PermissionUtils {
+// // Check if the "VIEW" permission exists in "MANAGE_SUBSPACE"
+// static bool hasViewPermission(List permissions) {
+// return _hasPermission(permissions, 'MANAGE_SUBSPACE', 'VIEW');
+// }
+
+// // Generalized permission checker
+// static bool _hasPermission(
+// List permissions, String mainTitle, String subTitle) {
+// final mainOption = permissions.firstWhere(
+// (perm) => perm['title'] == mainTitle,
+// orElse: () => null,
+// );
+// if (mainOption != null) {
+// final subOption = mainOption['subOptions'].firstWhere(
+// (sub) => sub['title'] == subTitle,
+// orElse: () => null,
+// );
+// return subOption != null && subOption['isChecked'] == true;
+// }
+// return false;
+// }
+// }
diff --git a/lib/features/app_layout/bloc/home_state.dart b/lib/features/app_layout/bloc/home_state.dart
index 6498b0d..d9814e1 100644
--- a/lib/features/app_layout/bloc/home_state.dart
+++ b/lib/features/app_layout/bloc/home_state.dart
@@ -15,8 +15,8 @@ class HomeError extends HomeState {
class HomeSuccess extends HomeState {}
-///specific states
-//get spaces
+class ActivationSuccess extends HomeState {}
+
class GetSpacesLoading extends HomeLoading {}
class GetSpacesSuccess extends HomeSuccess {
@@ -65,9 +65,15 @@ class RoomUnSelected extends HomeState {}
class NavChangePage extends HomeState {}
-// Define new state classes
+class HomePermissionUpdated extends HomeState {}
+
class HomeUserInfoLoaded extends HomeState {
final UserModel user;
HomeUserInfoLoaded(this.user);
}
+
+class PermissionsRoleLoaded extends HomeState {
+ final List permissionModel;
+ PermissionsRoleLoaded(this.permissionModel);
+}
diff --git a/lib/features/app_layout/model/permission_model.dart b/lib/features/app_layout/model/permission_model.dart
new file mode 100644
index 0000000..3965d27
--- /dev/null
+++ b/lib/features/app_layout/model/permission_model.dart
@@ -0,0 +1,39 @@
+class PermissionModel {
+ final String title;
+ final List subOptions;
+
+ PermissionModel({required this.title, required this.subOptions});
+
+ factory PermissionModel.fromJson(Map json) {
+ return PermissionModel(
+ title: json['title'],
+ subOptions: (json['subOptions'] as List)
+ .map((e) => PermissionAttributes.fromJson(e))
+ .toList(),
+ );
+ }
+
+ static List fromJsonList(List jsonList) {
+ return jsonList.map((json) => PermissionModel.fromJson(json)).toList();
+ }
+}
+
+class PermissionAttributes {
+ final String title;
+ final List? subOptions;
+ final bool? isChecked;
+
+ PermissionAttributes({required this.title, this.subOptions, this.isChecked});
+
+ factory PermissionAttributes.fromJson(Map json) {
+ return PermissionAttributes(
+ title: json['title'],
+ isChecked: json['isChecked'],
+ subOptions: json['subOptions'] != null
+ ? (json['subOptions'] as List)
+ .map((e) => PermissionAttributes.fromJson(e))
+ .toList()
+ : null,
+ );
+ }
+}
diff --git a/lib/features/app_layout/view/app_layout.dart b/lib/features/app_layout/view/app_layout.dart
index 214cce2..5dfe583 100644
--- a/lib/features/app_layout/view/app_layout.dart
+++ b/lib/features/app_layout/view/app_layout.dart
@@ -17,7 +17,10 @@ class AppLayout extends StatelessWidget {
child: BlocBuilder(
builder: (context, state) {
return DefaultScaffold(
- appBar: HomeCubit.getInstance().spaces != null ? const DefaultAppBar() : null,
+ appBar: HomeCubit.getInstance().spaces != null &&
+ HomeCubit.getInstance().spaces!.isNotEmpty
+ ? const DefaultAppBar()
+ : null,
bottomNavBar: const DefaultNavBar(),
child: const AppBody(),
);
diff --git a/lib/features/app_layout/view/widgets/default_app_bar.dart b/lib/features/app_layout/view/widgets/default_app_bar.dart
index 2d29b96..2284543 100644
--- a/lib/features/app_layout/view/widgets/default_app_bar.dart
+++ b/lib/features/app_layout/view/widgets/default_app_bar.dart
@@ -35,8 +35,10 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
)
: null,
),
- actions: HomeCubit.appBarActions[
- HomeCubit.bottomNavItems[HomeCubit.pageIndex].label],
+ actions: HomeCubit.manageScene
+ ? HomeCubit.appBarActions[
+ HomeCubit.bottomNavItems[HomeCubit.pageIndex].label]
+ : null,
));
},
);
diff --git a/lib/features/auth/bloc/auth_cubit.dart b/lib/features/auth/bloc/auth_cubit.dart
index f4418b0..2d37c7d 100644
--- a/lib/features/auth/bloc/auth_cubit.dart
+++ b/lib/features/auth/bloc/auth_cubit.dart
@@ -221,6 +221,7 @@ class AuthCubit extends Cubit {
List userFullName = fullName.split(' ');
response = await AuthenticationAPI.signUp(
model: SignUpModel(
+ hasAcceptedAppAgreement: true,
email: email.toLowerCase(),
password: signUpPassword,
firstName: userFullName[0],
diff --git a/lib/features/auth/model/signup_model.dart b/lib/features/auth/model/signup_model.dart
index c4a0adf..c9b4fa1 100644
--- a/lib/features/auth/model/signup_model.dart
+++ b/lib/features/auth/model/signup_model.dart
@@ -3,10 +3,12 @@ class SignUpModel {
final String password;
final String firstName;
final String lastName;
+ final bool hasAcceptedAppAgreement;
SignUpModel(
{required this.email,
required this.password,
+ required this.hasAcceptedAppAgreement,
required this.firstName,
required this.lastName});
@@ -15,7 +17,8 @@ class SignUpModel {
email: json['email'],
password: json['password'],
firstName: json['firstName'],
- lastName: json['lastName']);
+ lastName: json['lastName'],
+ hasAcceptedAppAgreement: true);
}
Map toJson() {
@@ -24,6 +27,7 @@ class SignUpModel {
'password': password,
'firstName': firstName,
'lastName': lastName,
+ "hasAcceptedAppAgreement": hasAcceptedAppAgreement
};
}
}
diff --git a/lib/features/auth/model/user_model.dart b/lib/features/auth/model/user_model.dart
index 5e055a7..143b114 100644
--- a/lib/features/auth/model/user_model.dart
+++ b/lib/features/auth/model/user_model.dart
@@ -15,6 +15,11 @@ class UserModel {
final String? timeZone;
final String? regionUuid;
final bool? isAgreementAccepted;
+ final bool? hasAcceptedWebAgreement;
+ final DateTime? webAgreementAcceptedAt;
+ final bool? hasAcceptedAppAgreement;
+ final DateTime? appAgreementAcceptedAt;
+ final Role? role;
UserModel({
required this.uuid,
@@ -28,7 +33,11 @@ class UserModel {
required this.isAgreementAccepted,
required this.regionName,
required this.timeZone,
- // required this.role,
+ required this.hasAcceptedWebAgreement,
+ required this.webAgreementAcceptedAt,
+ required this.hasAcceptedAppAgreement,
+ required this.appAgreementAcceptedAt,
+ required this.role,
});
factory UserModel.fromJson(Map json) {
@@ -44,6 +53,15 @@ class UserModel {
regionName: json['region']?['regionName'],
timeZone: json['timeZone']?['timeZoneOffset'],
regionUuid: json['region']?['uuid'],
+ hasAcceptedWebAgreement: json['hasAcceptedWebAgreement'],
+ webAgreementAcceptedAt: json['webAgreementAcceptedAt'] != null
+ ? DateTime.parse(json['webAgreementAcceptedAt'])
+ : null,
+ hasAcceptedAppAgreement: json['hasAcceptedAppAgreement'],
+ appAgreementAcceptedAt: json['appAgreementAcceptedAt'] != null
+ ? DateTime.parse(json['appAgreementAcceptedAt'])
+ : null,
+ role: json['role'] != null ? Role.fromJson(json['role']) : null,
);
}
@@ -61,6 +79,15 @@ class UserModel {
regionUuid: null,
regionName: tempJson['region']?['regionName'],
timeZone: tempJson['timezone']?['timeZoneOffset'],
+ hasAcceptedWebAgreement: tempJson['hasAcceptedWebAgreement'],
+ webAgreementAcceptedAt: tempJson['webAgreementAcceptedAt'] != null
+ ? DateTime.parse(tempJson['webAgreementAcceptedAt'])
+ : null,
+ hasAcceptedAppAgreement: tempJson['hasAcceptedAppAgreement'],
+ appAgreementAcceptedAt: tempJson['appAgreementAcceptedAt'] != null
+ ? DateTime.parse(tempJson['appAgreementAcceptedAt'])
+ : null,
+ role: tempJson['role'] != null ? Role.fromJson(tempJson['role']) : null,
);
}
@@ -85,6 +112,43 @@ class UserModel {
'isAgreementAccepted': isAgreementAccepted,
'regionName': regionName,
'timeZone': timeZone,
+ 'hasAcceptedWebAgreement': hasAcceptedWebAgreement,
+ 'webAgreementAcceptedAt': webAgreementAcceptedAt?.toIso8601String(),
+ 'hasAcceptedAppAgreement': hasAcceptedAppAgreement,
+ 'appAgreementAcceptedAt': appAgreementAcceptedAt?.toIso8601String(),
+ 'role': role?.toJson(),
+ };
+ }
+}
+
+class Role {
+ final String? uuid;
+ final DateTime? createdAt;
+ final DateTime? updatedAt;
+ final String? type;
+
+ Role({
+ required this.uuid,
+ required this.createdAt,
+ required this.updatedAt,
+ required this.type,
+ });
+
+ factory Role.fromJson(Map json) {
+ return Role(
+ uuid: json['uuid'],
+ createdAt: json['createdAt'] != null ? DateTime.parse(json['createdAt']) : null,
+ updatedAt: json['updatedAt'] != null ? DateTime.parse(json['updatedAt']) : null,
+ type: json['type'],
+ );
+ }
+
+ Map toJson() {
+ return {
+ 'uuid': uuid,
+ 'createdAt': createdAt?.toIso8601String(),
+ 'updatedAt': updatedAt?.toIso8601String(),
+ 'type': type,
};
}
}
diff --git a/lib/features/devices/bloc/acs_bloc/acs_bloc.dart b/lib/features/devices/bloc/acs_bloc/acs_bloc.dart
index 4fd7fe0..b0b43af 100644
--- a/lib/features/devices/bloc/acs_bloc/acs_bloc.dart
+++ b/lib/features/devices/bloc/acs_bloc/acs_bloc.dart
@@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_event.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_state.dart';
+import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/ac_model.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
@@ -135,6 +136,8 @@ class ACsBloc extends Bloc {
ac.acSwitch = acSwitchValue;
}
}
+
+
_setAllAcsTempsAndSwitches();
_emitAcsStatus(emit);
} else {
diff --git a/lib/features/devices/bloc/ceiling_bloc/ceiling_sensor_bloc.dart b/lib/features/devices/bloc/ceiling_bloc/ceiling_sensor_bloc.dart
index ca1fadf..d8a463c 100644
--- a/lib/features/devices/bloc/ceiling_bloc/ceiling_sensor_bloc.dart
+++ b/lib/features/devices/bloc/ceiling_bloc/ceiling_sensor_bloc.dart
@@ -1,3 +1,5 @@
+import 'dart:convert';
+
import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -112,7 +114,7 @@ class CeilingSensorBloc extends Bloc {
code: 'presence_state',
);
recordGroups = response;
- // print('---${recordGroups.data!.first.eventTime}');
+ // print('---${jsonEncode(recordGroups.data.first.)}');
emit(FitchData());
} on DioException catch (e) {
final errorData = e.response!.data;
diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart
index 9fe8020..6006e1a 100644
--- a/lib/features/devices/bloc/devices_cubit.dart
+++ b/lib/features/devices/bloc/devices_cubit.dart
@@ -31,6 +31,7 @@ class DevicesCubit extends Cubit {
// Fetch groups based on the selected space ID
await fetchGroups(selectedSpace.id);
+ await fetchAllDevices(selectedSpace);
}
DevicesCubit._() : super(DevicesInitial()) {
@@ -47,6 +48,7 @@ class DevicesCubit extends Cubit {
return _instance ??= DevicesCubit._();
}
+
@override
Future close() {
_instance = null;
@@ -109,17 +111,6 @@ class DevicesCubit extends Cubit {
}
// Getter to retrieve all devices from HomeCubit
- List get allDevices {
- List devices = [];
- if (HomeCubit.getInstance().selectedSpace != null) {
- for (var room in HomeCubit.getInstance().selectedSpace!.subspaces) {
- if (room.devices != null) {
- devices.addAll(room.devices!);
- }
- }
- }
- return devices;
- }
// DevicesCategoryModel? get chosenCategory {
// for (var category in allCategories!) {
@@ -267,36 +258,36 @@ class DevicesCubit extends Cubit {
}
///////////////////////// API CALLS //////////////////////////
- deviceControl(DeviceControlModel control, String deviceId) async {
- emitSafe(DeviceControlLoading(
- code: control.code,
- ));
- try {
- var response = await DevicesAPI.controlDevice(control, deviceId);
+ // deviceControl(DeviceControlModel control, String deviceId) async {
+ // emitSafe(DeviceControlLoading(
+ // code: control.code,
+ // ));
+ // try {
+ // var response = await DevicesAPI.controlDevice(control, deviceId);
- if (response['success'] ?? false) {
- emitSafe(DeviceControlSuccess(code: control.code));
- //this delay is to give tuya server time to update the status
- // Future.delayed(const Duration(milliseconds: 400), () {
- fetchDevicesStatues(
- deviceId,
- HomeCubit.getInstance()
- .selectedSpace!
- .subspaces
- .indexOf(HomeCubit.getInstance().selectedRoom!),
- code: control.code);
- // });
- } else {
- emitSafe(DeviceControlError('Failed to control the device'));
- }
- } catch (failure) {
- emitSafe(DeviceControlError(failure.toString()));
- return;
- }
- }
+ // if (response['success'] ?? false) {
+ // emitSafe(DeviceControlSuccess(code: control.code));
+ // //this delay is to give tuya server time to update the status
+ // // Future.delayed(const Duration(milliseconds: 400), () {
+ // fetchDevicesStatues(
+ // deviceId,
+ // HomeCubit.getInstance()
+ // .selectedSpace!
+ // .subspaces
+ // .indexOf(HomeCubit.getInstance().selectedRoom!),
+ // code: control.code);
+ // // });
+ // } else {
+ // emitSafe(DeviceControlError('Failed to control the device'));
+ // }
+ // } catch (failure) {
+ // emitSafe(DeviceControlError(failure.toString()));
+ // return;
+ // }
+ // }
fetchGroups(String spaceId) async {
- emitSafe(DevicesCategoriesLoading());
+ emitSafe(GetDevicesLoading());
try {
allCategories = await DevicesAPI.fetchGroups(spaceId);
} catch (e) {
@@ -321,12 +312,15 @@ class DevicesCubit extends Cubit {
try {
HomeCubit.getInstance().selectedSpace!.subspaces[roomIndex].devices =
await DevicesAPI.getDevicesByRoomId(
- communityUuid: unit!.community.uuid, spaceUuid: unit.id, roomId: roomId);
+ communityUuid: unit!.community.uuid,
+ spaceUuid: unit.id,
+ roomId: roomId);
} catch (e) {
emitSafe(GetDevicesError(e.toString()));
return;
}
- final devices = HomeCubit.getInstance().selectedSpace!.subspaces[roomIndex].devices;
+ final devices =
+ HomeCubit.getInstance().selectedSpace!.subspaces[roomIndex].devices;
emitSafe(GetDevicesSuccess(devices));
//get status for each device
@@ -356,8 +350,11 @@ class DevicesCubit extends Cubit {
emitSafe(GetDeviceStatusError(e.toString()));
return;
}
- HomeCubit.getInstance().selectedSpace!.subspaces[roomIndex].devices![deviceIndex].status =
- statuses;
+ HomeCubit.getInstance()
+ .selectedSpace!
+ .subspaces[roomIndex]
+ .devices![deviceIndex]
+ .status = statuses;
emitSafe(GetDeviceStatusSuccess(code: code));
}
@@ -406,6 +403,345 @@ class DevicesCubit extends Cubit {
// emitSafe(LightBrightnessChanged(value));
// }
// }
+ // List _fetchedDevices = [];
+
+ // List get allDevices => _fetchedDevices;
+ List allDevices = [];
+
+ Future fetchAllDevices(SpaceModel? unit) async {
+ emitSafe(GetDevicesLoading());
+ try {
+ final devices = await DevicesAPI.getAllDevices(
+ communityUuid: unit!.community.uuid,
+ spaceUuid: unit.id,
+ );
+ allDevices = devices;
+ emitSafe(GetDevicesSuccess(allDevices));
+ } catch (e) {
+ emitSafe(GetDevicesError(e.toString()));
+ }
+ }
+
+ bool isDeviceOn(DeviceModel device) {
+ final switchStatuses = device.status.where(
+ (s) => (s.code?.startsWith('switch') ?? false),
+ );
+ final anySwitchFalse = switchStatuses.any((s) => s.value == false);
+ return !anySwitchFalse;
+ }
+
+ void updateDeviceStatus(String deviceId, bool newToggleStatus) {
+ emitSafe(GetDevicesLoading());
+
+ // Create a fresh copy of the device list.
+ final updatedDevices = List.from(allDevices);
+
+ for (int i = 0; i < updatedDevices.length; i++) {
+ final device = updatedDevices[i];
+ if (device.uuid == deviceId) {
+ updatedDevices[i] = DeviceModel(
+ activeTime: device.activeTime,
+ localKey: device.localKey,
+ model: device.model,
+ name: device.name,
+ icon: device.icon,
+ categoryName: device.categoryName,
+ type: device.type,
+ isOnline: device.isOnline,
+ status: device.status, // Make sure to keep the same status list
+ productName: device.productName,
+ timeZone: device.timeZone,
+ updateTime: device.updateTime,
+ uuid: device.uuid,
+ productUuid: device.productUuid,
+ productType: device.productType,
+ subspace: device.subspace,
+ toggleStatus: newToggleStatus,
+ );
+ break;
+ }
+ }
+ emit(GetDevicesSuccess(updatedDevices));
+ }
+
+ Future threeGangToggle(
+ DeviceControlModel control, String deviceUuid) async {
+ emit(SwitchControlLoading(code: control.code));
+ try {
+ final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
+ if (deviceIndex == -1) {
+ throw Exception('Device not found');
+ }
+ final device = allDevices[deviceIndex];
+ final switches = ['switch_1', 'switch_2', 'switch_3'];
+ for (final switchCode in switches) {
+ final statusIndex =
+ device.status.indexWhere((s) => s.code == switchCode);
+ if (statusIndex != -1) {
+ final currentValue = device.status[statusIndex].value ?? false;
+ final toggledValue = !currentValue;
+ final controlRequest = DeviceControlModel(
+ code: switchCode, value: toggledValue, deviceId: deviceUuid);
+ final response =
+ await DevicesAPI.controlDevice(controlRequest, deviceUuid);
+ if (response['success'] != true) {
+ throw Exception('Failed to toggle $switchCode');
+ }
+ device.status[statusIndex].value = toggledValue;
+ }
+ }
+ final anySwitchOff = device.status.any(
+ (s) => (s.code?.startsWith('switch_') ?? false) && (s.value == false),
+ );
+ device.toggleStatus = !anySwitchOff;
+ allDevices[deviceIndex] = device;
+ emit(DeviceControlSuccess(code: control.code));
+ } catch (failure) {
+ emit(DeviceControlError(failure.toString()));
+ }
+ }
+
+ Future towGangToggle(
+ DeviceControlModel control, String deviceUuid) async {
+ emit(SwitchControlLoading(code: control.code));
+ try {
+ final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
+ if (deviceIndex == -1) {
+ throw Exception('Device not found');
+ }
+ final device = allDevices[deviceIndex];
+ final switches = [
+ 'switch_1',
+ 'switch_2',
+ ];
+ for (final switchCode in switches) {
+ final statusIndex =
+ device.status.indexWhere((s) => s.code == switchCode);
+ if (statusIndex != -1) {
+ final currentValue = device.status[statusIndex].value ?? false;
+ final toggledValue = !currentValue;
+ final controlRequest = DeviceControlModel(
+ code: switchCode, value: toggledValue, deviceId: deviceUuid);
+ final response =
+ await DevicesAPI.controlDevice(controlRequest, deviceUuid);
+
+ device.status[statusIndex].value = response['result'];
+ }
+ }
+ final anySwitchOff = device.status.any(
+ (s) => (s.code?.startsWith('switch_') ?? false) && (s.value == false),
+ );
+ device.toggleStatus = !anySwitchOff;
+ allDevices[deviceIndex] = device;
+ emit(DeviceControlSuccess(code: control.code));
+ } catch (failure) {
+ emit(DeviceControlError(failure.toString()));
+ }
+ }
+
+ Future towGTGangToggle(
+ DeviceControlModel control, String deviceUuid) async {
+ emit(SwitchControlLoading(code: control.code));
+ try {
+ final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
+ if (deviceIndex == -1) {
+ throw Exception('Device not found');
+ }
+ final device = allDevices[deviceIndex];
+ final switches = [
+ 'switch_1',
+ 'switch_2',
+ ];
+ for (final switchCode in switches) {
+ final statusIndex =
+ device.status.indexWhere((s) => s.code == switchCode);
+ if (statusIndex != -1) {
+ final currentValue = device.status[statusIndex].value ?? false;
+ final toggledValue = !currentValue;
+ final controlRequest = DeviceControlModel(
+ code: switchCode, value: toggledValue, deviceId: deviceUuid);
+ final response =
+ await DevicesAPI.controlDevice(controlRequest, deviceUuid);
+
+ device.status[statusIndex].value = response['result'];
+ }
+ }
+ final anySwitchOff = device.status.any(
+ (s) => (s.code?.startsWith('switch_') ?? false) && (s.value == false),
+ );
+ device.toggleStatus = !anySwitchOff;
+ allDevices[deviceIndex] = device;
+ emit(DeviceControlSuccess(code: control.code));
+ } catch (failure) {
+ emit(DeviceControlError(failure.toString()));
+ }
+ }
+
+ Future oneGangToggle(
+ DeviceControlModel control, String deviceUuid) async {
+ emit(SwitchControlLoading(code: control.code));
+ try {
+ final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
+ if (deviceIndex == -1) {
+ throw Exception('Device not found');
+ }
+ final device = allDevices[deviceIndex];
+
+ final statusIndex = device.status.indexWhere((s) => s.code == 'switch_1');
+ if (statusIndex != -1) {
+ final currentValue = device.status[statusIndex].value ?? false;
+ final toggledValue = !currentValue;
+ final controlRequest = DeviceControlModel(
+ code: 'switch_1', value: toggledValue, deviceId: deviceUuid);
+ final response =
+ await DevicesAPI.controlDevice(controlRequest, deviceUuid);
+ print(response);
+ if (response['result'] != true) {
+ throw Exception('Failed to toggle switch_1');
+ }
+ device.status[statusIndex].value = response['result'];
+ }
+
+ final anySwitchOff = device.status.any(
+ (s) => (s.code?.startsWith('switch_') ?? false) && (s.value == false),
+ );
+ device.toggleStatus = !anySwitchOff;
+ allDevices[deviceIndex] = device;
+ emit(DeviceControlSuccess(code: control.code));
+ } catch (failure) {
+ emit(DeviceControlError(failure.toString()));
+ }
+ }
+
+ Future oneGTGangToggle(
+ DeviceControlModel control, String deviceUuid) async {
+ emit(SwitchControlLoading(code: control.code));
+ try {
+ final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
+ if (deviceIndex == -1) {
+ throw Exception('Device not found');
+ }
+ final device = allDevices[deviceIndex];
+
+ final statusIndex = device.status.indexWhere((s) => s.code == 'switch_1');
+ if (statusIndex != -1) {
+ final currentValue = device.status[statusIndex].value ?? false;
+ final toggledValue = !currentValue;
+ final controlRequest = DeviceControlModel(
+ code: 'switch_1', value: toggledValue, deviceId: deviceUuid);
+ final response =
+ await DevicesAPI.controlDevice(controlRequest, deviceUuid);
+ if (response['result'] != true) {
+ throw Exception('Failed to toggle switch_1');
+ }
+ device.status[statusIndex].value = response['result'];
+ }
+
+ final anySwitchOff = device.status.any(
+ (s) => (s.code?.startsWith('switch_') ?? false) && (s.value == false),
+ );
+ device.toggleStatus = !anySwitchOff;
+ allDevices[deviceIndex] = device;
+ emit(DeviceControlSuccess(code: control.code));
+ } catch (failure) {
+ emit(DeviceControlError(failure.toString()));
+ }
+ }
+
+ Future deviceControl(
+ DeviceControlModel control, String deviceUuid) async {
+ emit(SwitchControlLoading(code: control.code));
+ try {
+ final response = await DevicesAPI.controlDevice(control, deviceUuid);
+ if (response['success'] == true) {
+ final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
+ if (deviceIndex != -1) {
+ final device = allDevices[deviceIndex];
+ final statusIndex =
+ device.status.indexWhere((s) => s.code == control.code);
+ if (statusIndex != -1) {
+ device.status[statusIndex].value = control.value;
+ }
+ final anySwitchOff = device.status.any(
+ (s) =>
+ (s.code?.startsWith('switch_') ?? false) && (s.value == false),
+ );
+ device.toggleStatus = !anySwitchOff;
+ allDevices[deviceIndex] = device;
+ }
+ emit(DeviceControlSuccess(code: control.code));
+ } else {
+ emit(DeviceControlError('Failed to control the device'));
+ }
+ } catch (failure) {
+ emit(DeviceControlError(failure.toString()));
+ }
+ }
+
+ Future changeCurtainSwitch(
+ DeviceControlModel control, String deviceUuid) async {
+ emit(SwitchControlLoading(code: control.code));
+ try {
+ final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
+ if (deviceIndex == -1) {
+ throw Exception('Device not found');
+ }
+ final device = allDevices[deviceIndex];
+ final isOpen = control.value == "open";
+ final newValue = isOpen ? 0 : 100;
+ final response = await DevicesAPI.deviceBatchController(
+ code: 'percent_control',
+ devicesUuid: [deviceUuid],
+ value: newValue,
+ );
+ if (response['success'] == true) {
+ final statusIndex =
+ device.status.indexWhere((s) => s.code == 'percent_control');
+ if (statusIndex != -1) {
+ device.status[statusIndex].value = newValue;
+ }
+ allDevices[deviceIndex] = device;
+
+ emit(DeviceControlSuccess(code: control.code));
+ } else {
+ emit(DeviceControlError('Failed to toggle curtain.'));
+ }
+ } catch (error) {
+ emit(DeviceControlError(error.toString()));
+ }
+ }
+
+ Future changeGarageSwitch(
+ DeviceControlModel control, String deviceUuid) async {
+ emit(SwitchControlLoading(code: control.code));
+ try {
+ final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
+ if (deviceIndex == -1) {
+ throw Exception('Device not found');
+ }
+ final device = allDevices[deviceIndex];
+ final isOpen = control.value == "open";
+ final newValue = isOpen ? 0 : 100;
+ final response = await DevicesAPI.deviceBatchController(
+ code: 'percent_control',
+ devicesUuid: [deviceUuid],
+ value: newValue,
+ );
+ if (response['success'] == true) {
+ final statusIndex =
+ device.status.indexWhere((s) => s.code == 'percent_control');
+ if (statusIndex != -1) {
+ device.status[statusIndex].value = newValue;
+ }
+ allDevices[deviceIndex] = device;
+ emit(DeviceControlSuccess(code: control.code));
+ } else {
+ emit(DeviceControlError('Failed to toggle curtain.'));
+ }
+ } catch (error) {
+ emit(DeviceControlError(error.toString()));
+ }
+ }
}
enum LightMode {
diff --git a/lib/features/devices/bloc/devices_state.dart b/lib/features/devices/bloc/devices_state.dart
index cb23e24..5e54720 100644
--- a/lib/features/devices/bloc/devices_state.dart
+++ b/lib/features/devices/bloc/devices_state.dart
@@ -34,6 +34,7 @@ class GetDeviceStatusError extends DevicesState {
}
class GetDevicesLoading extends DevicesState {}
+class RoomLoading extends DevicesState {}
class GetDevicesSuccess extends DevicesState {
GetDevicesSuccess(this.devices);
@@ -55,10 +56,16 @@ class DeviceSwitchChanged extends DevicesState {}
class DeviceSelected extends DevicesState {}
// Device Control
-class DeviceControlLoading extends DevicesState {
- final String? code;
+// class DeviceControlLoading extends DevicesState {
+// final String? code;
- DeviceControlLoading({this.code});
+// DeviceControlLoading({this.code});
+// }
+class SwitchControlLoading extends DevicesState {
+ final String? code;
+ final String? deviceId;
+
+ SwitchControlLoading({this.deviceId, this.code});
}
class DeviceControlSuccess extends DevicesState {
diff --git a/lib/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart b/lib/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart
index 7f66724..56031c8 100644
--- a/lib/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart
+++ b/lib/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart
@@ -40,7 +40,8 @@ class TwoTouchBloc extends Bloc {
bool createSchedule = false;
List listSchedule = [];
- TwoTouchBloc({required this.twoTouchId, required this.switchCode}) : super(InitialState()) {
+ TwoTouchBloc({required this.twoTouchId, required this.switchCode})
+ : super(InitialState()) {
on(_fetchTwoTouchStatus);
on(_twoTouchUpdated);
on(_changeFirstSwitch);
@@ -71,13 +72,15 @@ class TwoTouchBloc extends Bloc {
int selectedTabIndex = 0;
- void toggleSelectedIndex(ToggleSelectedEvent event, Emitter emit) {
+ void toggleSelectedIndex(
+ ToggleSelectedEvent event, Emitter emit) {
emit(LoadingInitialState());
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
- void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter emit) {
+ void toggleCreateSchedule(
+ ToggleCreateScheduleEvent event, Emitter emit) {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
@@ -85,7 +88,8 @@ class TwoTouchBloc extends Bloc {
emit(UpdateCreateScheduleState(createSchedule));
}
- void _fetchTwoTouchStatus(InitialEvent event, Emitter emit) async {
+ void _fetchTwoTouchStatus(
+ InitialEvent event, Emitter emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(twoTouchId);
@@ -104,18 +108,21 @@ class TwoTouchBloc extends Bloc {
_listenToChanges() {
try {
- DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$twoTouchId');
+ DatabaseReference ref =
+ FirebaseDatabase.instance.ref('device-status/$twoTouchId');
Stream stream = ref.onValue;
stream.listen((DatabaseEvent event) async {
if (_timer != null) {
await Future.delayed(const Duration(seconds: 2));
}
- Map usersMap = event.snapshot.value as Map;
+ Map usersMap =
+ event.snapshot.value as Map;
List statusList = [];
usersMap['status'].forEach((element) {
- statusList.add(StatusModel(code: element['code'], value: element['value']));
+ statusList
+ .add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus = TwoTouchModel.fromJson(statusList);
@@ -130,7 +137,8 @@ class TwoTouchBloc extends Bloc {
emit(UpdateState(twoTouchModel: deviceStatus));
}
- void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter emit) async {
+ void _changeFirstSwitch(
+ ChangeFirstSwitchStatusEvent event, Emitter emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
deviceStatus.firstSwitch = !event.value;
@@ -141,7 +149,8 @@ class TwoTouchBloc extends Bloc {
_timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice(
- DeviceControlModel(deviceId: twoTouchId, code: 'switch_1', value: !event.value),
+ DeviceControlModel(
+ deviceId: twoTouchId, code: 'switch_1', value: !event.value),
twoTouchId);
if (!response['success']) {
@@ -153,7 +162,8 @@ class TwoTouchBloc extends Bloc {
}
}
- void _changeSecondSwitch(ChangeSecondSwitchStatusEvent event, Emitter emit) async {
+ void _changeSecondSwitch(
+ ChangeSecondSwitchStatusEvent event, Emitter emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
deviceStatus.secondSwitch = !event.value;
@@ -163,7 +173,8 @@ class TwoTouchBloc extends Bloc {
}
_timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice(
- DeviceControlModel(deviceId: twoTouchId, code: 'switch_2', value: !event.value),
+ DeviceControlModel(
+ deviceId: twoTouchId, code: 'switch_2', value: !event.value),
twoTouchId);
if (!response['success']) {
@@ -186,11 +197,15 @@ class TwoTouchBloc extends Bloc {
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
- deviceId: twoTouchId, code: 'switch_1', value: deviceStatus.firstSwitch),
+ deviceId: twoTouchId,
+ code: 'switch_1',
+ value: deviceStatus.firstSwitch),
twoTouchId),
DevicesAPI.controlDevice(
DeviceControlModel(
- deviceId: twoTouchId, code: 'switch_2', value: deviceStatus.secondSwitch),
+ deviceId: twoTouchId,
+ code: 'switch_2',
+ value: deviceStatus.secondSwitch),
twoTouchId),
]);
@@ -213,11 +228,15 @@ class TwoTouchBloc extends Bloc {
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
- deviceId: twoTouchId, code: 'switch_1', value: deviceStatus.firstSwitch),
+ deviceId: twoTouchId,
+ code: 'switch_1',
+ value: deviceStatus.firstSwitch),
twoTouchId),
DevicesAPI.controlDevice(
DeviceControlModel(
- deviceId: twoTouchId, code: 'switch_2', value: deviceStatus.secondSwitch),
+ deviceId: twoTouchId,
+ code: 'switch_2',
+ value: deviceStatus.secondSwitch),
twoTouchId),
]);
if (response.every((element) => !element['success'])) {
@@ -237,8 +256,10 @@ class TwoTouchBloc extends Bloc {
groupTwoTouchList[i].firstSwitch = true;
groupTwoTouchList[i].secondSwitch = true;
}
- emit(UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: true));
- List allDeviceIds = groupTwoTouchList.map((device) => device.deviceId).toList();
+ emit(
+ UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: true));
+ List allDeviceIds =
+ groupTwoTouchList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1',
@@ -271,9 +292,11 @@ class TwoTouchBloc extends Bloc {
groupTwoTouchList[i].secondSwitch = false;
}
- emit(UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: false));
+ emit(UpdateGroupState(
+ twoTouchList: groupTwoTouchList, allSwitches: false));
- List allDeviceIds = groupTwoTouchList.map((device) => device.deviceId).toList();
+ List allDeviceIds =
+ groupTwoTouchList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1',
@@ -298,17 +321,20 @@ class TwoTouchBloc extends Bloc {
}
}
- void _changeSliding(ChangeSlidingSegment event, Emitter emit) async {
+ void _changeSliding(
+ ChangeSlidingSegment event, Emitter emit) async {
emit(ChangeSlidingSegmentState(value: event.value));
}
- void _setCounterValue(SetCounterValue event, Emitter emit) async {
+ void _setCounterValue(
+ SetCounterValue event, Emitter emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
int seconds = 0;
try {
seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice(
- DeviceControlModel(deviceId: twoTouchId, code: event.deviceCode, value: seconds),
+ DeviceControlModel(
+ deviceId: twoTouchId, code: event.deviceCode, value: seconds),
twoTouchId);
if (response['success'] ?? false) {
@@ -333,7 +359,8 @@ class TwoTouchBloc extends Bloc {
}
}
- void _getCounterValue(GetCounterEvent event, Emitter emit) async {
+ void _getCounterValue(
+ GetCounterEvent event, Emitter emit) async {
emit(LoadingInitialState());
try {
add(GetScheduleEvent());
@@ -441,7 +468,8 @@ class TwoTouchBloc extends Bloc {
deviceId: twoTouchId,
);
List jsonData = response;
- listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
+ listSchedule =
+ jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState());
} on DioException catch (e) {
final errorData = e.response!.data;
@@ -452,12 +480,13 @@ class TwoTouchBloc extends Bloc {
int? getTimeStampWithoutSeconds(DateTime? dateTime) {
if (dateTime == null) return null;
- DateTime dateTimeWithoutSeconds =
- DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute);
+ DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
+ dateTime.day, dateTime.hour, dateTime.minute);
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
}
- Future toggleRepeat(ToggleScheduleEvent event, Emitter emit) async {
+ Future toggleRepeat(
+ ToggleScheduleEvent event, Emitter emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule(
@@ -476,7 +505,8 @@ class TwoTouchBloc extends Bloc {
}
}
- Future deleteSchedule(DeleteScheduleEvent event, Emitter emit) async {
+ Future deleteSchedule(
+ DeleteScheduleEvent event, Emitter emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule(
@@ -496,7 +526,8 @@ class TwoTouchBloc extends Bloc {
}
}
- void _fetchTwoTouchWizardStatus(InitialWizardEvent event, Emitter emit) async {
+ void _fetchTwoTouchWizardStatus(
+ InitialWizardEvent event, Emitter emit) async {
emit(LoadingInitialState());
try {
devicesList = [];
@@ -506,7 +537,8 @@ class TwoTouchBloc extends Bloc {
HomeCubit.getInstance().selectedSpace?.id ?? '', '2GT');
for (int i = 0; i < devicesList.length; i++) {
- var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
+ var response =
+ await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
@@ -529,15 +561,16 @@ class TwoTouchBloc extends Bloc {
return true;
});
}
- emit(UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: allSwitchesOn));
+ emit(UpdateGroupState(
+ twoTouchList: groupTwoTouchList, allSwitches: allSwitchesOn));
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
- void _changeFirstWizardSwitch(
- ChangeFirstWizardSwitchStatusEvent event, Emitter emit) async {
+ void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
+ Emitter emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
bool allSwitchesValue = true;
@@ -550,7 +583,8 @@ class TwoTouchBloc extends Bloc {
}
});
- emit(UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: allSwitchesValue));
+ emit(UpdateGroupState(
+ twoTouchList: groupTwoTouchList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: [event.deviceId],
@@ -565,8 +599,8 @@ class TwoTouchBloc extends Bloc {
}
}
- void _changeSecondWizardSwitch(
- ChangeSecondWizardSwitchStatusEvent event, Emitter emit) async {
+ void _changeSecondWizardSwitch(ChangeSecondWizardSwitchStatusEvent event,
+ Emitter emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
bool allSwitchesValue = true;
@@ -579,7 +613,8 @@ class TwoTouchBloc extends Bloc {
}
});
- emit(UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: allSwitchesValue));
+ emit(UpdateGroupState(
+ twoTouchList: groupTwoTouchList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController(
code: 'switch_2',
@@ -598,7 +633,8 @@ class TwoTouchBloc extends Bloc {
String statusSelected = '';
String optionSelected = '';
- Future _changeStatus(ChangeStatusEvent event, Emitter emit) async {
+ Future _changeStatus(
+ ChangeStatusEvent event, Emitter emit) async {
try {
emit(LoadingInitialState());
final Map> controlMap = {
@@ -627,11 +663,15 @@ class TwoTouchBloc extends Bloc {
final selectedControl = controlMap[optionSelected]?[statusSelected];
if (selectedControl != null) {
await DevicesAPI.controlDevice(
- DeviceControlModel(deviceId: twoTouchId, code: optionSelected, value: selectedControl),
+ DeviceControlModel(
+ deviceId: twoTouchId,
+ code: optionSelected,
+ value: selectedControl),
twoTouchId,
);
} else {
- emit(const FailedState(error: 'Invalid statusSelected or optionSelected'));
+ emit(const FailedState(
+ error: 'Invalid statusSelected or optionSelected'));
}
} on DioException catch (e) {
final errorData = e.response!.data;
diff --git a/lib/features/devices/model/device_model.dart b/lib/features/devices/model/device_model.dart
index 557e83f..9824468 100644
--- a/lib/features/devices/model/device_model.dart
+++ b/lib/features/devices/model/device_model.dart
@@ -10,6 +10,9 @@ class DeviceModel {
String? model;
String? name;
String? icon;
+ String? categoryName;
+ bool? toggleStatus = false;
+
String? type;
bool? isOnline;
List status = [];
@@ -21,6 +24,8 @@ class DeviceModel {
DeviceType? productType;
bool isSelected = false;
late List functions;
+ DeviceSubspace? subspace;
+
DeviceModel(
{this.activeTime,
this.productUuid,
@@ -34,6 +39,9 @@ class DeviceModel {
this.updateTime,
this.uuid,
this.productType,
+ this.categoryName,
+ this.subspace,
+ this.toggleStatus,
this.icon,
this.type}) {
functions = getFunctions(productType!);
@@ -87,23 +95,74 @@ class DeviceModel {
} else {
tempIcon = Assets.assetsIconsLogo;
}
+ // Step 1: Parse `status` as before
+ final statusList = (json['status'] as List?)
+ ?.map((st) => StatusModel.fromJson(st as Map))
+ .toList();
+
+// Step 2: Check whether ANY status means "off"
+ final anyOff = statusList?.any((s) {
+ final code = s.code;
+ if (code == null) return false;
+
+ // 1) Handle "switch" or "switch_x"
+ if (code == 'switch' || code.startsWith('switch_')) {
+ // If it's false, we consider that "off"
+ return s.value == false;
+ }
+
+ // 2) If code == "control" and value == "stop", consider "off"
+ if (s.value == 'open') {
+ return true;
+ }
+
+ // 3) If code == "percent_control" and value == 0, maybe "off"
+ if (code == 'percent_control' && s.value == 0) {
+ return true;
+ }
+
+ // Add more conditions for other codes as needed
+
+ // Default: if none of the above apply, it's not "off"
+ return false;
+ });
+
+// Step 3: Decide final toggleStatus (true = fully "on", false = partially/fully "off")
+ bool computedToggleStatus = !(anyOff ?? false);
return DeviceModel(
- icon: tempIcon,
- activeTime: json['activeTime'],
- // id: json['id'],
- localKey: json['localKey'],
- model: json['model'],
- name: json['name'],
- isOnline: json['online'],
- productName: json['productName'],
- timeZone: json['timeZone'],
- updateTime: json['updateTime'],
- uuid: json['uuid'],
- productType: type,
- type: json['productType'],
- status: [],
- productUuid: json['productUuid']);
+ icon: tempIcon,
+ activeTime: json['activeTime'],
+ categoryName: json['categoryName'],
+ localKey: json['localKey'],
+ model: json['model'],
+ name: json['name'],
+ isOnline: json['online'],
+ productName: json['productName'],
+ timeZone: json['timeZone'],
+ updateTime: json['updateTime'],
+ uuid: json['uuid'],
+ productType: type,
+ type: json['productType'],
+
+ // Use the newly computed toggleStatus:
+ toggleStatus: computedToggleStatus,
+
+ // Or if you prefer to use the value returned by the backend when available:
+ // toggleStatus: json['toggleStatus'] ?? computedToggleStatus,
+
+ status: statusList ?? [],
+ subspace: json['subspace'] != null
+ ? DeviceSubspace.fromJson(json['subspace'])
+ : DeviceSubspace(
+ createdAt: null,
+ disabled: false,
+ subspaceName: '',
+ updatedAt: null,
+ uuid: '',
+ ),
+ productUuid: json['productUuid'],
+ );
}
Map toJson() {
@@ -118,9 +177,50 @@ class DeviceModel {
'updateTime': updateTime,
'uuid': uuid,
'productType': productType,
+ 'subspace': subspace?.toJson(), // serialize subspace
};
}
List getFunctions(DeviceType type) =>
devicesFunctionsMap[productType] ?? [];
}
+
+class DeviceSubspace {
+ String? uuid;
+ DateTime? createdAt;
+ DateTime? updatedAt;
+ String? subspaceName;
+ bool? disabled;
+
+ DeviceSubspace({
+ this.uuid,
+ this.createdAt,
+ this.updatedAt,
+ this.subspaceName,
+ this.disabled,
+ });
+
+ factory DeviceSubspace.fromJson(Map json) {
+ return DeviceSubspace(
+ uuid: json['uuid'],
+ createdAt: json['createdAt'] != null
+ ? DateTime.tryParse(json['createdAt'])
+ : null,
+ updatedAt: json['updatedAt'] != null
+ ? DateTime.tryParse(json['updatedAt'])
+ : null,
+ subspaceName: json['subspaceName'],
+ disabled: json['disabled'],
+ );
+ }
+
+ Map toJson() {
+ return {
+ 'uuid': uuid,
+ 'createdAt': createdAt?.toIso8601String(),
+ 'updatedAt': updatedAt?.toIso8601String(),
+ 'subspaceName': subspaceName,
+ 'disabled': disabled,
+ };
+ }
+}
diff --git a/lib/features/devices/view/device_settings/profile_page.dart b/lib/features/devices/view/device_settings/profile_page.dart
index 6e1f254..bb1d1df 100644
--- a/lib/features/devices/view/device_settings/profile_page.dart
+++ b/lib/features/devices/view/device_settings/profile_page.dart
@@ -38,8 +38,10 @@ class SettingProfilePage extends StatelessWidget {
final _bloc = BlocProvider.of(context);
return state is DeviceSettingLoadingState
? const Center(
- child:
- DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()),
+ child: DefaultContainer(
+ width: 50,
+ height: 50,
+ child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
@@ -55,15 +57,18 @@ class SettingProfilePage extends StatelessWidget {
child: SvgPicture.asset(
Assets.sosHomeIcon,
fit: BoxFit.fitHeight,
- height: MediaQuery.of(context).size.height * 0.13,
+ height:
+ MediaQuery.of(context).size.height * 0.13,
))
: CircleAvatar(
radius: 55,
backgroundColor: ColorsManager.graysColor,
child: ClipOval(
child: Column(
- crossAxisAlignment: CrossAxisAlignment.center,
- mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment:
+ CrossAxisAlignment.center,
+ mainAxisAlignment:
+ MainAxisAlignment.center,
children: [
Center(
child: SvgPicture.asset(
@@ -71,7 +76,10 @@ class SettingProfilePage extends StatelessWidget {
? Assets.fourSceneIcon
: Assets.sixSceneIcon,
fit: BoxFit.contain,
- height: MediaQuery.of(context).size.height * 0.08,
+ height: MediaQuery.of(context)
+ .size
+ .height *
+ 0.08,
),
),
],
@@ -89,7 +97,8 @@ class SettingProfilePage extends StatelessWidget {
children: [
IntrinsicWidth(
child: ConstrainedBox(
- constraints: const BoxConstraints(maxWidth: 200),
+ constraints:
+ const BoxConstraints(maxWidth: 200),
child: TextFormField(
maxLength: 30,
style: const TextStyle(
@@ -122,7 +131,8 @@ class SettingProfilePage extends StatelessWidget {
Assets.sosEditProfile,
color: Colors.grey,
fit: BoxFit.contain,
- height: MediaQuery.of(context).size.height * 0.02,
+ height: MediaQuery.of(context).size.height *
+ 0.02,
),
),
),
@@ -141,15 +151,17 @@ class SettingProfilePage extends StatelessWidget {
padding: const EdgeInsets.all(20),
child: InkWell(
onTap: () async {
- bool? val = await Navigator.of(context).push(
- MaterialPageRoute(
- builder: (context) => LocationSettingPage(
- space: spaces!.first,
- deviceId: device?.uuid ?? '',
- )),
- );
- if (val != null && val == true) {
- _bloc.add(const DeviceSettingInitialInfo());
+ if (HomeCubit.visitorPasswordManagement) {
+ bool? val = await Navigator.of(context).push(
+ MaterialPageRoute(
+ builder: (context) => LocationSettingPage(
+ space: spaces!.first,
+ deviceId: device?.uuid ?? '',
+ )),
+ );
+ if (val != null && val == true) {
+ _bloc.add(const DeviceSettingInitialInfo());
+ }
}
},
child: Row(
@@ -162,7 +174,8 @@ class SettingProfilePage extends StatelessWidget {
children: [
SizedBox(
child: BodyMedium(
- text: _bloc.deviceInfo.subspace.subspaceName,
+ text: _bloc
+ .deviceInfo.subspace.subspaceName,
fontColor: ColorsManager.textGray,
),
),
diff --git a/lib/features/devices/view/widgets/ACs/ac_interface.dart b/lib/features/devices/view/widgets/ACs/ac_interface.dart
index 218b820..3f54a80 100644
--- a/lib/features/devices/view/widgets/ACs/ac_interface.dart
+++ b/lib/features/devices/view/widgets/ACs/ac_interface.dart
@@ -1,9 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
+import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_event.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_state.dart';
+import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/ac_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface_controls.dart';
@@ -71,6 +73,7 @@ class AcInterface extends StatelessWidget {
onTap: () {
BlocProvider.of(context)
.add(AcSwitch(acSwitch: statusModel.acSwitch));
+
},
child: SvgPicture.asset(Assets.acSwitchIcon))
],
diff --git a/lib/features/devices/view/widgets/ACs/acs_view.dart b/lib/features/devices/view/widgets/ACs/acs_view.dart
index 7680ba7..5bde723 100644
--- a/lib/features/devices/view/widgets/ACs/acs_view.dart
+++ b/lib/features/devices/view/widgets/ACs/acs_view.dart
@@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_event.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_state.dart';
+import 'package:syncrow_app/features/devices/model/ac_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_list.dart';
@@ -40,6 +41,8 @@ class ACsView extends StatelessWidget {
extendBody: true,
appBar: deviceModel != null
? DeviceAppbar(
+ //BlocProvider.of(context).deviceStatus.acSwitch.toString()
+ value: true,
deviceName: deviceModel!.name!,
deviceUuid: deviceModel!.uuid!,
)
diff --git a/lib/features/devices/view/widgets/all_devices.dart b/lib/features/devices/view/widgets/all_devices.dart
new file mode 100644
index 0000000..6549d90
--- /dev/null
+++ b/lib/features/devices/view/widgets/all_devices.dart
@@ -0,0 +1,110 @@
+import 'package:flutter/material.dart';
+import 'package:syncrow_app/features/devices/model/device_model.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:syncrow_app/features/devices/view/widgets/room_page_switch.dart';
+import 'package:syncrow_app/generated/assets.dart';
+import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
+
+class AllDevices extends StatefulWidget {
+ const AllDevices({super.key, required this.allDevices});
+
+ final List allDevices;
+
+ @override
+ _AllDevicesState createState() => _AllDevicesState();
+}
+
+class _AllDevicesState extends State {
+ final TextEditingController _searchController = TextEditingController();
+ List _filteredDevices = [];
+
+ @override
+ void initState() {
+ super.initState();
+ _filteredDevices = widget.allDevices ?? [];
+ _searchController.addListener(_filterDevices);
+ }
+
+ @override
+ void dispose() {
+ _searchController.removeListener(_filterDevices);
+ _searchController.dispose();
+ super.dispose();
+ }
+
+ void _filterDevices() {
+ final query = _searchController.text.toLowerCase();
+ setState(() {
+ _filteredDevices = widget.allDevices!
+ .where((device) => device.name!.toLowerCase().contains(query))
+ .toList();
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: [
+ if (widget.allDevices.isNotEmpty)
+ TextFormField(
+ controller: _searchController,
+ decoration: InputDecoration(
+ hintText: 'Search',
+ hintStyle: const TextStyle(
+ color: ColorsManager.textGray,
+ fontSize: 16,
+ fontWeight: FontWeight.w400),
+ prefixIcon: Container(
+ padding: const EdgeInsets.all(5.0),
+ margin: const EdgeInsets.all(10.0),
+ child: SvgPicture.asset(
+ Assets.searchIcon,
+ fit: BoxFit.contain,
+ ),
+ ),
+ border: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(8.0),
+ ),
+ ),
+ ),
+ _filteredDevices.isNotEmpty
+ ? Expanded(
+ child: GridView.builder(
+ gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
+ crossAxisCount: 2,
+ crossAxisSpacing: 10,
+ mainAxisSpacing: 10,
+ childAspectRatio: 1.5,
+ ),
+ padding: const EdgeInsets.only(top: 10),
+ itemCount: _filteredDevices.length,
+ itemBuilder: (context, index) {
+ return RoomPageSwitch(
+ allDevices: _filteredDevices,
+ isAllDevices: true,
+ device: _filteredDevices[index]);
+ },
+ ),
+ )
+ : widget.allDevices.isNotEmpty
+ ? const Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Center(
+ child: Text(
+ 'No Results Found',
+ style: TextStyle(
+ color: ColorsManager.grayColor,
+ fontSize: 14,
+ fontWeight: FontWeight.w400),
+ )),
+ ],
+ ),
+ )
+ : const SizedBox(),
+ ],
+ );
+ }
+}
diff --git a/lib/features/devices/view/widgets/ceiling_sensor/ceiling_sensor_interface.dart b/lib/features/devices/view/widgets/ceiling_sensor/ceiling_sensor_interface.dart
index 17ba0d0..77101a7 100644
--- a/lib/features/devices/view/widgets/ceiling_sensor/ceiling_sensor_interface.dart
+++ b/lib/features/devices/view/widgets/ceiling_sensor/ceiling_sensor_interface.dart
@@ -250,7 +250,9 @@ class CeilingSensorInterface extends StatelessWidget {
),
] else if (button['title'] == 'Space Type') ...[
Text(
- model.spaceType.name.toString(),
+ model.spaceType.name.toString() == "none"
+ ? "Office"
+ : model.spaceType.name.toString(),
style: const TextStyle(color: Colors.black),
),
] else ...[
@@ -299,7 +301,13 @@ class CeilingSensorInterface extends StatelessWidget {
);
if (result != null) {
bloc.add(ChangeValueEvent(
- type: title.toString(), value: result, code: 'nobody_time'));
+ type: title.toString(),
+ value: result
+ .toString()
+ .toLowerCase()
+ .replaceAll('sec', 's')
+ .replaceAll('1hr', '1hour'), // Replacing "sec" with "s"
+ code: 'nobody_time'));
}
} else if (title == 'Maximum Distance') {
final result = await _showDialog(
diff --git a/lib/features/devices/view/widgets/ceiling_sensor/presence_record.dart b/lib/features/devices/view/widgets/ceiling_sensor/presence_record.dart
index 9599676..3595cac 100644
--- a/lib/features/devices/view/widgets/ceiling_sensor/presence_record.dart
+++ b/lib/features/devices/view/widgets/ceiling_sensor/presence_record.dart
@@ -90,9 +90,7 @@ class PresenceRecord extends StatelessWidget {
: Colors.grey,
),
title: Text(
- record.value == 'true'
- ? "Opened"
- : "Closed",
+ record.value.toString(),
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
diff --git a/lib/features/devices/view/widgets/ceiling_sensor/presence_space_type.dart b/lib/features/devices/view/widgets/ceiling_sensor/presence_space_type.dart
index 970f62c..79dbe6e 100644
--- a/lib/features/devices/view/widgets/ceiling_sensor/presence_space_type.dart
+++ b/lib/features/devices/view/widgets/ceiling_sensor/presence_space_type.dart
@@ -106,12 +106,11 @@ class _PresenceSpaceTypeDialogState extends State {
padding: const EdgeInsets.all(10),
child: SvgPicture.asset(
icon,
-
),
),
const SizedBox(height: 4),
Text(
- title,
+ title == "None" ? "Office" : title,
style: Theme.of(context)
.textTheme
.bodySmall
diff --git a/lib/features/devices/view/widgets/curtains/curtain_view.dart b/lib/features/devices/view/widgets/curtains/curtain_view.dart
index 6965008..8778f7d 100644
--- a/lib/features/devices/view/widgets/curtains/curtain_view.dart
+++ b/lib/features/devices/view/widgets/curtains/curtain_view.dart
@@ -6,6 +6,7 @@ import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_event.dar
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_buttons.dart';
+import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/generated/assets.dart';
@@ -33,11 +34,17 @@ class CurtainView extends StatelessWidget {
// blindHeight = state.blindHeight;
}
return DefaultScaffold(
+ appBar: DeviceAppbar(
+ deviceName: curtain!.name!,
+ deviceUuid: curtain!.uuid!,
+ ),
title: curtain.name,
child: state is CurtainLoadingState
? const Center(
- child:
- DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()),
+ child: DefaultContainer(
+ width: 50,
+ height: 50,
+ child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
@@ -62,37 +69,56 @@ class CurtainView extends StatelessWidget {
children: [
SvgPicture.asset(
Assets.assetsIconsCurtainsIconCurtainHolder,
- width: MediaQuery.sizeOf(context).width * 0.75,
+ width:
+ MediaQuery.sizeOf(context).width * 0.75,
),
SizedBox(
- width: MediaQuery.sizeOf(context).width * 0.75,
+ width:
+ MediaQuery.sizeOf(context).width * 0.75,
child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ mainAxisAlignment:
+ MainAxisAlignment.spaceBetween,
children: [
SizedBox(
- width: MediaQuery.sizeOf(context).width * 0.025,
+ width:
+ MediaQuery.sizeOf(context).width *
+ 0.025,
),
AnimatedContainer(
- duration: const Duration(milliseconds: 200),
+ duration:
+ const Duration(milliseconds: 200),
curve: Curves.linear,
- height: MediaQuery.sizeOf(context).height * 0.35,
- width: MediaQuery.sizeOf(context).width * 0.35,
+ height: MediaQuery.sizeOf(context)
+ .height *
+ 0.35,
+ width:
+ MediaQuery.sizeOf(context).width *
+ 0.35,
child: Stack(
children: List.generate(
4,
(index) {
- double spacing = curtainWidth / 7.5;
- double leftMostPosition = index * spacing;
+ double spacing =
+ curtainWidth / 7.5;
+ double leftMostPosition =
+ index * spacing;
return AnimatedPositioned(
- duration: const Duration(milliseconds: 200),
+ duration: const Duration(
+ milliseconds: 200),
curve: Curves.linear,
left: leftMostPosition,
child: SizedBox(
- height:
- MediaQuery.sizeOf(context).height * 0.35,
- width: MediaQuery.sizeOf(context).width * 0.08,
+ height: MediaQuery.sizeOf(
+ context)
+ .height *
+ 0.35,
+ width: MediaQuery.sizeOf(
+ context)
+ .width *
+ 0.08,
child: SvgPicture.asset(
- Assets.assetsIconsCurtainsIconVerticalBlade,
+ Assets
+ .assetsIconsCurtainsIconVerticalBlade,
fit: BoxFit.fill,
),
),
@@ -102,23 +128,37 @@ class CurtainView extends StatelessWidget {
),
),
AnimatedContainer(
- duration: const Duration(milliseconds: 200),
+ duration:
+ const Duration(milliseconds: 200),
curve: Curves.linear,
- height: MediaQuery.sizeOf(context).height * 0.35,
- width: MediaQuery.sizeOf(context).width * 0.35,
+ height: MediaQuery.sizeOf(context)
+ .height *
+ 0.35,
+ width:
+ MediaQuery.sizeOf(context).width *
+ 0.35,
child: Stack(
children: List.generate(
4,
(index) {
- double spacing = curtainWidth / 7.5;
- double rightMostPosition = index * spacing;
+ double spacing =
+ curtainWidth / 7.5;
+ double rightMostPosition =
+ index * spacing;
return AnimatedPositioned(
- duration: const Duration(milliseconds: 200),
+ duration: const Duration(
+ milliseconds: 200),
curve: Curves.linear,
right: rightMostPosition,
child: SizedBox(
- height: MediaQuery.sizeOf(context).height * 0.35,
- width: MediaQuery.sizeOf(context).width * 0.08,
+ height: MediaQuery.sizeOf(
+ context)
+ .height *
+ 0.35,
+ width: MediaQuery.sizeOf(
+ context)
+ .width *
+ 0.08,
child: SvgPicture.asset(
Assets.rightVerticalBlade,
fit: BoxFit.fill,
@@ -130,7 +170,9 @@ class CurtainView extends StatelessWidget {
),
),
SizedBox(
- width: MediaQuery.sizeOf(context).width * 0.025,
+ width:
+ MediaQuery.sizeOf(context).width *
+ 0.025,
),
],
),
diff --git a/lib/features/devices/view/widgets/device_appbar.dart b/lib/features/devices/view/widgets/device_appbar.dart
index 0e43711..bc64615 100644
--- a/lib/features/devices/view/widgets/device_appbar.dart
+++ b/lib/features/devices/view/widgets/device_appbar.dart
@@ -1,3 +1,4 @@
+import 'dart:io';
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
@@ -6,14 +7,27 @@ import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class DeviceAppbar extends StatelessWidget implements PreferredSizeWidget {
final String deviceName;
final String deviceUuid;
+ final bool? value;
+
final double appBarHeight = 56.0;
final void Function()? onPressed;
const DeviceAppbar(
- {super.key, required this.deviceName, required this.deviceUuid, this.onPressed});
+ {super.key,
+ required this.deviceName,
+ this.value,
+ required this.deviceUuid,
+ this.onPressed});
@override
Widget build(BuildContext context) {
return AppBar(
+ leading: IconButton(
+ onPressed: () {
+ Navigator.of(context).pop(value ?? true);
+ },
+ icon: Icon(
+ Platform.isIOS ? Icons.arrow_back_ios : Icons.arrow_back,
+ )),
backgroundColor: Colors.transparent,
centerTitle: true,
title: BodyLarge(
diff --git a/lib/features/devices/view/widgets/devices_view_body.dart b/lib/features/devices/view/widgets/devices_view_body.dart
index 930f5a5..bca3173 100644
--- a/lib/features/devices/view/widgets/devices_view_body.dart
+++ b/lib/features/devices/view/widgets/devices_view_body.dart
@@ -1,12 +1,12 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
-import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
+import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
+import 'package:syncrow_app/features/devices/view/widgets/all_devices.dart';
import 'package:syncrow_app/features/devices/view/widgets/room_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/rooms_slider.dart';
import 'package:syncrow_app/features/devices/view/widgets/wizard_page.dart';
-import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_bloc.dart';
import 'package:syncrow_app/features/scene/view/scene_view.dart';
import 'package:syncrow_app/features/shared_widgets/create_unit.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
@@ -14,103 +14,130 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.da
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
-class DevicesViewPage extends StatelessWidget {
- const DevicesViewPage({super.key});
-
- @override
- Widget build(BuildContext context) {
- return BlocProvider(
- create: (context) => SceneBloc(), // Initialize your SceneBloc here
- child: DevicesViewBody(),
- );
- }
-}
-
class DevicesViewBody extends StatelessWidget {
- const DevicesViewBody({
- super.key,
- });
-
+ const DevicesViewBody({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
- return BlocBuilder(
- builder: (context, state) {
- if (state is DevicesLoading ||
- state is GetDevicesLoading ||
- state is DevicesCategoriesLoading) {
- return const Center(child: CircularProgressIndicator());
- } else {
- return HomeCubit.getInstance().spaces?.isEmpty ?? true
- ? const CreateUnitWidget()
- : Column(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- Row(
- children: [
- TitleMedium(
- text: StringsManager.devices,
- style: context.titleMedium.copyWith(
- fontSize: 25,
- ),
- ),
- ],
- ),
- SizedBox(
- height: MediaQuery.of(context).size.height * 0.1,
- child: const SceneView(
- pageType: true,
- )),
- const SizedBox(
- height: 20,
- ),
- const RoomsSlider(),
- const SizedBox(
- height: 10,
- ),
- Expanded(
- child: PageView(
- controller: HomeCubit.getInstance().devicesPageController,
- onPageChanged: (index) {
- HomeCubit.getInstance().devicesPageChanged(index);
- },
- children: [
- WizardPage(
- groupsList: DevicesCubit.getInstance().allCategories ?? [],
- ),
- if (HomeCubit.getInstance().selectedSpace != null)
- ...HomeCubit.getInstance().selectedSpace!.subspaces.map(
- (room) {
- return RoomPage(
- room: room,
- );
- },
- )
- ],
- ),
- ),
- HomeCubit.getInstance().selectedSpace != null
- ? Padding(
- padding: const EdgeInsets.symmetric(
- vertical: 7,
- ),
- child: SmoothPageIndicator(
- controller: HomeCubit.getInstance().devicesPageController,
- count: HomeCubit.getInstance().selectedSpace!.subspaces.length + 1,
- effect: const WormEffect(
- paintStyle: PaintingStyle.stroke,
- dotHeight: 8,
- dotWidth: 8,
- ),
- ),
- )
- : const Center(
- child: BodyLarge(text: 'No Home Found'),
- ),
- ],
- );
+ return BlocBuilder(
+ builder: (context, homeState) {
+ final homeCubit = HomeCubit.getInstance();
+
+ // Handle state priority: Errors first
+ if (homeState is ActivationError) {
+ return const CreateUnitWidget();
}
+
+ // Handle loading states
+ if (homeState is GetSpacesLoading || homeState is HomeLoading) {
+ return const Center(child: CircularProgressIndicator());
+ }
+
+ // Handle error states
+ if (homeState is GetSpacesError) {
+ return const CreateUnitWidget();
+ }
+
+ // Handle success states
+ if (homeState is GetSpacesSuccess ||
+ homeState is RoomUnSelected ||
+ homeState is RoomSelected ||
+ homeState is NavChangePage) {
+ // Show empty state if no spaces
+ if (homeCubit.spaces.isEmpty) {
+ return const CreateUnitWidget();
+ }
+
+ return BlocBuilder(
+ builder: (context, devicesState) {
+ // Devices loading states
+ if (devicesState is DevicesLoading ||
+ devicesState is DevicesCategoriesLoading ||
+ devicesState is GetDevicesLoading) {
+ return const Center(child: CircularProgressIndicator());
+ }
+
+ // Devices error state
+ if (devicesState is GetDevicesError) {
+ return Center(child: BodyLarge(text: devicesState.errorMsg));
+ }
+ // Main content for both GetSpacesSuccess and RoomUnSelected
+ return _buildMainContent(context, homeCubit);
+ },
+ );
+ }
+
+ // Fallback for unknown states
+ return const Center(child: BodyLarge(text: ''));
},
);
}
+
+ Widget _buildMainContent(BuildContext context, HomeCubit homeCubit) {
+ final devicesCubit = context.read();
+
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Row(
+ children: [
+ TitleMedium(
+ text: StringsManager.devices,
+ style: context.titleMedium.copyWith(fontSize: 25),
+ ),
+ ],
+ ),
+ SizedBox(
+ height: MediaQuery.of(context).size.height * 0.1,
+ child: const SceneView(pageType: true),
+ ),
+ const SizedBox(height: 20),
+ const RoomsSlider(),
+ const SizedBox(height: 10),
+ Expanded(
+ child: PageView(
+ controller: homeCubit.devicesPageController,
+ onPageChanged: (index) {
+ homeCubit.devicesPageChanged(index);
+ if (index == 0) {
+ devicesCubit.fetchAllDevices(homeCubit.selectedSpace);
+ }
+ },
+ children: [
+ AllDevices(
+ allDevices: devicesCubit.allDevices,
+ ),
+ WizardPage(
+ groupsList: devicesCubit.allCategories ?? [],
+ ),
+ if (homeCubit.selectedSpace != null)
+ ...homeCubit.selectedSpace!.subspaces.map(
+ (room) => RoomPage(room: room),
+ ),
+ ],
+ ),
+ ),
+ _buildPageIndicator(homeCubit),
+ ],
+ );
+ }
+
+ Widget _buildPageIndicator(HomeCubit homeCubit) {
+ return homeCubit.selectedSpace != null
+ ? Padding(
+ padding: const EdgeInsets.symmetric(vertical: 7),
+ child: SmoothPageIndicator(
+ controller: homeCubit.devicesPageController,
+ count: homeCubit.selectedSpace!.subspaces.length + 2,
+ effect: const WormEffect(
+ paintStyle: PaintingStyle.stroke,
+ dotHeight: 8,
+ dotWidth: 8,
+ ),
+ ),
+ )
+ : const Center(
+ child: BodyLarge(text: 'No Home Found'),
+ );
+ }
}
diff --git a/lib/features/devices/view/widgets/garage_door/garage_door_screen.dart b/lib/features/devices/view/widgets/garage_door/garage_door_screen.dart
index 3d59c4a..0a84a9f 100644
--- a/lib/features/devices/view/widgets/garage_door/garage_door_screen.dart
+++ b/lib/features/devices/view/widgets/garage_door/garage_door_screen.dart
@@ -5,6 +5,7 @@ import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_b
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_event.dart';
import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
+import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart';
import 'package:syncrow_app/features/devices/view/widgets/garage_door/garage_preferences_settings.dart';
import 'package:syncrow_app/features/devices/view/widgets/garage_door/garage_records_screen.dart';
import 'package:syncrow_app/features/devices/view/widgets/garage_door/schedule_garage_screen.dart';
@@ -22,6 +23,10 @@ class GarageDoorScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return DefaultScaffold(
+ appBar: DeviceAppbar(
+ deviceName: device!.name!,
+ deviceUuid: device!.uuid!,
+ ),
title: 'Garage Door Opener',
child: BlocProvider(
create: (context) => GarageDoorBloc(GDId: device?.uuid ?? '')
diff --git a/lib/features/devices/view/widgets/room_page_switch.dart b/lib/features/devices/view/widgets/room_page_switch.dart
index af1bfd5..2893b63 100644
--- a/lib/features/devices/view/widgets/room_page_switch.dart
+++ b/lib/features/devices/view/widgets/room_page_switch.dart
@@ -5,6 +5,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
+import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/6_scene_switch/six_scene_screen.dart';
@@ -28,23 +29,31 @@ import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_interf
import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/water_heater/water_heater_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/water_leak/water_leak_screen.dart';
+import 'package:syncrow_app/features/shared_widgets/custom_switch.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class RoomPageSwitch extends StatelessWidget {
- const RoomPageSwitch({
- super.key,
- required this.device,
- });
+ const RoomPageSwitch(
+ {super.key,
+ required this.device,
+ this.isAllDevices = false,
+ this.allDevices});
final DeviceModel device;
+ final List? allDevices;
+ final bool isAllDevices;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
- showDeviceInterface(device, context);
+ showDeviceInterface(
+ device: device,
+ context: context,
+ isAllDevices: isAllDevices,
+ allDevices: allDevices);
},
child: DefaultContainer(
padding: const EdgeInsets.all(15),
@@ -60,22 +69,38 @@ class RoomPageSwitch extends StatelessWidget {
device.icon!,
fit: BoxFit.contain,
),
- // CustomSwitch(
- // device: device,
- // ),
+ isAllDevices
+ ? CustomSwitch(
+ device: device,
+ )
+ : const SizedBox(),
],
),
Flexible(
child: FittedBox(
- child: Text(
- device.name ?? "",
- overflow: TextOverflow.ellipsis,
- maxLines: 2,
- style: context.bodyLarge.copyWith(
- fontWeight: FontWeight.bold,
- fontSize: 20,
- color: Colors.grey,
- ),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ device.name ?? "",
+ overflow: TextOverflow.ellipsis,
+ maxLines: 2,
+ style: context.bodyLarge.copyWith(
+ fontWeight: FontWeight.bold,
+ fontSize: 20,
+ color: Colors.grey,
+ ),
+ ),
+ Text(
+ device.subspace!.subspaceName ?? '',
+ overflow: TextOverflow.ellipsis,
+ style: context.bodySmall.copyWith(
+ fontWeight: FontWeight.w400,
+ fontSize: 10,
+ color: Colors.grey,
+ ),
+ ),
+ ],
),
),
),
@@ -89,14 +114,23 @@ class RoomPageSwitch extends StatelessWidget {
/// Shows the device interface based on the product type of the device.
///
/// The [device] parameter represents the device model.
-void showDeviceInterface(DeviceModel device, BuildContext context) {
+Future showDeviceInterface(
+ {required DeviceModel device,
+ required BuildContext context,
+ required isAllDevices,
+ List? allDevices}) async {
+ final devicesCubit = context.read();
+
switch (device.productType) {
case DeviceType.AC:
- Navigator.push(
+ var value = await Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
ACsView(deviceModel: device)));
+ if (value && isAllDevices) {
+ devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
+ }
// navigateToInterface(ACsView(deviceModel: device), context);
break;
case DeviceType.WallSensor:
@@ -116,12 +150,15 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
// navigateToInterface(CeilingSensorInterface(ceilingSensor: device), context);
break;
case DeviceType.Curtain:
- Navigator.push(
+ var value = await Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => CurtainView(
curtain: device,
)));
+ if (value && isAllDevices) {
+ devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
+ }
break;
case DeviceType.Blind:
break;
@@ -143,30 +180,43 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
case DeviceType.LightBulb:
navigateToInterface(LightInterface(light: device), context);
case DeviceType.OneGang:
- Navigator.push(
+ var value = await Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
OneGangInterface(gangSwitch: device)));
+
+ if (value && isAllDevices) {
+ devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
+ }
case DeviceType.TwoGang:
- Navigator.push(
+ var value = await Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
TwoGangInterface(gangSwitch: device)));
+ if (value && isAllDevices) {
+ devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
+ }
case DeviceType.ThreeGang:
- Navigator.push(
+ var value = await Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
ThreeGangInterface(gangSwitch: device)));
+ if (value && isAllDevices) {
+ devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
+ }
case DeviceType.WH:
- Navigator.push(
+ var value = await Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
WaterHeaterPage(device: device)));
+ if (value && isAllDevices) {
+ devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
+ }
case DeviceType.DS:
Navigator.push(
context,
@@ -182,31 +232,43 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
PowerClampPage(device: device)));
case DeviceType.OneTouch:
- Navigator.push(
+ var value = await Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
OneTouchScreen(device: device)));
+ if (value && isAllDevices) {
+ devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
+ }
case DeviceType.TowTouch:
- Navigator.push(
+ var value = await Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
TwoTouchInterface(touchSwitch: device)));
+ if (value && isAllDevices) {
+ devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
+ }
case DeviceType.ThreeTouch:
- Navigator.push(
+ var value = await Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
ThreeTouchInterface(touchSwitch: device)));
+ if (value && isAllDevices) {
+ devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
+ }
case DeviceType.GarageDoor:
- Navigator.push(
+ var value = await Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
GarageDoorScreen(device: device)));
+ if (value && isAllDevices) {
+ devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
+ }
case DeviceType.WaterLeak:
Navigator.push(
@@ -216,18 +278,24 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
WaterLeakScreen(device: device)));
case DeviceType.SixScene:
- Navigator.push(
+ var value = await Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
SixSceneScreen(device: device)));
+ if (value && isAllDevices) {
+ devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
+ }
case DeviceType.FourScene:
- Navigator.push(
+ var value = await Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
FourSceneScreen(device: device)));
+ if (value && isAllDevices) {
+ devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
+ }
case DeviceType.SOS:
Navigator.push(
diff --git a/lib/features/devices/view/widgets/rooms_slider.dart b/lib/features/devices/view/widgets/rooms_slider.dart
index cfe1f26..06c34d9 100644
--- a/lib/features/devices/view/widgets/rooms_slider.dart
+++ b/lib/features/devices/view/widgets/rooms_slider.dart
@@ -23,6 +23,21 @@ class RoomsSlider extends StatelessWidget {
HomeCubit.getInstance().roomSliderPageChanged(index);
},
children: [
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 15),
+ child: InkWell(
+ onTap: () {
+ HomeCubit.getInstance().unselectRoom();
+ },
+ child: TitleMedium(
+ text: 'All Devices',
+ style: context.titleMedium.copyWith(
+ fontSize: 25,
+ color: ColorsManager.textPrimaryColor,
+ ),
+ ),
+ ),
+ ),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: InkWell(
@@ -43,7 +58,10 @@ class RoomsSlider extends StatelessWidget {
(room) => InkWell(
onTap: () {
HomeCubit.getInstance().roomSliderPageChanged(
- HomeCubit.getInstance().selectedSpace!.subspaces.indexOf(room));
+ HomeCubit.getInstance()
+ .selectedSpace!
+ .subspaces
+ .indexOf(room));
},
child: TitleMedium(
text: room.name!,
@@ -51,7 +69,8 @@ class RoomsSlider extends StatelessWidget {
fontSize: 25,
color: HomeCubit.getInstance().selectedRoom == room
? ColorsManager.textPrimaryColor
- : ColorsManager.textPrimaryColor.withOpacity(.2),
+ : ColorsManager.textPrimaryColor
+ .withOpacity(.2),
),
),
),
diff --git a/lib/features/devices/view/widgets/smart_door/door_grid.dart b/lib/features/devices/view/widgets/smart_door/door_grid.dart
index a37be12..6d49a31 100644
--- a/lib/features/devices/view/widgets/smart_door/door_grid.dart
+++ b/lib/features/devices/view/widgets/smart_door/door_grid.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
+import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/members_management_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/smart_linkage_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/temporary_password_page.dart';
@@ -14,6 +15,8 @@ class DoorLockGrid extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final buttons = doorLockButtons(val: uuid);
+
return GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
@@ -23,14 +26,15 @@ class DoorLockGrid extends StatelessWidget {
crossAxisSpacing: 10,
childAspectRatio: 1.75 / 1,
),
- itemCount: 4,
+ itemCount: buttons.length,
itemBuilder: (context, index) => DefaultContainer(
onTap: () {
//TODO: remove checking after adding the pages
doorLockButtons()[index]['page'] != null
? Navigator.of(context).push(
MaterialPageRoute(
- builder: (context) => doorLockButtons(val: uuid)[index]['page'] as Widget,
+ builder: (context) =>
+ doorLockButtons(val: uuid)[index]['page'] as Widget,
),
)
: null;
@@ -75,11 +79,12 @@ List