Implemented smart door animation

This commit is contained in:
Abdullah Alassaf
2024-08-26 16:45:50 +03:00
parent 611c515173
commit dcc98445d7
6 changed files with 147 additions and 159 deletions

View File

@ -6,7 +6,6 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_event.dart'; import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_event.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_state.dart'; import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_state.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/offline_password_model.dart'; import 'package:syncrow_app/features/devices/model/offline_password_model.dart';
import 'package:syncrow_app/features/devices/model/offline_temporary_password.dart'; import 'package:syncrow_app/features/devices/model/offline_temporary_password.dart';
import 'package:syncrow_app/features/devices/model/smart_door_model.dart'; import 'package:syncrow_app/features/devices/model/smart_door_model.dart';
@ -216,11 +215,13 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
void _updateLock(UpdateLockEvent event, Emitter<SmartDoorState> emit) async { void _updateLock(UpdateLockEvent event, Emitter<SmartDoorState> emit) async {
emit(LoadingNewSate(smartDoorModel: deviceStatus)); emit(LoadingNewSate(smartDoorModel: deviceStatus));
try { try {
final response = await DevicesAPI.controlDevice( // final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: deviceId, code: 'normal_open_switch', value: !event.value), // DeviceControlModel(deviceId: deviceId, code: 'normal_open_switch', value: !event.value),
deviceId); // deviceId);
if (response['success'] ?? false) { final response = await DevicesAPI.openDoorLock(deviceId);
if (response) {
deviceStatus.normalOpenSwitch = !event.value; deviceStatus.normalOpenSwitch = !event.value;
} }
} catch (_) {} } catch (_) {}
@ -353,7 +354,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
try { try {
isSavingPassword = true; isSavingPassword = true;
emit(LoadingSaveState()); emit(LoadingSaveState());
var res = await DevicesAPI.createPassword( await DevicesAPI.createPassword(
deviceId: deviceId, deviceId: deviceId,
effectiveTime: effectiveTimeTimeStamp.toString(), effectiveTime: effectiveTimeTimeStamp.toString(),
invalidTime: expirationTimeTimeStamp.toString(), invalidTime: expirationTimeTimeStamp.toString(),
@ -407,7 +408,6 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
Future<void> deletePassword(DeletePasswordEvent event, Emitter<SmartDoorState> emit) async { Future<void> deletePassword(DeletePasswordEvent event, Emitter<SmartDoorState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
var response =
await DevicesAPI.deletePassword(deviceId: deviceId, passwordId: event.passwordId) await DevicesAPI.deletePassword(deviceId: deviceId, passwordId: event.passwordId)
.then((value) async { .then((value) async {
add(InitialPasswordsPage()); add(InitialPasswordsPage());
@ -442,7 +442,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
return true; return true;
} }
if (repeat == true && (endTime == null || startTime == null || selectedDays == null)) { if (repeat == true && (endTime == null || startTime == null)) {
CustomSnackBar.displaySnackBar('Start Time and End time and the days required '); CustomSnackBar.displaySnackBar('Start Time and End time and the days required ');
return true; return true;
} }

View File

@ -1,14 +1,10 @@
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_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
// import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_event.dart';
// import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_bloc.dart'; import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_event.dart'; import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_event.dart';
// import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/smart_door_model.dart'; import 'package:syncrow_app/features/devices/model/smart_door_model.dart';
// import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_status_bar.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
@ -37,11 +33,16 @@ class _DoorLockButtonState extends State<DoorLockButton> with SingleTickerProvid
super.initState(); super.initState();
_animationController = AnimationController( _animationController = AnimationController(
vsync: this, vsync: this,
duration: const Duration(seconds: 2), value: smartDoorModel.unlockRequest > 0 ? 1 : 0,
duration: Duration(seconds: smartDoorModel.unlockRequest),
); );
_animation = Tween<double>(begin: 0, end: 1.0).animate(_animationController) if (smartDoorModel.unlockRequest > 0) {
_animationController.reverse();
}
_animation = Tween<double>(begin: 0, end: 1).animate(_animationController)
..addListener(() { ..addListener(() {
if (_animation.status == AnimationStatus.completed) { // if (_animation.status == AnimationStatus.completed) {
// if (widget.doorLock.status // if (widget.doorLock.status
// .firstWhere((element) => element.code == 'normal_open_switch') // .firstWhere((element) => element.code == 'normal_open_switch')
// .value != // .value !=
@ -51,20 +52,22 @@ class _DoorLockButtonState extends State<DoorLockButton> with SingleTickerProvid
// deviceId: widget.doorLock.uuid, code: 'normal_open_switch', value: true), // deviceId: widget.doorLock.uuid, code: 'normal_open_switch', value: true),
// widget.doorLock.uuid ?? ""); // widget.doorLock.uuid ?? "");
// } // }
BlocProvider.of<SmartDoorBloc>(context) // BlocProvider.of<SmartDoorBloc>(context)
.add(UpdateLockEvent(value: smartDoorModel.normalOpenSwitch)); // .add(UpdateLockEvent(value: smartDoorModel.normalOpenSwitch));
_animationController.reverse(); // _animationController.reverse();
} else if (_animation.status == AnimationStatus.dismissed) { // }
// if (widget.doorLock.status // } else if (_animation.status == AnimationStatus.dismissed) {
// .firstWhere((element) => element.code == 'normal_open_switch') // // if (widget.doorLock.status
// .value != // // .firstWhere((element) => element.code == 'normal_open_switch')
// false) { // // .value !=
// // false) {
// DevicesCubit.getInstance().deviceControl( // DevicesCubit.getInstance().deviceControl(
// DeviceControlModel( // DeviceControlModel(
// deviceId: widget.doorLock.uuid, code: 'normal_open_switch', value: false), // deviceId: widget.doorLock.uuid, code: 'normal_open_switch', value: false),
// widget.doorLock.uuid ?? ""); // widget.doorLock.uuid ?? "");
// // }
// _animationController.forward();
// } // }
}
setState(() {}); setState(() {});
}); });
} }
@ -88,14 +91,18 @@ class _DoorLockButtonState extends State<DoorLockButton> with SingleTickerProvid
WidgetStateProperty.all(ColorsManager.primaryColorWithOpacity.withOpacity(0.1)), WidgetStateProperty.all(ColorsManager.primaryColorWithOpacity.withOpacity(0.1)),
borderRadius: BorderRadius.circular(999), borderRadius: BorderRadius.circular(999),
onTapDown: (details) { onTapDown: (details) {
if (_animationController.status == AnimationStatus.dismissed) { // if (_animationController.status == AnimationStatus.dismissed) {
_animationController.forward(); // _animationController.forward();
} else if (_animationController.status == AnimationStatus.completed) { // } else if (_animationController.status == AnimationStatus.completed) {
_animationController.reverse(); // _animationController.reverse();
} else if (_animationController.status == AnimationStatus.forward) { // } else if (_animationController.status == AnimationStatus.forward) {
_animationController.reverse(); // _animationController.reverse();
} else if (_animationController.status == AnimationStatus.reverse) { // } else if (_animationController.status == AnimationStatus.reverse) {
_animationController.forward(); // _animationController.forward();
// }
if (smartDoorModel.unlockRequest > 0) {
BlocProvider.of<SmartDoorBloc>(context)
.add(UpdateLockEvent(value: smartDoorModel.normalOpenSwitch));
} }
}, },
onTapUp: (details) { onTapUp: (details) {

View File

@ -7,27 +7,22 @@ import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_sta
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/smart_door_model.dart'; import 'package:syncrow_app/features/devices/model/smart_door_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart'; import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart';
import 'package:syncrow_app/features/devices/view/widgets/popup_menu_widget.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_button.dart'; import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_button.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_grid.dart'; import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_grid.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_status_bar.dart'; import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_status_bar.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class DoorInterface extends StatelessWidget { class DoorInterface extends StatelessWidget {
const DoorInterface({super.key, required this.doorLock});
DoorInterface({super.key, required this.doorLock});
final DeviceModel doorLock; final DeviceModel doorLock;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => SmartDoorBloc(deviceId: doorLock.uuid ?? '')..add(InitialEvent()), create: (context) => SmartDoorBloc(deviceId: doorLock.uuid ?? '')..add(InitialEvent()),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>( child: BlocConsumer<SmartDoorBloc, SmartDoorState>(listener: (context, state) {
listener: (context, state) {
if (state is FailedState) { if (state is FailedState) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
@ -98,14 +93,11 @@ class DoorInterface extends StatelessWidget {
? const Center( ? const Center(
child: RefreshProgressIndicator(), child: RefreshProgressIndicator(),
) )
: : RefreshIndicator(
RefreshIndicator(
onRefresh: () async { onRefresh: () async {
BlocProvider.of<SmartDoorBloc>(context).add(InitialEvent()); BlocProvider.of<SmartDoorBloc>(context).add(InitialEvent());
}, },
child: child: ListView(
ListView(
children: [ children: [
DoorLockStatusBar( DoorLockStatusBar(
smartDoorModel: smartDoorModel, smartDoorModel: smartDoorModel,
@ -118,8 +110,9 @@ class DoorInterface extends StatelessWidget {
doorLock: doorLock, doorLock: doorLock,
smartDoorModel: smartDoorModel, smartDoorModel: smartDoorModel,
), ),
DoorLockGrid( uuid: doorLock.uuid!, ), DoorLockGrid(
uuid: doorLock.uuid!,
),
], ],
) )
], ],
@ -132,4 +125,3 @@ class DoorInterface extends StatelessWidget {
); );
} }
} }

View File

@ -18,7 +18,7 @@ class ManageHomeView extends StatelessWidget {
title: 'Manage Your Home', title: 'Manage Your Home',
child: spaces == null child: spaces == null
? const Center( ? const Center(
child: CircularProgressIndicator(), child: BodyMedium(text: 'No spaces found'),
) )
: Column( : Column(
children: [ children: [
@ -30,8 +30,7 @@ class ManageHomeView extends StatelessWidget {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: children: List.generate(
List.generate(
spaces.length, spaces.length,
(index) { (index) {
if (index == spaces.length - 1) { if (index == spaces.length - 1) {
@ -43,12 +42,10 @@ class ManageHomeView extends StatelessWidget {
))); )));
}, },
child: Row( child: Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
children: [ children: [
BodyMedium( BodyMedium(
text: StringHelpers.toTitleCase( text: StringHelpers.toTitleCase(spaces[index].name ?? "")),
spaces[index].name ?? "")),
const Icon( const Icon(
Icons.arrow_forward_ios, Icons.arrow_forward_ios,
color: ColorsManager.greyColor, color: ColorsManager.greyColor,
@ -76,14 +73,10 @@ class ManageHomeView extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Row( Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
children: [ children: [
BodyMedium( BodyMedium(
text: HomeCubit.getInstance() text: HomeCubit.getInstance().spaces![index].name ?? ""),
.spaces![index]
.name ??
""),
const Icon( const Icon(
Icons.arrow_forward_ios, Icons.arrow_forward_ios,
color: ColorsManager.greyColor, color: ColorsManager.greyColor,
@ -92,8 +85,7 @@ class ManageHomeView extends StatelessWidget {
], ],
), ),
Container( Container(
margin: margin: const EdgeInsets.symmetric(vertical: 15),
const EdgeInsets.symmetric(vertical: 15),
height: 1, height: 1,
color: ColorsManager.greyColor, color: ColorsManager.greyColor,
), ),

View File

@ -81,8 +81,7 @@ abstract class ApiEndpoints {
static const String controlGroup = '/group/control'; static const String controlGroup = '/group/control';
//GET //GET
static const String groupBySpace = '/group/{unitUuid}'; static const String groupBySpace = '/group/{unitUuid}';
static const String devicesByGroupName = static const String devicesByGroupName = '/group/{unitUuid}/devices/{groupName}';
'/group/{unitUuid}/devices/{groupName}';
static const String groupByUuid = '/group/{groupUuid}'; static const String groupByUuid = '/group/{groupUuid}';
//DELETE //DELETE
@ -94,18 +93,17 @@ abstract class ApiEndpoints {
static const String addDeviceToRoom = '/device/room'; static const String addDeviceToRoom = '/device/room';
static const String addDeviceToGroup = '/device/group'; static const String addDeviceToGroup = '/device/group';
static const String controlDevice = '/device/{deviceUuid}/control'; static const String controlDevice = '/device/{deviceUuid}/control';
static const String firmwareDevice = static const String firmwareDevice = '/device/{deviceUuid}/firmware/{firmwareVersion}';
'/device/{deviceUuid}/firmware/{firmwareVersion}';
static const String getDevicesByUserId = '/device/user/{userId}'; static const String getDevicesByUserId = '/device/user/{userId}';
static const String getDevicesByUnitId = '/device/unit/{unitUuid}'; static const String getDevicesByUnitId = '/device/unit/{unitUuid}';
static const String openDoorLock = '/door-lock/open/{doorLockUuid}';
//GET //GET
static const String deviceByRoom = '/device/room'; static const String deviceByRoom = '/device/room';
static const String deviceByUuid = '/device/{deviceUuid}'; static const String deviceByUuid = '/device/{deviceUuid}';
static const String deviceFunctions = '/device/{deviceUuid}/functions'; static const String deviceFunctions = '/device/{deviceUuid}/functions';
static const String gatewayApi = '/device/gateway/{gatewayUuid}/devices'; static const String gatewayApi = '/device/gateway/{gatewayUuid}/devices';
static const String deviceFunctionsStatus = static const String deviceFunctionsStatus = '/device/{deviceUuid}/functions/status';
'/device/{deviceUuid}/functions/status';
///Device Permission Module ///Device Permission Module
//POST //POST
@ -130,29 +128,24 @@ abstract class ApiEndpoints {
static const String getUnitAutomation = '/automation/{unitUuid}'; static const String getUnitAutomation = '/automation/{unitUuid}';
static const String getAutomationDetails = static const String getAutomationDetails = '/automation/details/{automationId}';
'/automation/details/{automationId}';
/// PUT /// PUT
static const String updateScene = '/scene/tap-to-run/{sceneId}'; static const String updateScene = '/scene/tap-to-run/{sceneId}';
static const String updateAutomation = '/automation/{automationId}'; static const String updateAutomation = '/automation/{automationId}';
static const String updateAutomationStatus = static const String updateAutomationStatus = '/automation/status/{automationId}';
'/automation/status/{automationId}';
/// DELETE /// DELETE
static const String deleteScene = '/scene/tap-to-run/{unitUuid}/{sceneId}'; static const String deleteScene = '/scene/tap-to-run/{unitUuid}/{sceneId}';
static const String deleteAutomation = static const String deleteAutomation = '/automation/{unitUuid}/{automationId}';
'/automation/{unitUuid}/{automationId}';
//////////////////////Door Lock ////////////////////// //////////////////////Door Lock //////////////////////
//online //online
static const String addTemporaryPassword = static const String addTemporaryPassword = '/door-lock/temporary-password/online/{doorLockUuid}';
'/door-lock/temporary-password/online/{doorLockUuid}'; static const String getTemporaryPassword = '/door-lock/temporary-password/online/{doorLockUuid}';
static const String getTemporaryPassword =
'/door-lock/temporary-password/online/{doorLockUuid}';
//one-time offline //one-time offline
static const String addOneTimeTemporaryPassword = static const String addOneTimeTemporaryPassword =
@ -160,8 +153,6 @@ abstract class ApiEndpoints {
static const String getOneTimeTemporaryPassword = static const String getOneTimeTemporaryPassword =
'/door-lock/temporary-password/offline/one-time/{doorLockUuid}'; '/door-lock/temporary-password/offline/one-time/{doorLockUuid}';
//user //user
static const String getUser = '/user/{userUuid}'; static const String getUser = '/user/{userUuid}';

View File

@ -46,6 +46,17 @@ class DevicesAPI {
} }
} }
static Future<bool> openDoorLock(String deviceId) async {
final response = await _httpService.post(
path: ApiEndpoints.openDoorLock.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false,
expectedResponseModel: (json) {
return json['success'] ?? false;
},
);
return response;
}
static Future<List<DevicesCategoryModel>> fetchGroups(String spaceId) async { static Future<List<DevicesCategoryModel>> fetchGroups(String spaceId) async {
// Map<String, dynamic> params = {"homeId": spaceId, "pageSize": 100, "pageNo": 1}; // Map<String, dynamic> params = {"homeId": spaceId, "pageSize": 100, "pageNo": 1};
@ -69,17 +80,13 @@ class DevicesAPI {
return response; return response;
} }
static Future<Map<String, dynamic>> renamePass({ static Future<Map<String, dynamic>> renamePass(
required String name, {required String name, required String doorLockUuid, required String passwordId}) async {
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)
.replaceAll('{passwordId}', passwordId), .replaceAll('{passwordId}', passwordId),
body: { body: {"name": name},
"name": name
},
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
}, },
@ -156,7 +163,9 @@ class DevicesAPI {
return response; return response;
} }
static Future getTemporaryPasswords(String deviceId, ) async { static Future getTemporaryPasswords(
String deviceId,
) 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,
@ -196,7 +205,8 @@ class DevicesAPI {
required String effectiveTime, required String effectiveTime,
required String invalidTime, required String invalidTime,
required String deviceId, required String deviceId,
List<Schedule>? scheduleList,}) async { List<Schedule>? scheduleList,
}) async {
Map<String, dynamic> body = { Map<String, dynamic> body = {
"name": name, "name": name,
"password": password, "password": password,
@ -236,10 +246,7 @@ class DevicesAPI {
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: { body: {"effectiveTime": effectiveTime, "invalidTime": invalidTime},
"effectiveTime": effectiveTime,
"invalidTime": invalidTime
},
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
}, },
@ -263,5 +270,4 @@ class DevicesAPI {
); );
return response; return response;
} }
} }