mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-09 22:57:21 +00:00
push door lock
This commit is contained in:
17
assets/icons/door_un_look_ic.svg
Normal file
17
assets/icons/door_un_look_ic.svg
Normal file
@ -0,0 +1,17 @@
|
||||
<svg width="60" height="83" viewBox="0 0 60 83" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g filter="url(#filter0_i_594_1113)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M36.9111 57.3204C36.9111 55.4073 36.1416 53.6808 34.8899 52.4287C33.6383 51.1767 31.9124 50.4068 30 50.4068C28.0953 50.4068 26.3696 51.1767 25.1179 52.4287C23.8663 53.6809 23.0889 55.4074 23.0889 57.3204C23.0889 58.798 23.5554 60.1745 24.3561 61.3022C25.0169 62.2356 25.9031 62.9977 26.9371 63.511V66.7228C26.9371 67.5627 27.2791 68.3326 27.8389 68.8849C28.391 69.437 29.1605 69.787 30.0002 69.787C30.8476 69.787 31.6093 69.437 32.1691 68.8849C32.7212 68.3328 33.0631 67.5628 33.0631 66.7228V63.511C34.097 62.9977 34.9911 62.2356 35.6518 61.3022C36.4446 60.1745 36.9111 58.798 36.9111 57.3204ZM14.9028 37.186H52.9489C54.8924 37.186 56.657 37.9793 57.9321 39.2624C59.207 40.5378 60 42.3032 60 44.2475V75.9385C60 77.8827 59.207 79.648 57.9321 80.9234C56.6572 82.2066 54.8924 82.9998 52.9489 82.9998H7.05883C5.11535 82.9998 3.35067 82.2065 2.07562 80.9234C0.792999 79.648 -3.8147e-06 77.8825 -3.8147e-06 75.9385V44.2475C-3.8147e-06 42.3032 0.792999 40.5378 2.07562 39.2624C2.84529 38.4847 3.8015 37.8859 4.86652 37.5359V25.1426C4.86652 21.7519 5.55056 18.5088 6.77894 15.5459C8.06172 12.4662 9.92746 9.69761 12.2519 7.38002C14.5686 5.06243 17.3362 3.18826 20.4146 1.90516C23.3765 0.676325 26.6183 -0.000244141 30 -0.000244141C33.3895 -0.000244141 36.6312 0.676325 39.5932 1.90516C42.6717 3.18826 45.4392 5.06259 47.756 7.38002C50.0727 9.69745 51.9462 12.4662 53.2211 15.5459C54.4572 18.5088 55.1335 21.7519 55.1335 25.1426C55.1335 26.5268 54.5739 27.779 53.6642 28.6889C52.7546 29.5987 51.5029 30.1587 50.1192 30.1587C48.7355 30.1587 47.4761 29.5989 46.5665 28.6889C45.6647 27.779 45.0972 26.5268 45.0972 25.1426C45.0972 23.105 44.6929 21.1608 43.9545 19.3876C43.1849 17.5445 42.0576 15.8724 40.6583 14.4726C39.259 13.0806 37.5954 11.9529 35.7529 11.1829C33.9805 10.4442 32.0368 10.0398 30.0002 10.0398C27.9635 10.0398 26.0198 10.4441 24.2474 11.1829C22.405 11.9529 20.7414 13.0806 19.342 14.4726C17.9427 15.8724 16.8154 17.5445 16.0536 19.3876C15.3151 21.1606 14.9029 23.105 14.9029 25.1426L14.9028 37.186Z" fill="#C1C1C1"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_i_594_1113" x="0" y="-0.000244141" width="65" height="88" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dx="5" dy="5"/>
|
||||
<feGaussianBlur stdDeviation="2.5"/>
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"/>
|
||||
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_594_1113"/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
17
assets/icons/lockIcon.svg
Normal file
17
assets/icons/lockIcon.svg
Normal file
@ -0,0 +1,17 @@
|
||||
<svg width="51" height="68" viewBox="0 0 51 68" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g filter="url(#filter0_i_989_290)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M37.7041 29.193H12.6134V20.9929C12.6134 17.5416 14.0206 14.4018 16.2968 12.1312C18.5732 9.85412 21.7055 8.43994 25.1555 8.43994C28.6056 8.43994 31.7444 9.85425 34.0141 12.1312C36.2903 14.4018 37.7041 17.5418 37.7041 20.9929V29.193ZM48.398 30.9186C47.7365 30.2634 46.9259 29.7573 46.018 29.4719V20.9929C46.018 15.2516 43.6704 10.0293 39.8896 6.24716C36.1088 2.46505 30.8947 0.123047 25.1555 0.123047C19.4162 0.123047 14.2021 2.46505 10.4214 6.24716C6.64057 10.0293 4.29294 15.2516 4.29294 20.9929V29.446C3.35912 29.7314 2.52251 30.2438 1.84809 30.9186C0.784573 31.9891 0.123047 33.4552 0.123047 35.0769V61.4805C0.123047 63.1023 0.784573 64.5684 1.84809 65.6388C2.91806 66.7027 4.38383 67.3644 6.00496 67.3644H44.2411C45.8624 67.3644 47.328 66.7027 48.398 65.6388C49.4615 64.5684 50.123 63.1023 50.123 61.4805V35.0769C50.1232 33.4551 49.4617 31.9891 48.398 30.9186ZM21.0504 41.8887C22.0944 40.8507 23.5341 40.202 25.123 40.202C26.7119 40.202 28.1515 40.8507 29.1957 41.8887C30.2399 42.9333 30.8818 44.3735 30.8818 45.9628C30.8818 47.2018 30.4927 48.3436 29.8312 49.2844C29.2799 50.063 28.5406 50.6987 27.6781 51.1269V53.7997C27.6781 54.5002 27.3928 55.1425 26.9258 55.6031C26.4653 56.0636 25.8298 56.3556 25.1229 56.3556C24.4225 56.3556 23.7805 56.0636 23.32 55.6031C22.8596 55.1425 22.5677 54.5002 22.5677 53.7997V51.1269C21.7116 50.6987 20.9724 50.063 20.4211 49.2844C19.7531 48.3438 19.364 47.202 19.364 45.9628C19.3643 44.3734 20.0128 42.9331 21.0504 41.8887Z" fill="#C1C1C1"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_i_989_290" x="0.123047" y="0.123047" width="55" height="72.2412" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dx="5" dy="5"/>
|
||||
<feGaussianBlur stdDeviation="2.5"/>
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"/>
|
||||
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_989_290"/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/ac/view/ac_device_control.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/door_lock/view/door_lock_status_view.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/gateway/view/gateway_view.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/living_room_switch/view/living_room_device_control.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart';
|
||||
@ -19,7 +20,7 @@ mixin RouteControlsBasedCode {
|
||||
gatewayId: device.uuid!,
|
||||
);
|
||||
case 'DL':
|
||||
return const SizedBox();
|
||||
return DoorLockView(device: device);
|
||||
case 'WPS':
|
||||
return WallSensorControls(device: device);
|
||||
case 'CPS':
|
||||
|
131
lib/pages/device_managment/door_lock/bloc/door_lock_bloc.dart
Normal file
131
lib/pages/device_managment/door_lock/bloc/door_lock_bloc.dart
Normal file
@ -0,0 +1,131 @@
|
||||
// ignore_for_file: invalid_use_of_visible_for_testing_member
|
||||
|
||||
import 'dart:async';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/door_lock/bloc/door_lock_event.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/door_lock/bloc/door_lock_state.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/door_lock/models/door_lock_status_model.dart';
|
||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||
|
||||
class DoorLockBloc extends Bloc<DoorLockEvent, DoorLockState> {
|
||||
late DoorLockStatusModel deviceStatus;
|
||||
final String deviceId;
|
||||
Timer? _timer;
|
||||
|
||||
DoorLockBloc({required this.deviceId}) : super(DoorLockInitial()) {
|
||||
on<DoorLockFetchStatus>(_onFetchDeviceStatus);
|
||||
on<DoorLockControl>(_onDoorLockControl);
|
||||
on<UpdateLockEvent>(_updateLock);
|
||||
}
|
||||
|
||||
FutureOr<void> _onFetchDeviceStatus(
|
||||
DoorLockFetchStatus event, Emitter<DoorLockState> emit) async {
|
||||
emit(DoorLockStatusLoading());
|
||||
try {
|
||||
final status =
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
deviceStatus =
|
||||
DoorLockStatusModel.fromJson(event.deviceId, status.status);
|
||||
emit(DoorLockStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
emit(DoorLockControlError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onDoorLockControl(
|
||||
DoorLockControl event, Emitter<DoorLockState> emit) async {
|
||||
final oldValue = _getValueByCode(event.code);
|
||||
_updateLocalValue(event.code, event.value);
|
||||
emit(DoorLockStatusLoaded(deviceStatus));
|
||||
|
||||
await _runDebounce(
|
||||
deviceId: event.deviceId,
|
||||
code: event.code,
|
||||
value: event.value,
|
||||
oldValue: oldValue,
|
||||
emit: emit,
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> _updateLock(
|
||||
UpdateLockEvent event, Emitter<DoorLockState> emit) async {
|
||||
final oldValue = deviceStatus.normalOpenSwitch;
|
||||
deviceStatus = deviceStatus.copyWith(normalOpenSwitch: event.value);
|
||||
emit(DoorLockStatusLoaded(deviceStatus));
|
||||
|
||||
try {
|
||||
final response = await DevicesManagementApi.openDoorLock(deviceId);
|
||||
|
||||
if (!response) {
|
||||
_revertValueAndEmit(deviceId, 'normal_open_switch', oldValue, emit);
|
||||
}
|
||||
} catch (e) {
|
||||
_revertValueAndEmit(deviceId, 'normal_open_switch', oldValue, emit);
|
||||
emit(DoorLockControlError('Error controlling the lock: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _runDebounce({
|
||||
required String deviceId,
|
||||
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);
|
||||
emit(DoorLockStatusLoaded(deviceStatus));
|
||||
emit(const DoorLockControlError('Failed to control the device.'));
|
||||
}
|
||||
|
||||
void _updateLocalValue(String code, dynamic value) {
|
||||
switch (code) {
|
||||
case 'reverse_lock':
|
||||
if (value is bool) {
|
||||
deviceStatus = deviceStatus.copyWith(reverseLock: value);
|
||||
}
|
||||
break;
|
||||
case 'normal_open_switch':
|
||||
if (value is bool) {
|
||||
deviceStatus = deviceStatus.copyWith(normalOpenSwitch: value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
emit(DoorLockStatusLoaded(deviceStatus));
|
||||
}
|
||||
|
||||
dynamic _getValueByCode(String code) {
|
||||
switch (code) {
|
||||
case 'reverse_lock':
|
||||
return deviceStatus.reverseLock;
|
||||
case 'normal_open_switch':
|
||||
return deviceStatus.normalOpenSwitch;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
sealed class DoorLockEvent extends Equatable {
|
||||
const DoorLockEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class DoorLockFetchStatus extends DoorLockEvent {
|
||||
final String deviceId;
|
||||
|
||||
const DoorLockFetchStatus(this.deviceId);
|
||||
|
||||
@override
|
||||
List<Object> get props => [deviceId];
|
||||
}
|
||||
|
||||
class DoorLockControl extends DoorLockEvent {
|
||||
final String deviceId;
|
||||
final String code;
|
||||
final bool value;
|
||||
|
||||
const DoorLockControl({
|
||||
required this.deviceId,
|
||||
required this.code,
|
||||
required this.value,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [deviceId, code, value];
|
||||
}
|
||||
|
||||
class UpdateLockEvent extends DoorLockEvent {
|
||||
final bool value;
|
||||
const UpdateLockEvent({required this.value});
|
||||
@override
|
||||
List<Object> get props => [value];
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/door_lock/models/door_lock_status_model.dart';
|
||||
|
||||
sealed class DoorLockState extends Equatable {
|
||||
const DoorLockState();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class DoorLockInitial extends DoorLockState {}
|
||||
|
||||
class DoorLockStatusLoading extends DoorLockState {}
|
||||
|
||||
class DoorLockStatusLoaded extends DoorLockState {
|
||||
final DoorLockStatusModel status;
|
||||
|
||||
const DoorLockStatusLoaded(this.status);
|
||||
|
||||
@override
|
||||
List<Object> get props => [status];
|
||||
}
|
||||
|
||||
class DoorLockControlLoading extends DoorLockState {}
|
||||
|
||||
class DoorLockControlError extends DoorLockState {
|
||||
final String message;
|
||||
|
||||
const DoorLockControlError(this.message);
|
||||
|
||||
@override
|
||||
List<Object> get props => [message];
|
||||
}
|
||||
|
||||
class LoadingNewSate extends DoorLockState {
|
||||
final DoorLockStatusModel smartDoorModel;
|
||||
const LoadingNewSate({required this.smartDoorModel});
|
||||
|
||||
@override
|
||||
List<Object> get props => [smartDoorModel];
|
||||
}
|
||||
|
||||
class UpdateState extends DoorLockState {
|
||||
final DoorLockStatusModel smartDoorModel;
|
||||
const UpdateState({required this.smartDoorModel});
|
||||
|
||||
@override
|
||||
List<Object> get props => [smartDoorModel];
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
|
||||
class DoorLockStatusModel {
|
||||
final String uuid;
|
||||
final int unlockFingerprint;
|
||||
final int unlockPassword;
|
||||
final int unlockTemporary;
|
||||
final int unlockCard;
|
||||
final String alarmLock;
|
||||
final int unlockRequest;
|
||||
final int residualElectricity;
|
||||
final bool reverseLock;
|
||||
final int unlockApp;
|
||||
final bool hijack;
|
||||
final bool doorbell;
|
||||
final String unlockOfflinePd;
|
||||
final String unlockOfflineClear;
|
||||
final String unlockDoubleKit;
|
||||
final String remoteNoPdSetkey;
|
||||
final String remoteNoDpKey;
|
||||
bool normalOpenSwitch;
|
||||
|
||||
DoorLockStatusModel({
|
||||
required this.uuid,
|
||||
required this.unlockFingerprint,
|
||||
required this.unlockPassword,
|
||||
required this.unlockTemporary,
|
||||
required this.unlockCard,
|
||||
required this.alarmLock,
|
||||
required this.unlockRequest,
|
||||
required this.residualElectricity,
|
||||
required this.reverseLock,
|
||||
required this.unlockApp,
|
||||
required this.hijack,
|
||||
required this.doorbell,
|
||||
required this.unlockOfflinePd,
|
||||
required this.unlockOfflineClear,
|
||||
required this.unlockDoubleKit,
|
||||
required this.remoteNoPdSetkey,
|
||||
required this.remoteNoDpKey,
|
||||
required this.normalOpenSwitch,
|
||||
});
|
||||
|
||||
factory DoorLockStatusModel.fromJson(String id, List<Status> jsonList) {
|
||||
late int unlockFingerprint;
|
||||
late int unlockPassword;
|
||||
late int unlockTemporary;
|
||||
late int unlockCard;
|
||||
late String alarmLock;
|
||||
late int unlockRequest;
|
||||
late int residualElectricity;
|
||||
late bool reverseLock;
|
||||
late int unlockApp;
|
||||
late bool hijack;
|
||||
late bool doorbell;
|
||||
late String unlockOfflinePd;
|
||||
late String unlockOfflineClear;
|
||||
late String unlockDoubleKit;
|
||||
late String remoteNoPdSetkey;
|
||||
late String remoteNoDpKey;
|
||||
late bool normalOpenSwitch;
|
||||
|
||||
for (var status in jsonList) {
|
||||
switch (status.code) {
|
||||
case 'unlock_fingerprint':
|
||||
unlockFingerprint = status.value ?? 0;
|
||||
break;
|
||||
case 'unlock_password':
|
||||
unlockPassword = status.value ?? 0;
|
||||
break;
|
||||
case 'unlock_temporary':
|
||||
unlockTemporary = status.value ?? 0;
|
||||
break;
|
||||
case 'unlock_card':
|
||||
unlockCard = status.value ?? 0;
|
||||
break;
|
||||
case 'alarm_lock':
|
||||
alarmLock = status.value ?? '';
|
||||
break;
|
||||
case 'unlock_request':
|
||||
unlockRequest = status.value ?? 0;
|
||||
break;
|
||||
case 'residual_electricity':
|
||||
residualElectricity = status.value ?? 0;
|
||||
break;
|
||||
case 'reverse_lock':
|
||||
reverseLock = status.value ?? false;
|
||||
break;
|
||||
case 'unlock_app':
|
||||
unlockApp = status.value ?? 0;
|
||||
break;
|
||||
case 'hijack':
|
||||
hijack = status.value ?? false;
|
||||
break;
|
||||
case 'doorbell':
|
||||
doorbell = status.value ?? false;
|
||||
break;
|
||||
case 'unlock_offline_pd':
|
||||
unlockOfflinePd = status.value ?? '';
|
||||
break;
|
||||
case 'unlock_offline_clear':
|
||||
unlockOfflineClear = status.value ?? '';
|
||||
break;
|
||||
case 'unlock_double_kit':
|
||||
unlockDoubleKit = status.value ?? '';
|
||||
break;
|
||||
case 'remote_no_pd_setkey':
|
||||
remoteNoPdSetkey = status.value ?? '';
|
||||
break;
|
||||
case 'remote_no_dp_key':
|
||||
remoteNoDpKey = status.value ?? '';
|
||||
break;
|
||||
case 'normal_open_switch':
|
||||
normalOpenSwitch = status.value ?? false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return DoorLockStatusModel(
|
||||
uuid: id,
|
||||
unlockFingerprint: unlockFingerprint,
|
||||
unlockPassword: unlockPassword,
|
||||
unlockTemporary: unlockTemporary,
|
||||
unlockCard: unlockCard,
|
||||
alarmLock: alarmLock,
|
||||
unlockRequest: unlockRequest,
|
||||
residualElectricity: residualElectricity,
|
||||
reverseLock: reverseLock,
|
||||
unlockApp: unlockApp,
|
||||
hijack: hijack,
|
||||
doorbell: doorbell,
|
||||
unlockOfflinePd: unlockOfflinePd,
|
||||
unlockOfflineClear: unlockOfflineClear,
|
||||
unlockDoubleKit: unlockDoubleKit,
|
||||
remoteNoPdSetkey: remoteNoPdSetkey,
|
||||
remoteNoDpKey: remoteNoDpKey,
|
||||
normalOpenSwitch: normalOpenSwitch,
|
||||
);
|
||||
}
|
||||
|
||||
DoorLockStatusModel copyWith({
|
||||
String? uuid,
|
||||
int? unlockFingerprint,
|
||||
int? unlockPassword,
|
||||
int? unlockTemporary,
|
||||
int? unlockCard,
|
||||
String? alarmLock,
|
||||
int? unlockRequest,
|
||||
int? residualElectricity,
|
||||
bool? reverseLock,
|
||||
int? unlockApp,
|
||||
bool? hijack,
|
||||
bool? doorbell,
|
||||
String? unlockOfflinePd,
|
||||
String? unlockOfflineClear,
|
||||
String? unlockDoubleKit,
|
||||
String? remoteNoPdSetkey,
|
||||
String? remoteNoDpKey,
|
||||
bool? normalOpenSwitch,
|
||||
}) {
|
||||
return DoorLockStatusModel(
|
||||
uuid: uuid ?? this.uuid,
|
||||
unlockFingerprint: unlockFingerprint ?? this.unlockFingerprint,
|
||||
unlockPassword: unlockPassword ?? this.unlockPassword,
|
||||
unlockTemporary: unlockTemporary ?? this.unlockTemporary,
|
||||
unlockCard: unlockCard ?? this.unlockCard,
|
||||
alarmLock: alarmLock ?? this.alarmLock,
|
||||
unlockRequest: unlockRequest ?? this.unlockRequest,
|
||||
residualElectricity: residualElectricity ?? this.residualElectricity,
|
||||
reverseLock: reverseLock ?? this.reverseLock,
|
||||
unlockApp: unlockApp ?? this.unlockApp,
|
||||
hijack: hijack ?? this.hijack,
|
||||
doorbell: doorbell ?? this.doorbell,
|
||||
unlockOfflinePd: unlockOfflinePd ?? this.unlockOfflinePd,
|
||||
unlockOfflineClear: unlockOfflineClear ?? this.unlockOfflineClear,
|
||||
unlockDoubleKit: unlockDoubleKit ?? this.unlockDoubleKit,
|
||||
remoteNoPdSetkey: remoteNoPdSetkey ?? this.remoteNoPdSetkey,
|
||||
remoteNoDpKey: remoteNoDpKey ?? this.remoteNoDpKey,
|
||||
normalOpenSwitch: normalOpenSwitch ?? this.normalOpenSwitch,
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/door_lock/bloc/door_lock_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/door_lock/bloc/door_lock_event.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/door_lock/bloc/door_lock_state.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/door_lock/models/door_lock_status_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/door_lock/widget/door_button.dart';
|
||||
|
||||
class DoorLockView extends StatelessWidget {
|
||||
final AllDevicesModel device;
|
||||
|
||||
const DoorLockView({super.key, required this.device});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => DoorLockBloc(deviceId: device.uuid!)
|
||||
..add(DoorLockFetchStatus(device.uuid!)),
|
||||
child: BlocListener<DoorLockBloc, DoorLockState>(
|
||||
listener: (context, state) {
|
||||
if (state is DoorLockControlError) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(state.message)),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: BlocBuilder<DoorLockBloc, DoorLockState>(
|
||||
builder: (context, state) {
|
||||
if (state is DoorLockStatusLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (state is DoorLockStatusLoaded) {
|
||||
return _buildStatusControls(context, state.status);
|
||||
} else if (state is UpdateState) {
|
||||
return _buildStatusControls(context, state.smartDoorModel);
|
||||
} else if (state is DoorLockControlError) {
|
||||
return Center(child: Text(state.message));
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatusControls(
|
||||
BuildContext context, DoorLockStatusModel status) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 40),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
DoorLockButton(
|
||||
smartDoorModel: status,
|
||||
doorLock: device,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
130
lib/pages/device_managment/door_lock/widget/door_button.dart
Normal file
130
lib/pages/device_managment/door_lock/widget/door_button.dart
Normal file
@ -0,0 +1,130 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/door_lock/bloc/door_lock_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/door_lock/bloc/door_lock_event.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/door_lock/models/door_lock_status_model.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class DoorLockButton extends StatefulWidget {
|
||||
const DoorLockButton({
|
||||
super.key,
|
||||
required this.doorLock,
|
||||
required this.smartDoorModel,
|
||||
});
|
||||
|
||||
final AllDevicesModel doorLock;
|
||||
final DoorLockStatusModel smartDoorModel;
|
||||
|
||||
@override
|
||||
State<DoorLockButton> createState() =>
|
||||
_DoorLockButtonState(smartDoorModel: smartDoorModel);
|
||||
}
|
||||
|
||||
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.forward();
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_animationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: 255,
|
||||
height: 255,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
_animationController.forward(from: 0);
|
||||
BlocProvider.of<DoorLockBloc>(context)
|
||||
.add(UpdateLockEvent(value: !smartDoorModel.normalOpenSwitch));
|
||||
},
|
||||
child: Container(
|
||||
width: 255,
|
||||
height: 255,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFEBECED),
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.5),
|
||||
blurRadius: 18,
|
||||
blurStyle: BlurStyle.outer,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Container(
|
||||
margin: const EdgeInsets.all(30),
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFF9F9F9),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
smartDoorModel.normalOpenSwitch
|
||||
? Assets.doorUnlock
|
||||
: Assets.lockIcon,
|
||||
width: 60,
|
||||
height: 60,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox.expand(
|
||||
child: CircularProgressIndicator(
|
||||
value: _animation.value,
|
||||
strokeWidth: 8,
|
||||
backgroundColor: Colors.transparent,
|
||||
valueColor: const AlwaysStoppedAnimation<Color>(
|
||||
ColorsManager.primaryColor),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -119,157 +119,4 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ////// changing here for devices controls ////
|
||||
// Widget _buildStatusControls(List<Status> statuses) {
|
||||
// return GridView.builder(
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 40),
|
||||
// shrinkWrap: true,
|
||||
// physics: const NeverScrollableScrollPhysics(),
|
||||
// gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
// crossAxisCount: 3,
|
||||
// mainAxisExtent: 133,
|
||||
// crossAxisSpacing: 12,
|
||||
// mainAxisSpacing: 12,
|
||||
// ),
|
||||
// itemCount: statuses.length,
|
||||
// itemBuilder: (context, index) {
|
||||
// final status = statuses[index];
|
||||
|
||||
// return Container(
|
||||
// decoration: BoxDecoration(
|
||||
// borderRadius: BorderRadius.circular(20),
|
||||
// color: ColorsManager.greyColor.withOpacity(0.2),
|
||||
// border: Border.all(color: ColorsManager.boxDivider),
|
||||
// ),
|
||||
// padding: const EdgeInsets.all(16),
|
||||
// child: _buildControlForStatus(status),
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
|
||||
// Widget _buildControlForStatus(Status status) {
|
||||
// switch (status.type) {
|
||||
// case OperationDialogType.onOff:
|
||||
// return Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||
// children: [
|
||||
// if (status.icon.isNotEmpty)
|
||||
// ClipOval(
|
||||
// child: Container(
|
||||
// color: ColorsManager.whiteColors,
|
||||
// child: SvgPicture.asset(
|
||||
// status.icon,
|
||||
// width: 60,
|
||||
// height: 60,
|
||||
// fit: BoxFit.cover,
|
||||
// ),
|
||||
// )),
|
||||
// SizedBox(
|
||||
// height: 20,
|
||||
// width: 35,
|
||||
// child: CupertinoSwitch(
|
||||
// value: status.value ?? false,
|
||||
// onChanged: (newValue) {
|
||||
// // Handle toggle change
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// const Spacer(),
|
||||
// Center(
|
||||
// child: Text(
|
||||
// status.name,
|
||||
// style: const TextStyle(
|
||||
// fontWeight: FontWeight.bold,
|
||||
// fontSize: 14,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// case OperationDialogType.countdown:
|
||||
// return Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// Center(
|
||||
// child: Text(
|
||||
// status.name,
|
||||
// style: const TextStyle(
|
||||
// fontWeight: FontWeight.bold,
|
||||
// fontSize: 14,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// const Spacer(),
|
||||
// IncrementDecrementWidget(
|
||||
// value: status.value.toString(),
|
||||
// description: 'hr',
|
||||
// onIncrement: () {
|
||||
// // Handle increment
|
||||
// },
|
||||
// onDecrement: () {
|
||||
// // Handle decrement
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// case OperationDialogType.integerSteps:
|
||||
// return IncrementDecrementWidget(
|
||||
// value: status.value.toString(),
|
||||
// description: 'm',
|
||||
// onIncrement: () {
|
||||
// // Handle increment
|
||||
// },
|
||||
// onDecrement: () {
|
||||
// // Handle decrement
|
||||
// },
|
||||
// );
|
||||
// case OperationDialogType.listOfOptions:
|
||||
// return Wrap(
|
||||
// children: [
|
||||
// ...status.options!.map((e) => ClipOval(
|
||||
// child: SvgPicture.asset(
|
||||
// e.icon,
|
||||
// width: 40,
|
||||
// height: 40,
|
||||
// fit: BoxFit.cover,
|
||||
// ),
|
||||
// ))
|
||||
// ],
|
||||
// );
|
||||
|
||||
// default:
|
||||
// return Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// if (status.icon.isNotEmpty)
|
||||
// ClipOval(
|
||||
// child: Container(
|
||||
// color: ColorsManager.whiteColors,
|
||||
// child: SvgPicture.asset(
|
||||
// status.icon,
|
||||
// width: 60,
|
||||
// height: 60,
|
||||
// fit: BoxFit.cover,
|
||||
// ),
|
||||
// )),
|
||||
// const Spacer(),
|
||||
// Text(
|
||||
// status.value.toString(),
|
||||
// style: const TextStyle(
|
||||
// fontSize: 14,
|
||||
// color: Colors.black54,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
@ -82,4 +82,15 @@ class DevicesManagementApi {
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -34,4 +34,5 @@ abstract class ApiEndpoints {
|
||||
|
||||
static const String deviceControl = '$baseUrl/device/{uuid}/control';
|
||||
static const String gatewayApi = '/device/gateway/{gatewayUuid}/devices';
|
||||
static const String openDoorLock = '/door-lock/open/{doorLockUuid}';
|
||||
}
|
||||
|
@ -130,4 +130,11 @@ class Assets {
|
||||
static const String lightBulb = "assets/icons/Light.svg";
|
||||
//assets/icons/sensors.svg
|
||||
static const String sensors = "assets/icons/sensors.svg";
|
||||
|
||||
//assets/icons/door_un_look_ic.svg
|
||||
static const String doorUnlock = 'assets/icons/door_un_look_ic.svg';
|
||||
|
||||
//assets/icons/lockIcon.svg
|
||||
|
||||
static const String lockIcon = 'assets/icons/lockIcon.svg';
|
||||
}
|
||||
|
Reference in New Issue
Block a user