restrict_spaceMemberUser_and_change_SignUpModel

This commit is contained in:
mohammad
2025-01-23 18:35:01 +03:00
parent 827585815b
commit 790479effb
20 changed files with 643 additions and 322 deletions

View File

@ -7,10 +7,10 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:onesignal_flutter/onesignal_flutter.dart'; import 'package:onesignal_flutter/onesignal_flutter.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:share_plus/share_plus.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/model/space_model.dart';
import 'package:syncrow_app/features/app_layout/view/widgets/app_bar_home_dropdown.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/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/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/subspace_model.dart'; import 'package:syncrow_app/features/devices/model/subspace_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.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/services/api/spaces_api.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
part 'home_state.dart'; part 'home_state.dart';
class HomeCubit extends Cubit<HomeState> { class HomeCubit extends Cubit<HomeState> {
HomeCubit._() : super(HomeInitial()) { HomeCubit._() : super(HomeInitial()) {
// checkIfNotificationPermissionGranted(); // checkIfNotificationPermissionGranted();
fetchUserInfo(); fetchUserInfo().then(
if (selectedSpace == null) { (value) {
fetchUnitsByUserId(); if (selectedSpace == null) {
// .then((value) { fetchUnitsByUserId();
// if (selectedSpace != null) { fetchPermissions();
// fetchRoomsByUnitId(selectedSpace!);
// } // .then((value) {
// }); // if (selectedSpace != null) {
} // fetchRoomsByUnitId(selectedSpace!);
// }
// });
}
},
);
} }
static UserModel? user; static UserModel? user;
List<PermissionModel>? permissionModel = [];
static HomeCubit? _instance; static HomeCubit? _instance;
static HomeCubit getInstance() { static HomeCubit getInstance() {
// If an instance already exists, return it // If an instance already exists, return it
@ -56,15 +63,87 @@ class HomeCubit extends Cubit<HomeState> {
Future fetchUserInfo() async { Future fetchUserInfo() async {
try { try {
emit(HomeLoading());
var uuid = var uuid =
await const FlutterSecureStorage().read(key: UserModel.userUuidKey); await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
user = await ProfileApi().fetchUserInfo(uuid); user = await ProfileApi().fetchUserInfo(uuid);
emit(HomeUserInfoLoaded(user!)); // Emit state after fetching user info emit(HomeUserInfoLoaded(user!));
} catch (e) { } catch (e) {
return; return;
} }
} }
static bool manageSupSpace = false;
static bool manageScene = false;
static bool manageDeviceLocation = false;
static bool visitorPasswordManagement = false;
Future<void> 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<PermissionModel> 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) { void emitSafe(HomeState newState) {
final cubit = this; final cubit = this;
if (!cubit.isClosed) { if (!cubit.isClosed) {
@ -89,7 +168,7 @@ class HomeCubit extends Cubit<HomeState> {
static HomeCubit get(context) => BlocProvider.of(context); static HomeCubit get(context) => BlocProvider.of(context);
List<SpaceModel>? spaces; List<SpaceModel>? spaces = [];
SpaceModel? selectedSpace; SpaceModel? selectedSpace;
@ -261,6 +340,7 @@ class HomeCubit extends Cubit<HomeState> {
emitSafe(GetSpacesLoading()); emitSafe(GetSpacesLoading());
try { try {
spaces = await SpacesAPI.getSpacesByUserId(); spaces = await SpacesAPI.getSpacesByUserId();
emitSafe(GetSpacesSuccess(spaces!));
} catch (failure) { } catch (failure) {
emitSafe(GetSpacesError("No units found")); emitSafe(GetSpacesError("No units found"));
return; return;
@ -298,11 +378,13 @@ class HomeCubit extends Cubit<HomeState> {
await const FlutterSecureStorage().read(key: UserModel.userUuidKey); await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
var res = await SpacesAPI.activationCodeSpace( var res = await SpacesAPI.activationCodeSpace(
activationCode: activationCode, userUuid: uuid); activationCode: activationCode, userUuid: uuid);
if (res['success'] == true) { if (res['success'] == true) {
fetchUserInfo(); fetchUserInfo();
fetchUnitsByUserId(); fetchUnitsByUserId();
} }
emitSafe(GetSpacesSuccess(spaces!)); emitSafe(GetSpacesSuccess(spaces!));
return res['success']; return res['success'];
} on DioException catch (e) { } on DioException catch (e) {
final errorMessage = e.response?.data['error']['message']; final errorMessage = e.response?.data['error']['message'];
@ -378,6 +460,8 @@ class HomeCubit extends Cubit<HomeState> {
// ), // ),
// onPressed: () {}, // onPressed: () {},
// ), // ),
// HomeCubit.permissionModel!.scene!.visible == true
// ?
IconButton( IconButton(
icon: const Icon( icon: const Icon(
Icons.add, Icons.add,
@ -413,7 +497,8 @@ class HomeCubit extends Cubit<HomeState> {
.read<CreateSceneBloc>() .read<CreateSceneBloc>()
.add(const ClearTabToRunSetting()); .add(const ClearTabToRunSetting());
}, },
), )
// : const SizedBox(),
// IconButton( // IconButton(
// icon: const Icon( // icon: const Icon(
// Icons.more_vert, // Icons.more_vert,
@ -503,3 +588,28 @@ BottomNavigationBarItem defaultBottomNavBarItem(
label: label, label: label,
); );
} }
// class PermissionUtils {
// // Check if the "VIEW" permission exists in "MANAGE_SUBSPACE"
// static bool hasViewPermission(List<dynamic> permissions) {
// return _hasPermission(permissions, 'MANAGE_SUBSPACE', 'VIEW');
// }
// // Generalized permission checker
// static bool _hasPermission(
// List<dynamic> 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;
// }
// }

View File

@ -14,9 +14,9 @@ class HomeError extends HomeState {
} }
class HomeSuccess extends HomeState {} class HomeSuccess extends HomeState {}
class ActivationSuccess extends HomeState {}
///specific states
//get spaces
class GetSpacesLoading extends HomeLoading {} class GetSpacesLoading extends HomeLoading {}
class GetSpacesSuccess extends HomeSuccess { class GetSpacesSuccess extends HomeSuccess {
@ -64,10 +64,16 @@ class RoomSelected extends HomeState {
class RoomUnSelected extends HomeState {} class RoomUnSelected extends HomeState {}
class NavChangePage extends HomeState {} class NavChangePage extends HomeState {}
class HomePermissionUpdated extends HomeState {}
// Define new state classes
class HomeUserInfoLoaded extends HomeState { class HomeUserInfoLoaded extends HomeState {
final UserModel user; final UserModel user;
HomeUserInfoLoaded(this.user); HomeUserInfoLoaded(this.user);
} }
class PermissionsRoleLoaded extends HomeState {
final List<PermissionModel> permissionModel;
PermissionsRoleLoaded(this.permissionModel);
}

View File

@ -0,0 +1,39 @@
class PermissionModel {
final String title;
final List<PermissionAttributes> subOptions;
PermissionModel({required this.title, required this.subOptions});
factory PermissionModel.fromJson(Map<String, dynamic> json) {
return PermissionModel(
title: json['title'],
subOptions: (json['subOptions'] as List)
.map((e) => PermissionAttributes.fromJson(e))
.toList(),
);
}
static List<PermissionModel> fromJsonList(List<dynamic> jsonList) {
return jsonList.map((json) => PermissionModel.fromJson(json)).toList();
}
}
class PermissionAttributes {
final String title;
final List<PermissionAttributes>? subOptions;
final bool? isChecked;
PermissionAttributes({required this.title, this.subOptions, this.isChecked});
factory PermissionAttributes.fromJson(Map<String, dynamic> json) {
return PermissionAttributes(
title: json['title'],
isChecked: json['isChecked'],
subOptions: json['subOptions'] != null
? (json['subOptions'] as List)
.map((e) => PermissionAttributes.fromJson(e))
.toList()
: null,
);
}
}

View File

@ -17,7 +17,10 @@ class AppLayout extends StatelessWidget {
child: BlocBuilder<HomeCubit, HomeState>( child: BlocBuilder<HomeCubit, HomeState>(
builder: (context, state) { builder: (context, state) {
return DefaultScaffold( 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(), bottomNavBar: const DefaultNavBar(),
child: const AppBody(), child: const AppBody(),
); );

View File

@ -35,8 +35,10 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
) )
: null, : null,
), ),
actions: HomeCubit.appBarActions[ actions: HomeCubit.manageScene
HomeCubit.bottomNavItems[HomeCubit.pageIndex].label], ? HomeCubit.appBarActions[
HomeCubit.bottomNavItems[HomeCubit.pageIndex].label]
: null,
)); ));
}, },
); );

View File

@ -221,6 +221,7 @@ class AuthCubit extends Cubit<AuthState> {
List<String> userFullName = fullName.split(' '); List<String> userFullName = fullName.split(' ');
response = await AuthenticationAPI.signUp( response = await AuthenticationAPI.signUp(
model: SignUpModel( model: SignUpModel(
hasAcceptedAppAgreement: true,
email: email.toLowerCase(), email: email.toLowerCase(),
password: signUpPassword, password: signUpPassword,
firstName: userFullName[0], firstName: userFullName[0],

View File

@ -3,10 +3,12 @@ class SignUpModel {
final String password; final String password;
final String firstName; final String firstName;
final String lastName; final String lastName;
final bool hasAcceptedAppAgreement;
SignUpModel( SignUpModel(
{required this.email, {required this.email,
required this.password, required this.password,
required this.hasAcceptedAppAgreement,
required this.firstName, required this.firstName,
required this.lastName}); required this.lastName});
@ -15,7 +17,8 @@ class SignUpModel {
email: json['email'], email: json['email'],
password: json['password'], password: json['password'],
firstName: json['firstName'], firstName: json['firstName'],
lastName: json['lastName']); lastName: json['lastName'],
hasAcceptedAppAgreement: true);
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -24,6 +27,7 @@ class SignUpModel {
'password': password, 'password': password,
'firstName': firstName, 'firstName': firstName,
'lastName': lastName, 'lastName': lastName,
"hasAcceptedAppAgreement": hasAcceptedAppAgreement
}; };
} }
} }

View File

@ -15,6 +15,11 @@ class UserModel {
final String? timeZone; final String? timeZone;
final String? regionUuid; final String? regionUuid;
final bool? isAgreementAccepted; final bool? isAgreementAccepted;
final bool? hasAcceptedWebAgreement;
final DateTime? webAgreementAcceptedAt;
final bool? hasAcceptedAppAgreement;
final DateTime? appAgreementAcceptedAt;
final Role? role;
UserModel({ UserModel({
required this.uuid, required this.uuid,
@ -28,7 +33,11 @@ class UserModel {
required this.isAgreementAccepted, required this.isAgreementAccepted,
required this.regionName, required this.regionName,
required this.timeZone, 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<String, dynamic> json) { factory UserModel.fromJson(Map<String, dynamic> json) {
@ -44,6 +53,15 @@ class UserModel {
regionName: json['region']?['regionName'], regionName: json['region']?['regionName'],
timeZone: json['timeZone']?['timeZoneOffset'], timeZone: json['timeZone']?['timeZoneOffset'],
regionUuid: json['region']?['uuid'], 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, regionUuid: null,
regionName: tempJson['region']?['regionName'], regionName: tempJson['region']?['regionName'],
timeZone: tempJson['timezone']?['timeZoneOffset'], 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, 'isAgreementAccepted': isAgreementAccepted,
'regionName': regionName, 'regionName': regionName,
'timeZone': timeZone, '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<String, dynamic> 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<String, dynamic> toJson() {
return {
'uuid': uuid,
'createdAt': createdAt?.toIso8601String(),
'updatedAt': updatedAt?.toIso8601String(),
'type': type,
}; };
} }
} }

View File

@ -433,7 +433,9 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
seconds = event.seconds; seconds = event.seconds;
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: acId, code: 'countdown_time', value: event.duration), deviceId: acId,
code: 'countdown_time',
value: event.duration),
acId); acId);
if (response['success'] ?? false) { if (response['success'] ?? false) {

View File

@ -38,8 +38,10 @@ class SettingProfilePage extends StatelessWidget {
final _bloc = BlocProvider.of<DeviceSettingBloc>(context); final _bloc = BlocProvider.of<DeviceSettingBloc>(context);
return state is DeviceSettingLoadingState return state is DeviceSettingLoadingState
? const Center( ? const Center(
child: child: DefaultContainer(
DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()), width: 50,
height: 50,
child: CircularProgressIndicator()),
) )
: RefreshIndicator( : RefreshIndicator(
onRefresh: () async { onRefresh: () async {
@ -55,15 +57,18 @@ class SettingProfilePage extends StatelessWidget {
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.sosHomeIcon, Assets.sosHomeIcon,
fit: BoxFit.fitHeight, fit: BoxFit.fitHeight,
height: MediaQuery.of(context).size.height * 0.13, height:
MediaQuery.of(context).size.height * 0.13,
)) ))
: CircleAvatar( : CircleAvatar(
radius: 55, radius: 55,
backgroundColor: ColorsManager.graysColor, backgroundColor: ColorsManager.graysColor,
child: ClipOval( child: ClipOval(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment:
mainAxisAlignment: MainAxisAlignment.center, CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
children: [ children: [
Center( Center(
child: SvgPicture.asset( child: SvgPicture.asset(
@ -71,7 +76,10 @@ class SettingProfilePage extends StatelessWidget {
? Assets.fourSceneIcon ? Assets.fourSceneIcon
: Assets.sixSceneIcon, : Assets.sixSceneIcon,
fit: BoxFit.contain, 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: [ children: [
IntrinsicWidth( IntrinsicWidth(
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 200), constraints:
const BoxConstraints(maxWidth: 200),
child: TextFormField( child: TextFormField(
maxLength: 30, maxLength: 30,
style: const TextStyle( style: const TextStyle(
@ -122,7 +131,8 @@ class SettingProfilePage extends StatelessWidget {
Assets.sosEditProfile, Assets.sosEditProfile,
color: Colors.grey, color: Colors.grey,
fit: BoxFit.contain, 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), padding: const EdgeInsets.all(20),
child: InkWell( child: InkWell(
onTap: () async { onTap: () async {
bool? val = await Navigator.of(context).push( if (HomeCubit.visitorPasswordManagement) {
MaterialPageRoute( bool? val = await Navigator.of(context).push(
builder: (context) => LocationSettingPage( MaterialPageRoute(
space: spaces!.first, builder: (context) => LocationSettingPage(
deviceId: device?.uuid ?? '', space: spaces!.first,
)), deviceId: device?.uuid ?? '',
); )),
if (val != null && val == true) { );
_bloc.add(const DeviceSettingInitialInfo()); if (val != null && val == true) {
_bloc.add(const DeviceSettingInitialInfo());
}
} }
}, },
child: Row( child: Row(
@ -162,7 +174,8 @@ class SettingProfilePage extends StatelessWidget {
children: [ children: [
SizedBox( SizedBox(
child: BodyMedium( child: BodyMedium(
text: _bloc.deviceInfo.subspace.subspaceName, text: _bloc
.deviceInfo.subspace.subspaceName,
fontColor: ColorsManager.textGray, fontColor: ColorsManager.textGray,
), ),
), ),

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.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/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/smart_linkage_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/temporary_password_page.dart'; import 'package:syncrow_app/features/devices/view/widgets/smart_door/temporary_password_page.dart';
@ -14,6 +15,8 @@ class DoorLockGrid extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final buttons = doorLockButtons(val: uuid);
return GridView.builder( return GridView.builder(
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
@ -23,14 +26,15 @@ class DoorLockGrid extends StatelessWidget {
crossAxisSpacing: 10, crossAxisSpacing: 10,
childAspectRatio: 1.75 / 1, childAspectRatio: 1.75 / 1,
), ),
itemCount: 4, itemCount: buttons.length,
itemBuilder: (context, index) => DefaultContainer( itemBuilder: (context, index) => DefaultContainer(
onTap: () { onTap: () {
//TODO: remove checking after adding the pages //TODO: remove checking after adding the pages
doorLockButtons()[index]['page'] != null doorLockButtons()[index]['page'] != null
? Navigator.of(context).push( ? Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (context) => doorLockButtons(val: uuid)[index]['page'] as Widget, builder: (context) =>
doorLockButtons(val: uuid)[index]['page'] as Widget,
), ),
) )
: null; : null;
@ -75,11 +79,12 @@ List<Map<String, dynamic>> doorLockButtons({val}) => [
'image': Assets.assetsIconsDoorlockAssetsMembersManagement, 'image': Assets.assetsIconsDoorlockAssetsMembersManagement,
'page': const MembersManagementView(), 'page': const MembersManagementView(),
}, },
{ if (HomeCubit.manageDeviceLocation)
'title': 'Temporary Password', {
'image': Assets.assetsIconsDoorlockAssetsTemporaryPassword, 'title': 'Temporary Password',
'page': TemporaryPasswordPage(deviceId: val), 'image': Assets.assetsIconsDoorlockAssetsTemporaryPassword,
}, 'page': TemporaryPasswordPage(deviceId: val),
},
{ {
'title': 'Smart Linkage', 'title': 'Smart Linkage',
'image': Assets.assetsIconsDoorlockAssetsSmartLinkage, 'image': Assets.assetsIconsDoorlockAssetsSmartLinkage,

View File

@ -1,5 +1,15 @@
import 'dart:ui';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/menu/bloc/privacy_policy.dart';
import 'package:syncrow_app/features/menu/bloc/user_agreement.dart';
import 'package:syncrow_app/features/menu/view/widgets/join_home/join_home_view.dart';
import 'package:syncrow_app/features/menu/view/widgets/manage_home/manage_home_view.dart';
import 'package:syncrow_app/features/menu/view/widgets/securty/view/securty_view.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/services/api/profile_api.dart'; import 'package:syncrow_app/services/api/profile_api.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
part 'menu_state.dart'; part 'menu_state.dart';
@ -32,4 +42,143 @@ class MenuCubit extends Cubit<MenuState> {
emit(MenuError(error.toString())); emit(MenuError(error.toString()));
} }
} }
List<Map<String, Object>> menuSections = [
//Home Management
{
'title': 'Home Management',
'color': ColorsManager.primaryColor,
'buttons': [
// {
// 'title': 'Create a Unit',
// 'Icon': Assets.assetsIconsMenuIconsHomeManagementIconsCreateHome,
// 'page': const CreateUnitView()
// },
{
'title': 'Join a Unit',
'Icon': Assets.assetsIconsMenuIconsHomeManagementIconsJoinAHome,
'page': const JoinHomeView()
},
if (HomeCubit.manageSupSpace)
{
'title': 'Manage Your Units',
'Icon':
Assets.assetsIconsMenuIconsHomeManagementIconsManageYourHome,
'page': const ManageHomeView()
},
],
},
//General Settings
// {
// 'title': 'General Settings',
// 'color': const Color(0xFF023DFE),
// 'buttons': [
// {
// 'title': 'Voice Assistant',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsVoiceAssistant,
// 'page': null
// },
// {
// 'title': 'Temperature unit',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsTemperatureUnit,
// 'page': null
// },
// {
// 'title': 'Touch tone on panel',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsTouchTone,
// 'page': null
// },
// {
// 'title': 'Language',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsLanguage,
// 'page': null
// },
// {
// 'title': 'Network Diagnosis',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsNetworkDiagnosis,
// 'page': null
// },
// {
// 'title': 'Clear Cache',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsClearCach,
// 'page': null
// },
// ],
// },
// //Messages Center
// {
// 'title': 'Messages Center',
// 'color': const Color(0xFF0088FF),
// 'buttons': [
// {
// 'title': 'Alerts',
// 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsAlerts,
// 'page': null
// },
// {
// 'title': 'Messages',
// 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsMessages,
// 'page': null
// },
// {
// 'title': 'FAQs',
// 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsFAQs,
// 'page': null
// },
// {
// 'title': 'Help & Feedback',
// 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsHelpAndFeedback,
// 'page': null
// },
// ],
// },
//Security And Privacy
{
'title': 'Security And Privacy',
'color': const Color(0xFF8AB9FF),
'buttons': [
{
'title': 'Security',
'Icon': Assets.assetsIconsMenuIconsSecurityAndPrivacyIconsSecurty,
'page': const SecurtyView()
},
// {
// 'title': 'Privacy',
// 'Icon': Assets.assetsIconsMenuIconsSecurityAndPrivacyIconsPrivacy,
// 'page': const PrivacyView()
// },
],
},
//Legal Information
{
'title': 'Legal Information',
'color': const Color(0xFF001B72),
'buttons': [
{
'title': 'About',
'Icon': Assets.assetsIconsMenuIconsLeagalInfoIconsAbout,
'page': null
},
{
'title': 'Privacy Policy',
'Icon': Assets.assetsIconsMenuIconsLeagalInfoIconsPrivacyPolicy,
'page': const PrivacyPolicy()
},
{
'title': 'User Agreement',
'Icon': Assets.assetsIconsMenuIconsLeagalInfoIconsUserAgreement,
'page': const UserAgreement()
},
],
},
];
Future<void> fetchMenuSections() async {
emit(MenuLoading());
try {
emit(MenuItemsLoaded(menuSections));
} catch (e) {
emit(MenuError(e.toString()));
}
}
} }

View File

@ -11,6 +11,11 @@ class MenuLoaded extends MenuState {
MenuLoaded(this.userAgreementHtml); MenuLoaded(this.userAgreementHtml);
} }
class MenuItemsLoaded extends MenuState {
final List<Map<String, Object>> menuSections;
MenuItemsLoaded(this.menuSections);
}
class MenuError extends MenuState { class MenuError extends MenuState {
final String message; final String message;

View File

@ -1,69 +1,62 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart'; import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
import 'package:syncrow_app/features/menu/bloc/menu_cubit.dart'; import 'package:syncrow_app/features/menu/bloc/menu_cubit.dart';
import 'package:syncrow_app/features/menu/view/widgets/menu_list.dart'; import 'package:syncrow_app/features/menu/view/widgets/menu_list.dart';
import 'package:syncrow_app/features/menu/view/widgets/profile/profile_tab.dart'; import 'package:syncrow_app/features/menu/view/widgets/profile/profile_tab.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class MenuView extends StatelessWidget { class MenuView extends StatelessWidget {
const MenuView({super.key}); const MenuView({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (BuildContext context) => MenuCubit(), create: (BuildContext context) => MenuCubit()..fetchMenuSections(),
child: BlocBuilder<MenuCubit, MenuState>( child: BlocBuilder<MenuCubit, MenuState>(
builder: (context, state) { builder: (context, menuState) {
return BlocBuilder<AuthCubit, AuthState>( if (menuState is MenuLoading) {
builder: (context, state) { return const Center(child: CircularProgressIndicator());
return SingleChildScrollView( } else if (menuState is MenuError) {
physics: const BouncingScrollPhysics(), return Center(child: Text(menuState.message));
child: Column( } else if (menuState is MenuItemsLoaded) {
children: [ final sections = menuState.menuSections;
const ProfileTab(), return SingleChildScrollView(
for (var section in menuSections) physics: const BouncingScrollPhysics(),
MenuList( child: Column(
section: section, children: [
), const ProfileTab(),
const SizedBox( for (var section in sections) MenuList(section: section),
height: 15, const SizedBox(height: 15),
), InkWell(
BodyMedium(text: dotenv.env['ENV_NAME'] ?? ''), onTap: () {
const SizedBox( AuthCubit.get(context).logout();
height: 15, },
), child: Row(
InkWell( children: [
onTap: () { Expanded(
AuthCubit.get(context).logout(); child: DefaultContainer(
}, child: Center(
child: Row( child: BodyLarge(
children: [ text: 'Logout',
Expanded( style: context.bodyLarge.copyWith(
child: DefaultContainer( color: Colors.red,
child: Center(
child: BodyLarge(
text: 'Logout',
style: context.bodyLarge.copyWith(
color: Colors.red,
),
), ),
), ),
), ),
), ),
], ),
), ],
) ),
], ),
), ],
); ),
}, );
); }
// Fallback in case no states match
return const SizedBox.shrink();
}, },
), ),
); );

View File

@ -36,34 +36,38 @@ class SceneItem extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return DefaultContainer( return DefaultContainer(
onTap: () { onTap: () {
context.read<SmartSceneSelectBloc>().add(const SmartSceneClearEvent()); if (HomeCubit.manageScene) {
if (disablePlayButton == false) { context
BlocProvider.of<CreateSceneBloc>(context) .read<SmartSceneSelectBloc>()
.add(FetchSceneTasksEvent(sceneId: scene.id, isAutomation: false)); .add(const SmartSceneClearEvent());
if (disablePlayButton == false) {
BlocProvider.of<CreateSceneBloc>(context).add(
FetchSceneTasksEvent(sceneId: scene.id, isAutomation: false));
/// the state to set the scene type must be after the fetch /// the state to set the scene type must be after the fetch
BlocProvider.of<CreateSceneBloc>(context) BlocProvider.of<CreateSceneBloc>(context)
.add(const SceneTypeEvent(CreateSceneEnum.tabToRun)); .add(const SceneTypeEvent(CreateSceneEnum.tabToRun));
} else { } else {
BlocProvider.of<CreateSceneBloc>(context) BlocProvider.of<CreateSceneBloc>(context).add(
.add(FetchSceneTasksEvent(sceneId: scene.id, isAutomation: true)); FetchSceneTasksEvent(sceneId: scene.id, isAutomation: true));
/// the state to set the scene type must be after the fetch /// the state to set the scene type must be after the fetch
BlocProvider.of<CreateSceneBloc>(context) BlocProvider.of<CreateSceneBloc>(context)
.add(const SceneTypeEvent(CreateSceneEnum.deviceStatusChanges)); .add(const SceneTypeEvent(CreateSceneEnum.deviceStatusChanges));
}
Navigator.pushNamed(
context,
Routes.sceneTasksRoute,
arguments: SceneSettingsRouteArguments(
sceneType: disablePlayButton == false
? CreateSceneEnum.tabToRun.name
: CreateSceneEnum.deviceStatusChanges.name,
sceneId: scene.id,
sceneName: scene.name,
),
);
} }
Navigator.pushNamed(
context,
Routes.sceneTasksRoute,
arguments: SceneSettingsRouteArguments(
sceneType: disablePlayButton == false
? CreateSceneEnum.tabToRun.name
: CreateSceneEnum.deviceStatusChanges.name,
sceneId: scene.id,
sceneName: scene.name,
),
);
}, },
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -79,8 +83,11 @@ class SceneItem extends StatelessWidget {
height: 32, height: 32,
width: 32, width: 32,
fit: BoxFit.fill, fit: BoxFit.fill,
errorBuilder: (context, error, stackTrace) => errorBuilder: (context, error, stackTrace) => Image.asset(
Image.asset(Assets.assetsIconsLogo, height: 32, width: 32, fit: BoxFit.fill), Assets.assetsIconsLogo,
height: 32,
width: 32,
fit: BoxFit.fill),
), ),
if (disablePlayButton || scene.iconInBytes.isEmpty) if (disablePlayButton || scene.iconInBytes.isEmpty)
SvgPicture.asset( SvgPicture.asset(
@ -93,7 +100,9 @@ class SceneItem extends StatelessWidget {
? IconButton( ? IconButton(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
onPressed: () { onPressed: () {
context.read<SceneBloc>().add(SceneTrigger(scene.id, scene.name)); context
.read<SceneBloc>()
.add(SceneTrigger(scene.id, scene.name));
}, },
icon: isLoading icon: isLoading
? const Center( ? const Center(
@ -115,11 +124,15 @@ class SceneItem extends StatelessWidget {
activeColor: ColorsManager.primaryColor, activeColor: ColorsManager.primaryColor,
value: scene.status == 'enable' ? true : false, value: scene.status == 'enable' ? true : false,
onChanged: (value) { onChanged: (value) {
context.read<SceneBloc>().add(UpdateAutomationStatus( context.read<SceneBloc>().add(
automationStatusUpdate: AutomationStatusUpdate( UpdateAutomationStatus(
isEnable: value, automationStatusUpdate:
spaceUuid: HomeCubit.getInstance().selectedSpace!.id), AutomationStatusUpdate(
automationId: scene.id)); isEnable: value,
spaceUuid: HomeCubit.getInstance()
.selectedSpace!
.id),
automationId: scene.id));
}, },
), ),
], ],

View File

@ -16,7 +16,7 @@ class CreateUnitWidget extends StatelessWidget {
TextEditingController textEditingController = TextEditingController(); TextEditingController textEditingController = TextEditingController();
return BlocConsumer<HomeCubit, HomeState>( return BlocConsumer<HomeCubit, HomeState>(
listener: (context, state) { listener: (context, state) {
if (state is ActivationError) {} // if (state is ActivationError) {}
}, },
builder: (context, state) { builder: (context, state) {
return SingleChildScrollView( return SingleChildScrollView(
@ -96,7 +96,11 @@ class CreateUnitWidget extends StatelessWidget {
textEditingController.text)) { textEditingController.text)) {
CustomSnackBar.displaySnackBar( CustomSnackBar.displaySnackBar(
'Done successfully'); 'Done successfully');
Navigator.of(context).pop(); Future.delayed(
const Duration(milliseconds: 500),
() {
Navigator.of(context).pop();
});
} else { } else {
CustomSnackBar.displaySnackBar( CustomSnackBar.displaySnackBar(
'Wrong code!'); 'Wrong code!');
@ -109,14 +113,14 @@ class CreateUnitWidget extends StatelessWidget {
], ],
), ),
), ),
state is ActivationError // state is ActivationError
? Text( // ? Text(
state.errMessage, // state.errMessage,
style: const TextStyle( // style: const TextStyle(
color: ColorsManager.red, // color: ColorsManager.red,
fontWeight: FontWeight.w400), // fontWeight: FontWeight.w400),
) // )
: const SizedBox() // : const SizedBox()
], ],
), ),
], ],
@ -136,42 +140,42 @@ class CreateUnitWidget extends StatelessWidget {
} }
} }
// return SizedBox( // return SizedBox(
// width: MediaQuery.sizeOf(context).width, // width: MediaQuery.sizeOf(context).width,
// height: MediaQuery.sizeOf(context).height, // height: MediaQuery.sizeOf(context).height,
// child: Column( // child: Column(
// mainAxisAlignment: MainAxisAlignment.center, // mainAxisAlignment: MainAxisAlignment.center,
// children: [ // children: [
// SvgPicture.asset( // SvgPicture.asset(
// Assets.noUnitsIconDashboard, // Assets.noUnitsIconDashboard,
// width: 100, // width: 100,
// height: 100, // height: 100,
// ), // ),
// const SizedBox( // const SizedBox(
// height: 50, // height: 50,
// ), // ),
// Flexible( // Flexible(
// child: GestureDetector( // child: GestureDetector(
// onTap: () { // onTap: () {
// Navigator.pushNamed(context, Routes.createUnit); // Navigator.pushNamed(context, Routes.createUnit);
// }, // },
// child: Container( // child: Container(
// padding: const EdgeInsets.symmetric(horizontal: 34, vertical: 14), // padding: const EdgeInsets.symmetric(horizontal: 34, vertical: 14),
// decoration: ShapeDecoration( // decoration: ShapeDecoration(
// color: const Color(0x99023DFE), // color: const Color(0x99023DFE),
// shape: RoundedRectangleBorder( // shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(20), // borderRadius: BorderRadius.circular(20),
// ), // ),
// ), // ),
// child: const TitleMedium( // child: const TitleMedium(
// text: 'Create a unit', // text: 'Create a unit',
// style: TextStyle(fontSize: 16, fontWeight: FontWeight.w400, color: Colors.white), // style: TextStyle(fontSize: 16, fontWeight: FontWeight.w400, color: Colors.white),
// ), // ),
// ), // ),
// ), // ),
// ), // ),
// ], // ],
// ), // ),
// ); // );
// } // }
// } // }

View File

@ -225,4 +225,7 @@ abstract class ApiEndpoints {
static const String getDeviceLogs = '/device/report-logs/{uuid}?code={code}'; static const String getDeviceLogs = '/device/report-logs/{uuid}?code={code}';
static const String terms = '/terms'; static const String terms = '/terms';
static const String policy = '/policy'; static const String policy = '/policy';
static const String getPermission = '/permission/{roleUuid}';
///permission/roleUuid
} }

View File

@ -88,7 +88,8 @@ class DevicesAPI {
static Future<Map<String, dynamic>> getDeviceStatus(String deviceId) async { static Future<Map<String, dynamic>> getDeviceStatus(String deviceId) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.deviceFunctionsStatus.replaceAll('{deviceUuid}', deviceId), path: ApiEndpoints.deviceFunctionsStatus
.replaceAll('{deviceUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@ -97,7 +98,8 @@ class DevicesAPI {
return response; return response;
} }
static Future<Map<String, dynamic>> getPowerClampStatus(String deviceId) async { static Future<Map<String, dynamic>> getPowerClampStatus(
String deviceId) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.powerClamp.replaceAll('{powerClampUuid}', deviceId), path: ApiEndpoints.powerClamp.replaceAll('{powerClampUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
@ -109,7 +111,9 @@ class DevicesAPI {
} }
static Future<Map<String, dynamic>> renamePass( static Future<Map<String, dynamic>> renamePass(
{required String name, required String doorLockUuid, required String passwordId}) async { {required String name,
required String doorLockUuid,
required String passwordId}) async {
final response = await _httpService.put( final response = await _httpService.put(
path: ApiEndpoints.renamePassword path: ApiEndpoints.renamePassword
.replaceAll('{doorLockUuid}', doorLockUuid) .replaceAll('{doorLockUuid}', doorLockUuid)
@ -144,7 +148,8 @@ class DevicesAPI {
return response; return response;
} }
static Future getSceneBySwitchName({String? deviceId, String? switchName}) async { static Future getSceneBySwitchName(
{String? deviceId, String? switchName}) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.fourSceneByName path: ApiEndpoints.fourSceneByName
.replaceAll('{deviceUuid}', deviceId!) .replaceAll('{deviceUuid}', deviceId!)
@ -165,7 +170,11 @@ class DevicesAPI {
final response = await _httpService.post( final response = await _httpService.post(
path: ApiEndpoints.deviceScene.replaceAll('{deviceUuid}', deviceId!), path: ApiEndpoints.deviceScene.replaceAll('{deviceUuid}', deviceId!),
body: jsonEncode( body: jsonEncode(
{"switchName": switchName, "sceneUuid": sceneUuid, "spaceUuid": spaceUuid}, {
"switchName": switchName,
"sceneUuid": sceneUuid,
"spaceUuid": spaceUuid
},
), ),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
@ -185,7 +194,8 @@ class DevicesAPI {
return response; return response;
} }
static Future<List<DeviceModel>> getDeviceByGroupName(String unitId, String groupName) async { static Future<List<DeviceModel>> getDeviceByGroupName(
String unitId, String groupName) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.devicesByGroupName path: ApiEndpoints.devicesByGroupName
.replaceAll('{unitUuid}', unitId) .replaceAll('{unitUuid}', unitId)
@ -230,7 +240,9 @@ class DevicesAPI {
if (json == null || json.isEmpty || json == []) { if (json == null || json.isEmpty || json == []) {
return <DeviceModel>[]; return <DeviceModel>[];
} }
return data.map<DeviceModel>((device) => DeviceModel.fromJson(device)).toList(); return data
.map<DeviceModel>((device) => DeviceModel.fromJson(device))
.toList();
}, },
); );
@ -242,7 +254,8 @@ class DevicesAPI {
} }
} }
static Future<List<DeviceModel>> getDevicesByGatewayId(String gatewayId) async { static Future<List<DeviceModel>> getDevicesByGatewayId(
String gatewayId) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.gatewayApi.replaceAll('{gatewayUuid}', gatewayId), path: ApiEndpoints.gatewayApi.replaceAll('{gatewayUuid}', gatewayId),
showServerMessage: false, showServerMessage: false,
@ -264,7 +277,8 @@ class DevicesAPI {
String deviceId, String deviceId,
) async { ) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.getTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), path: ApiEndpoints.getTemporaryPassword
.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@ -275,7 +289,8 @@ class DevicesAPI {
static Future getOneTimePasswords(String deviceId) async { static Future getOneTimePasswords(String deviceId) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.getOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), path: ApiEndpoints.getOneTimeTemporaryPassword
.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@ -286,7 +301,8 @@ class DevicesAPI {
static Future getTimeLimitPasswords(String deviceId) async { static Future getTimeLimitPasswords(String deviceId) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.getMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), path: ApiEndpoints.getMultipleTimeTemporaryPassword
.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@ -311,10 +327,12 @@ class DevicesAPI {
"invalidTime": invalidTime, "invalidTime": invalidTime,
}; };
if (scheduleList != null) { if (scheduleList != null) {
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList(); body["scheduleList"] =
scheduleList.map((schedule) => schedule.toJson()).toList();
} }
final response = await _httpService.post( final response = await _httpService.post(
path: ApiEndpoints.addTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), path: ApiEndpoints.addTemporaryPassword
.replaceAll('{doorLockUuid}', deviceId),
body: body, body: body,
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) => json, expectedResponseModel: (json) => json,
@ -325,7 +343,8 @@ class DevicesAPI {
static Future generateOneTimePassword({deviceId}) async { static Future generateOneTimePassword({deviceId}) async {
try { try {
final response = await _httpService.post( final response = await _httpService.post(
path: ApiEndpoints.addOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), path: ApiEndpoints.addOneTimeTemporaryPassword
.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@ -337,10 +356,12 @@ class DevicesAPI {
} }
} }
static Future generateMultiTimePassword({deviceId, effectiveTime, invalidTime}) async { static Future generateMultiTimePassword(
{deviceId, effectiveTime, invalidTime}) async {
try { try {
final response = await _httpService.post( final response = await _httpService.post(
path: ApiEndpoints.addMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), path: ApiEndpoints.addMultipleTimeTemporaryPassword
.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: true, showServerMessage: true,
body: {"effectiveTime": effectiveTime, "invalidTime": invalidTime}, body: {"effectiveTime": effectiveTime, "invalidTime": invalidTime},
expectedResponseModel: (json) { expectedResponseModel: (json) {
@ -530,7 +551,9 @@ class DevicesAPI {
String code, String code,
) async { ) async {
final response = await HTTPService().get( final response = await HTTPService().get(
path: ApiEndpoints.getDeviceLogs.replaceAll('{uuid}', uuid).replaceAll('{code}', code), path: ApiEndpoints.getDeviceLogs
.replaceAll('{uuid}', uuid)
.replaceAll('{code}', code),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return DeviceReport.fromJson(json); return DeviceReport.fromJson(json);

View File

@ -1,5 +1,4 @@
import 'dart:async'; import 'dart:async';
import 'dart:developer';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/auth/model/user_model.dart'; import 'package:syncrow_app/features/auth/model/user_model.dart';
import 'package:syncrow_app/features/menu/model/region_model.dart'; import 'package:syncrow_app/features/menu/model/region_model.dart';
@ -95,6 +94,16 @@ class ProfileApi {
return response; return response;
} }
Future fetchPermissions(roleId) async {
final response = await _httpService.get(
path: ApiEndpoints.getPermission.replaceAll('{roleUuid}', roleId!),
showServerMessage: true,
expectedResponseModel: (json) {
return json;
});
return response;
}
static Future<List<RegionModel>> fetchRegion() async { static Future<List<RegionModel>> fetchRegion() async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.getRegion, path: ApiEndpoints.getRegion,
@ -117,7 +126,7 @@ class ProfileApi {
return response as List<TimeZone>; return response as List<TimeZone>;
} }
Future fetchUserAgreement() async { Future fetchUserAgreement() async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.terms, path: ApiEndpoints.terms,
showServerMessage: true, showServerMessage: true,
@ -127,7 +136,7 @@ class ProfileApi {
return response; return response;
} }
Future fetchPrivacyPolicy() async { Future fetchPrivacyPolicy() async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.policy, path: ApiEndpoints.policy,
showServerMessage: true, showServerMessage: true,

View File

@ -1,5 +1,6 @@
//ignore_for_file: constant_identifier_names //ignore_for_file: constant_identifier_names
import 'dart:ui'; import 'dart:ui';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/model/function_model.dart'; import 'package:syncrow_app/features/devices/model/function_model.dart';
import 'package:syncrow_app/features/menu/bloc/privacy_policy.dart'; import 'package:syncrow_app/features/menu/bloc/privacy_policy.dart';
import 'package:syncrow_app/features/menu/bloc/user_agreement.dart'; import 'package:syncrow_app/features/menu/bloc/user_agreement.dart';
@ -677,134 +678,6 @@ K? getNextItem<K, V>(Map<K, V> map, V value) {
return null; return null;
} }
List<Map<String, Object>> menuSections = [
//Home Management
{
'title': 'Home Management',
'color': ColorsManager.primaryColor,
'buttons': [
// {
// 'title': 'Create a Unit',
// 'Icon': Assets.assetsIconsMenuIconsHomeManagementIconsCreateHome,
// 'page': const CreateUnitView()
// },
{
'title': 'Join a Unit',
'Icon': Assets.assetsIconsMenuIconsHomeManagementIconsJoinAHome,
'page': const JoinHomeView()
},
{
'title': 'Manage Your Units',
'Icon': Assets.assetsIconsMenuIconsHomeManagementIconsManageYourHome,
'page': const ManageHomeView()
},
],
},
//General Settings
// {
// 'title': 'General Settings',
// 'color': const Color(0xFF023DFE),
// 'buttons': [
// {
// 'title': 'Voice Assistant',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsVoiceAssistant,
// 'page': null
// },
// {
// 'title': 'Temperature unit',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsTemperatureUnit,
// 'page': null
// },
// {
// 'title': 'Touch tone on panel',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsTouchTone,
// 'page': null
// },
// {
// 'title': 'Language',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsLanguage,
// 'page': null
// },
// {
// 'title': 'Network Diagnosis',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsNetworkDiagnosis,
// 'page': null
// },
// {
// 'title': 'Clear Cache',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsClearCach,
// 'page': null
// },
// ],
// },
// //Messages Center
// {
// 'title': 'Messages Center',
// 'color': const Color(0xFF0088FF),
// 'buttons': [
// {
// 'title': 'Alerts',
// 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsAlerts,
// 'page': null
// },
// {
// 'title': 'Messages',
// 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsMessages,
// 'page': null
// },
// {
// 'title': 'FAQs',
// 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsFAQs,
// 'page': null
// },
// {
// 'title': 'Help & Feedback',
// 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsHelpAndFeedback,
// 'page': null
// },
// ],
// },
//Security And Privacy
{
'title': 'Security And Privacy',
'color': const Color(0xFF8AB9FF),
'buttons': [
{
'title': 'Security',
'Icon': Assets.assetsIconsMenuIconsSecurityAndPrivacyIconsSecurty,
'page': const SecurtyView()
},
// {
// 'title': 'Privacy',
// 'Icon': Assets.assetsIconsMenuIconsSecurityAndPrivacyIconsPrivacy,
// 'page': const PrivacyView()
// },
],
},
//Legal Information
{
'title': 'Legal Information',
'color': const Color(0xFF001B72),
'buttons': [
{
'title': 'About',
'Icon': Assets.assetsIconsMenuIconsLeagalInfoIconsAbout,
'page': null
},
{
'title': 'Privacy Policy',
'Icon': Assets.assetsIconsMenuIconsLeagalInfoIconsPrivacyPolicy,
'page': const PrivacyPolicy()
},
{
'title': 'User Agreement',
'Icon': Assets.assetsIconsMenuIconsLeagalInfoIconsUserAgreement,
'page': const UserAgreement()
},
],
},
];
enum MemberRole { enum MemberRole {
FamilyMember, FamilyMember,
OtherMember, OtherMember,