mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 15:17:31 +00:00
fix it and add lock to open when press (as loved simple animation)
with adding the timer as circle
This commit is contained in:
@ -1,5 +1,3 @@
|
|||||||
// ignore_for_file: invalid_use_of_visible_for_testing_member
|
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:firebase_database/firebase_database.dart';
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
@ -16,45 +14,38 @@ class DoorLockBloc extends Bloc<DoorLockEvent, DoorLockState> {
|
|||||||
|
|
||||||
DoorLockBloc({required this.deviceId}) : super(DoorLockInitial()) {
|
DoorLockBloc({required this.deviceId}) : super(DoorLockInitial()) {
|
||||||
on<DoorLockFetchStatus>(_onFetchDeviceStatus);
|
on<DoorLockFetchStatus>(_onFetchDeviceStatus);
|
||||||
//on<DoorLockControl>(_onDoorLockControl);
|
|
||||||
on<UpdateLockEvent>(_updateLock);
|
on<UpdateLockEvent>(_updateLock);
|
||||||
on<DoorLockFactoryReset>(_onFactoryReset);
|
on<DoorLockFactoryReset>(_onFactoryReset);
|
||||||
on<StatusUpdated>(_onStatusUpdated);
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
_listenToChanges(deviceId) {
|
void _listenToChanges(String deviceId) {
|
||||||
try {
|
try {
|
||||||
DatabaseReference ref =
|
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
ref.onValue.listen((event) {
|
||||||
Stream<DatabaseEvent> stream = ref.onValue;
|
final data = event.snapshot.value;
|
||||||
|
if (data is Map) {
|
||||||
|
final statusData = data['status'] as List<dynamic>? ?? [];
|
||||||
|
final statusList = statusData.map((item) {
|
||||||
|
return Status(code: item['code'], value: item['value']);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
stream.listen((DatabaseEvent event) {
|
final model =
|
||||||
Map<dynamic, dynamic> usersMap =
|
DoorLockStatusModel.fromJson(data['productUuid'], statusList);
|
||||||
event.snapshot.value as Map<dynamic, dynamic>;
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(model));
|
||||||
List<Status> statusList = [];
|
}
|
||||||
usersMap['status'].forEach((element) {
|
|
||||||
statusList
|
|
||||||
.add(Status(code: element['code'], value: element['value']));
|
|
||||||
});
|
|
||||||
|
|
||||||
deviceStatus =
|
|
||||||
DoorLockStatusModel.fromJson(usersMap['productUuid'], statusList);
|
|
||||||
if (!isClosed) {
|
|
||||||
add(StatusUpdated(deviceStatus));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onStatusUpdated(StatusUpdated event, Emitter<DoorLockState> emit) {
|
void _onStatusUpdated(StatusUpdated event, Emitter<DoorLockState> emit) {
|
||||||
emit(DoorLockStatusLoading());
|
|
||||||
|
|
||||||
deviceStatus = event.deviceStatus;
|
deviceStatus = event.deviceStatus;
|
||||||
emit(DoorLockStatusLoaded(deviceStatus));
|
emit(DoorLockStatusLoaded(deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onFetchDeviceStatus(
|
Future<void> _onFetchDeviceStatus(
|
||||||
DoorLockFetchStatus event, Emitter<DoorLockState> emit) async {
|
DoorLockFetchStatus event, Emitter<DoorLockState> emit) async {
|
||||||
emit(DoorLockStatusLoading());
|
emit(DoorLockStatusLoading());
|
||||||
try {
|
try {
|
||||||
@ -63,14 +54,13 @@ class DoorLockBloc extends Bloc<DoorLockEvent, DoorLockState> {
|
|||||||
deviceStatus =
|
deviceStatus =
|
||||||
DoorLockStatusModel.fromJson(event.deviceId, status.status);
|
DoorLockStatusModel.fromJson(event.deviceId, status.status);
|
||||||
_listenToChanges(event.deviceId);
|
_listenToChanges(event.deviceId);
|
||||||
|
|
||||||
emit(DoorLockStatusLoaded(deviceStatus));
|
emit(DoorLockStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(DoorLockControlError(e.toString()));
|
emit(DoorLockControlError(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _updateLock(
|
Future<void> _updateLock(
|
||||||
UpdateLockEvent event, Emitter<DoorLockState> emit) async {
|
UpdateLockEvent event, Emitter<DoorLockState> emit) async {
|
||||||
final oldValue = deviceStatus.normalOpenSwitch;
|
final oldValue = deviceStatus.normalOpenSwitch;
|
||||||
deviceStatus = deviceStatus.copyWith(normalOpenSwitch: !oldValue);
|
deviceStatus = deviceStatus.copyWith(normalOpenSwitch: !oldValue);
|
||||||
@ -78,7 +68,6 @@ class DoorLockBloc extends Bloc<DoorLockEvent, DoorLockState> {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await DevicesManagementApi.openDoorLock(deviceId);
|
final response = await DevicesManagementApi.openDoorLock(deviceId);
|
||||||
|
|
||||||
if (!response) {
|
if (!response) {
|
||||||
_revertValueAndEmit(deviceId, 'normal_open_switch', oldValue, emit);
|
_revertValueAndEmit(deviceId, 'normal_open_switch', oldValue, emit);
|
||||||
}
|
}
|
||||||
@ -88,35 +77,8 @@ class DoorLockBloc extends Bloc<DoorLockEvent, DoorLockState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _runDebounce({
|
void _revertValueAndEmit(String deviceId, String code, dynamic oldValue,
|
||||||
required String deviceId,
|
Emitter<DoorLockState> emit) {
|
||||||
required String code,
|
|
||||||
required dynamic value,
|
|
||||||
required dynamic oldValue,
|
|
||||||
required Emitter<DoorLockState> emit,
|
|
||||||
}) async {
|
|
||||||
if (_timer != null) {
|
|
||||||
_timer!.cancel();
|
|
||||||
}
|
|
||||||
_timer = Timer(const Duration(seconds: 1), () async {
|
|
||||||
try {
|
|
||||||
final response = await DevicesManagementApi()
|
|
||||||
.deviceControl(deviceId, Status(code: code, value: value));
|
|
||||||
if (!response) {
|
|
||||||
_revertValueAndEmit(deviceId, code, oldValue, emit);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
_revertValueAndEmit(deviceId, code, oldValue, emit);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _revertValueAndEmit(
|
|
||||||
String deviceId,
|
|
||||||
String code,
|
|
||||||
dynamic oldValue,
|
|
||||||
Emitter<DoorLockState> emit,
|
|
||||||
) {
|
|
||||||
_updateLocalValue(code, oldValue);
|
_updateLocalValue(code, oldValue);
|
||||||
emit(DoorLockStatusLoaded(deviceStatus));
|
emit(DoorLockStatusLoaded(deviceStatus));
|
||||||
emit(const DoorLockControlError('Failed to control the device.'));
|
emit(const DoorLockControlError('Failed to control the device.'));
|
||||||
@ -124,34 +86,23 @@ class DoorLockBloc extends Bloc<DoorLockEvent, DoorLockState> {
|
|||||||
|
|
||||||
void _updateLocalValue(String code, dynamic value) {
|
void _updateLocalValue(String code, dynamic value) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 'reverse_lock':
|
|
||||||
if (value is bool) {
|
|
||||||
deviceStatus = deviceStatus.copyWith(reverseLock: value);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'normal_open_switch':
|
case 'normal_open_switch':
|
||||||
if (value is bool) {
|
if (value is bool) {
|
||||||
deviceStatus = deviceStatus.copyWith(normalOpenSwitch: value);
|
deviceStatus = deviceStatus.copyWith(normalOpenSwitch: value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'reverse_lock':
|
||||||
|
if (value is bool) {
|
||||||
|
deviceStatus = deviceStatus.copyWith(reverseLock: value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
emit(DoorLockStatusLoaded(deviceStatus));
|
emit(DoorLockStatusLoaded(deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamic _getValueByCode(String code) {
|
Future<void> _onFactoryReset(
|
||||||
switch (code) {
|
|
||||||
case 'reverse_lock':
|
|
||||||
return deviceStatus.reverseLock;
|
|
||||||
case 'normal_open_switch':
|
|
||||||
return deviceStatus.normalOpenSwitch;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FutureOr<void> _onFactoryReset(
|
|
||||||
DoorLockFactoryReset event, Emitter<DoorLockState> emit) async {
|
DoorLockFactoryReset event, Emitter<DoorLockState> emit) async {
|
||||||
emit(DoorLockStatusLoading());
|
emit(DoorLockStatusLoading());
|
||||||
try {
|
try {
|
||||||
|
@ -8,7 +8,7 @@ import 'package:syncrow_web/pages/device_managment/door_lock/models/door_lock_st
|
|||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
class DoorLockButton extends StatefulWidget {
|
class DoorLockButton extends StatelessWidget {
|
||||||
const DoorLockButton({
|
const DoorLockButton({
|
||||||
super.key,
|
super.key,
|
||||||
required this.doorLock,
|
required this.doorLock,
|
||||||
@ -18,70 +18,28 @@ class DoorLockButton extends StatefulWidget {
|
|||||||
final AllDevicesModel doorLock;
|
final AllDevicesModel doorLock;
|
||||||
final DoorLockStatusModel smartDoorModel;
|
final DoorLockStatusModel smartDoorModel;
|
||||||
|
|
||||||
@override
|
double _calculateProgress() {
|
||||||
State<DoorLockButton> createState() =>
|
final value = smartDoorModel.unlockRequest;
|
||||||
_DoorLockButtonState(smartDoorModel: smartDoorModel);
|
if (value <= 0 || value > 30) return 0;
|
||||||
}
|
return value / 30.0;
|
||||||
|
|
||||||
class _DoorLockButtonState extends State<DoorLockButton>
|
|
||||||
with SingleTickerProviderStateMixin {
|
|
||||||
late AnimationController _animationController;
|
|
||||||
late Animation<double> _animation;
|
|
||||||
DoorLockStatusModel smartDoorModel;
|
|
||||||
|
|
||||||
_DoorLockButtonState({required this.smartDoorModel});
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_animationController = AnimationController(
|
|
||||||
vsync: this,
|
|
||||||
duration: const Duration(milliseconds: 500),
|
|
||||||
);
|
|
||||||
_animation = Tween<double>(begin: 0, end: 1).animate(_animationController)
|
|
||||||
..addListener(() {
|
|
||||||
setState(() {});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (smartDoorModel.unlockRequest > 0) {
|
|
||||||
_animationController.reverse(from: 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void didUpdateWidget(covariant DoorLockButton oldWidget) {
|
|
||||||
super.didUpdateWidget(oldWidget);
|
|
||||||
if (oldWidget.smartDoorModel.normalOpenSwitch !=
|
|
||||||
widget.smartDoorModel.normalOpenSwitch) {
|
|
||||||
setState(() {
|
|
||||||
smartDoorModel = widget.smartDoorModel;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (smartDoorModel.unlockRequest > 0) {
|
|
||||||
_animationController.forward(from: 0);
|
|
||||||
} else {
|
|
||||||
_animationController.reverse(from: 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_animationController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final progress = _calculateProgress();
|
||||||
|
final isEnabled = smartDoorModel.unlockRequest > 0;
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 255,
|
width: 255,
|
||||||
height: 255,
|
height: 255,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: isEnabled
|
||||||
_animationController.forward(from: 0);
|
? () {
|
||||||
BlocProvider.of<DoorLockBloc>(context)
|
BlocProvider.of<DoorLockBloc>(context).add(
|
||||||
.add(UpdateLockEvent(value: !smartDoorModel.normalOpenSwitch));
|
UpdateLockEvent(value: !smartDoorModel.normalOpenSwitch),
|
||||||
},
|
);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 255,
|
width: 255,
|
||||||
height: 255,
|
height: 255,
|
||||||
@ -115,15 +73,16 @@ class _DoorLockButtonState extends State<DoorLockButton>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox.expand(
|
if (progress > 0)
|
||||||
child: CircularProgressIndicator(
|
SizedBox.expand(
|
||||||
value: _animation.value,
|
child: CircularProgressIndicator(
|
||||||
strokeWidth: 8,
|
value: progress,
|
||||||
backgroundColor: Colors.transparent,
|
strokeWidth: 8,
|
||||||
valueColor: const AlwaysStoppedAnimation<Color>(
|
backgroundColor: Colors.transparent,
|
||||||
ColorsManager.primaryColor),
|
valueColor: const AlwaysStoppedAnimation<Color>(
|
||||||
|
ColorsManager.primaryColor),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Reference in New Issue
Block a user