diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..c169a71
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "cSpell.words": [
+ "Scheduleapp"
+ ]
+}
\ No newline at end of file
diff --git a/assets/icons/closed_garage_door.svg b/assets/icons/closed_garage_door.svg
new file mode 100644
index 0000000..464aa07
--- /dev/null
+++ b/assets/icons/closed_garage_door.svg
@@ -0,0 +1,148 @@
+
diff --git a/assets/icons/curtainsIcon/verticalBlade.svg b/assets/icons/curtainsIcon/left_vertical_blade.svg
similarity index 100%
rename from assets/icons/curtainsIcon/verticalBlade.svg
rename to assets/icons/curtainsIcon/left_vertical_blade.svg
diff --git a/assets/icons/curtainsIcon/right_vertical_blade.svg b/assets/icons/curtainsIcon/right_vertical_blade.svg
new file mode 100644
index 0000000..d7675aa
--- /dev/null
+++ b/assets/icons/curtainsIcon/right_vertical_blade.svg
@@ -0,0 +1,32 @@
+
diff --git a/assets/icons/garageIcon.svg b/assets/icons/garageIcon.svg
new file mode 100644
index 0000000..0b044eb
--- /dev/null
+++ b/assets/icons/garageIcon.svg
@@ -0,0 +1,135 @@
+
diff --git a/assets/icons/garage_countdown.svg b/assets/icons/garage_countdown.svg
new file mode 100644
index 0000000..b2a3ead
--- /dev/null
+++ b/assets/icons/garage_countdown.svg
@@ -0,0 +1,29 @@
+
diff --git a/assets/icons/garage_preferences_icon.svg b/assets/icons/garage_preferences_icon.svg
new file mode 100644
index 0000000..d0883b0
--- /dev/null
+++ b/assets/icons/garage_preferences_icon.svg
@@ -0,0 +1,11 @@
+
diff --git a/assets/icons/garage_schedule.svg b/assets/icons/garage_schedule.svg
new file mode 100644
index 0000000..04e7763
--- /dev/null
+++ b/assets/icons/garage_schedule.svg
@@ -0,0 +1,28 @@
+
diff --git a/assets/icons/open_garage_door.svg b/assets/icons/open_garage_door.svg
new file mode 100644
index 0000000..d55a690
--- /dev/null
+++ b/assets/icons/open_garage_door.svg
@@ -0,0 +1,117 @@
+
diff --git a/assets/images/Window.png b/assets/images/Window.png
deleted file mode 100644
index be38a0b..0000000
Binary files a/assets/images/Window.png and /dev/null differ
diff --git a/assets/images/window_img.svg b/assets/images/window_img.svg
new file mode 100644
index 0000000..d908db4
--- /dev/null
+++ b/assets/images/window_img.svg
@@ -0,0 +1,25 @@
+
diff --git a/lib/features/devices/bloc/curtain_bloc/curtain_bloc.dart b/lib/features/devices/bloc/curtain_bloc/curtain_bloc.dart
index 1dea664..7e0ac56 100644
--- a/lib/features/devices/bloc/curtain_bloc/curtain_bloc.dart
+++ b/lib/features/devices/bloc/curtain_bloc/curtain_bloc.dart
@@ -24,9 +24,7 @@ class CurtainBloc extends Bloc {
on(_onPauseCurtain);
}
- Future _onOpenCurtain(
- OpenCurtain event,
- Emitter emit) async {
+ Future _onOpenCurtain(OpenCurtain event, Emitter emit) async {
isMoving = true;
while (openPercentage < 100.0) {
if (state is CurtainsClosing) {
@@ -48,7 +46,7 @@ class CurtainBloc extends Bloc {
_pauseCurtain(emit);
}
});
- if (openPercentage >=100.0) {
+ if (openPercentage >= 100.0) {
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: curtainId,
@@ -73,8 +71,7 @@ class CurtainBloc extends Bloc {
}
}
- Future _onCloseCurtain(
- CloseCurtain event, Emitter emit) async {
+ Future _onCloseCurtain(CloseCurtain event, Emitter emit) async {
isMoving = true;
while (openPercentage > 0.0) {
if (state is CurtainsOpening) {
@@ -121,8 +118,7 @@ class CurtainBloc extends Bloc {
}
}
- Future _onPauseCurtain(
- PauseCurtain event, Emitter emit) async {
+ Future _onPauseCurtain(PauseCurtain event, Emitter emit) async {
_pauseCurtain(emit);
await DevicesAPI.controlDevice(
DeviceControlModel(
@@ -132,7 +128,7 @@ class CurtainBloc extends Bloc {
),
curtainId,
);
- await DevicesAPI.controlDevice(
+ await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: curtainId,
code: 'percent_control',
@@ -151,9 +147,6 @@ class CurtainBloc extends Bloc {
));
}
-
-
-
void _fetchStatus(InitCurtain event, Emitter emit) async {
try {
emit(CurtainLoadingState());
@@ -166,10 +159,9 @@ class CurtainBloc extends Bloc {
// Get the open percentage from the response
openPercentage = double.tryParse(statusModelList[1].value.toString())!;
// Calculate curtain width and blind height based on the open percentage
- if (openPercentage != null) {
- curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
- blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
- }
+ curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
+ blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
+
emit(CurtainsOpening(
curtainWidth: curtainWidth,
blindHeight: blindHeight,
@@ -180,5 +172,4 @@ class CurtainBloc extends Bloc {
return;
}
}
-
}
diff --git a/lib/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart b/lib/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart
new file mode 100644
index 0000000..995cd0c
--- /dev/null
+++ b/lib/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart
@@ -0,0 +1,564 @@
+import 'dart:async';
+import 'package:dio/dio.dart';
+import 'package:firebase_database/firebase_database.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
+import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_event.dart';
+import 'package:syncrow_app/features/devices/bloc/garage_door_bloc/garage_door_state.dart';
+import 'package:syncrow_app/features/devices/model/device_control_model.dart';
+import 'package:syncrow_app/features/devices/model/device_model.dart';
+import 'package:syncrow_app/features/devices/model/device_report_model.dart';
+import 'package:syncrow_app/features/devices/model/garage_door_model.dart';
+import 'package:syncrow_app/features/devices/model/group_garage_model.dart';
+import 'package:syncrow_app/features/devices/model/schedule_model.dart';
+import 'package:syncrow_app/features/devices/model/status_model.dart';
+import 'package:syncrow_app/services/api/devices_api.dart';
+import 'package:syncrow_app/utils/helpers/snack_bar.dart';
+
+class GarageDoorBloc extends Bloc {
+ final String GDId;
+ GarageDoorBloc({
+ required this.GDId,
+ }) : super(const GarageDoorSensorState()) {
+ on(_fetchStatus);
+ on(fetchLogsForLastMonth);
+ on(_toggleClosingReminder);
+ on(_toggleDoorAlarm);
+ on(toggleDaySelection);
+ on(saveSchedule);
+ on(getSchedule);
+ on(toggleChange);
+ on(toggleCreateSchedule);
+ on(_onClose);
+ on(selectSeconds);
+ on(openCloseGarageDoor);
+ on(_getCounterValue);
+ on(_setCounterValue);
+ on(_onTickTimer);
+ on(_fetchWizardStatus);
+ on(_groupAllOn);
+ on(_groupAllOff);
+ on(_changeFirstWizardSwitch);
+ }
+ void _onClose(OnClose event, Emitter emit) {
+ _timer?.cancel();
+ }
+
+ Timer? _timer;
+ bool lowBattery = false;
+ bool closingReminder = false;
+ bool doorAlarm = false;
+
+ GarageDoorModel deviceStatus = GarageDoorModel(
+ tr_timecon: 0,
+ countdown1: 0,
+ countdownAlarm: 0,
+ doorContactState: false,
+ doorControl1: '',
+ doorState1: '',
+ switch1: false,
+ voiceControl1: false,
+ batteryPercentage: 0,
+ );
+
+ void _fetchStatus(
+ GarageDoorInitial event, Emitter emit) async {
+ emit(GarageDoorLoadingState());
+ try {
+ var response = await DevicesAPI.getDeviceStatus(GDId);
+ List statusModelList = [];
+ for (var status in response['status']) {
+ statusModelList.add(StatusModel.fromJson(status));
+ }
+ deviceStatus = GarageDoorModel.fromJson(
+ statusModelList,
+ );
+ secondSelected = deviceStatus.tr_timecon;
+ toggleDoor = deviceStatus.switch1;
+ emit(UpdateState(garageSensor: deviceStatus));
+ Future.delayed(const Duration(milliseconds: 500));
+ _listenToChanges();
+ } catch (e) {
+ emit(GarageDoorFailedState(errorMessage: e.toString()));
+ return;
+ }
+ }
+
+ void _toggleClosingReminder(ToggleClosingReminderEvent event,
+ Emitter emit) async {
+ emit(LoadingNewSate(doorSensor: deviceStatus));
+ try {
+ closingReminder = event.isClosingReminderEnabled;
+ emit(UpdateState(garageSensor: deviceStatus));
+ await DevicesAPI.controlDevice(
+ DeviceControlModel(
+ deviceId: GDId,
+ code: 'closing_reminder',
+ value: closingReminder,
+ ),
+ GDId,
+ );
+ } catch (e) {
+ emit(GarageDoorFailedState(errorMessage: e.toString()));
+ }
+ }
+
+ void _toggleDoorAlarm(
+ ToggleDoorAlarmEvent event, Emitter emit) async {
+ emit(LoadingNewSate(doorSensor: deviceStatus));
+ try {
+ doorAlarm = event.isDoorAlarmEnabled;
+ emit(UpdateState(garageSensor: deviceStatus));
+ await DevicesAPI.controlDevice(
+ DeviceControlModel(
+ deviceId: GDId,
+ code: 'door_alarm',
+ value: doorAlarm,
+ ),
+ GDId,
+ );
+ } catch (e) {
+ emit(GarageDoorFailedState(errorMessage: e.toString()));
+ }
+ }
+
+ DeviceReport recordGroups =
+ DeviceReport(startTime: '0', endTime: '0', data: []);
+
+ Future fetchLogsForLastMonth(
+ ReportLogsInitial event, Emitter emit) async {
+ DateTime now = DateTime.now();
+
+ DateTime lastMonth = DateTime(now.year, now.month - 1, now.day);
+ int startTime = lastMonth.millisecondsSinceEpoch;
+ int endTime = now.millisecondsSinceEpoch;
+ try {
+ emit(GarageDoorLoadingState());
+ var response = await DevicesAPI.getReportLogs(
+ startTime: startTime.toString(),
+ endTime: endTime.toString(),
+ deviceUuid: GDId,
+ code: 'doorcontact_state',
+ );
+ recordGroups = response;
+ emit(UpdateState(garageSensor: deviceStatus));
+ } on DioException catch (e) {
+ final errorData = e.response!.data;
+ String errorMessage = errorData['message'];
+ emit(GarageDoorFailedState(errorMessage: errorMessage));
+ }
+ }
+
+ _listenToChanges() {
+ try {
+ DatabaseReference ref =
+ FirebaseDatabase.instance.ref('device-status/$GDId');
+ Stream stream = ref.onValue;
+
+ stream.listen((DatabaseEvent event) async {
+ if (_timer != null) {
+ await Future.delayed(const Duration(seconds: 2));
+ }
+ Map usersMap =
+ event.snapshot.value as Map;
+ List statusList = [];
+ usersMap['status'].forEach((element) {
+ statusList.add(StatusModel(code: element['code'], value: true));
+ });
+
+ deviceStatus = GarageDoorModel.fromJson(statusList);
+ if (!isClosed) {
+ // add(
+ // DoorSensorSwitch(switchD: deviceStatus.doorContactState),
+ // );
+ }
+ });
+ } catch (_) {}
+ }
+
+ List