mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-08-26 04:29:40 +00:00
@ -0,0 +1,334 @@
|
||||
import 'dart:async';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_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/schedule_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/status_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/water_heater.dart';
|
||||
import 'package:syncrow_app/services/api/devices_api.dart';
|
||||
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
final String whId;
|
||||
final String switchCode;
|
||||
WHModel deviceStatus = WHModel(
|
||||
firstSwitch: false,firstCountDown: 0
|
||||
);
|
||||
List<WHModel> deviceStatusList = [];
|
||||
List<DeviceModel> devicesList = [];
|
||||
bool allAcsPage = false;
|
||||
bool allAcsOn = true;
|
||||
bool allTempSame = true;
|
||||
int globalTemp = 25;
|
||||
Timer? _timer;
|
||||
|
||||
|
||||
bool toggleSchedule = true;
|
||||
List<String> selectedDays = [];
|
||||
bool createSchedule = false;
|
||||
bool createCirculate = false;
|
||||
List<ScheduleModel> listSchedule = [];
|
||||
DateTime? selectedTime=DateTime.now();
|
||||
|
||||
WaterHeaterBloc({required this.whId,required this.switchCode}) : super(WHInitialState()) {
|
||||
on<WaterHeaterInitial>(_fetchWaterHeaterStatus);
|
||||
on<WaterHeaterSwitch>(_changeFirstSwitch);
|
||||
on<SetCounterValue>(_setCounterValue);
|
||||
on<GetCounterEvent>(_getCounterValue);
|
||||
on<ToggleDaySelectionEvent>(toggleDaySelection);
|
||||
on<ScheduleSave>(saveSchedule);
|
||||
on<GetScheduleEvent>(getSchedule);
|
||||
on<ToggleScheduleEvent>(toggleChange);
|
||||
on<DeleteScheduleEvent>(deleteSchedule);
|
||||
on<TickTimer>(_onTickTimer);
|
||||
on<OnClose>(_onClose);
|
||||
on<SelectTimeEvent>(showTime);
|
||||
}
|
||||
|
||||
void _fetchWaterHeaterStatus(WaterHeaterInitial event, Emitter<WaterHeaterState> emit) async {
|
||||
emit(WHLoadingState());
|
||||
try {
|
||||
var response = await DevicesAPI.getDeviceStatus(whId);
|
||||
List<StatusModel> statusModelList = [];
|
||||
for (var status in response['status']) {
|
||||
statusModelList.add(StatusModel.fromJson(status));
|
||||
}
|
||||
deviceStatus = WHModel.fromJson(statusModelList, );
|
||||
emit(UpdateState(whModel: deviceStatus));
|
||||
Future.delayed(const Duration(milliseconds: 500));
|
||||
// _listenToChanges();
|
||||
} catch (e) {
|
||||
emit(WHFailedState(errorMessage: e.toString()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _changeFirstSwitch(WaterHeaterSwitch event, Emitter<WaterHeaterState> emit) async {
|
||||
emit(LoadingNewSate(whModel: deviceStatus));
|
||||
try {
|
||||
deviceStatus.firstSwitch = !event.whSwitch;
|
||||
emit(UpdateState(whModel: deviceStatus));
|
||||
if (_timer != null) {
|
||||
_timer!.cancel();
|
||||
}
|
||||
_timer = Timer(const Duration(milliseconds: 500), () async {
|
||||
final response = await DevicesAPI.controlDevice(
|
||||
DeviceControlModel(
|
||||
deviceId: whId,
|
||||
code: 'switch_1',
|
||||
value: deviceStatus.firstSwitch ),
|
||||
whId);
|
||||
|
||||
if (!response['success']) {
|
||||
// add(InitialEvent(groupScreen: oneGangGroup));
|
||||
}
|
||||
});
|
||||
} catch (_) {
|
||||
emit(WHFailedState(errorMessage: _.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//=====================---------- timer ----------------------------------------
|
||||
|
||||
void _setCounterValue(SetCounterValue event, Emitter<WaterHeaterState> emit) async {
|
||||
emit(LoadingNewSate(whModel: deviceStatus));
|
||||
int seconds = 0;
|
||||
try {
|
||||
seconds = event.duration.inSeconds;
|
||||
final response = await DevicesAPI.controlDevice(
|
||||
DeviceControlModel(deviceId: whId, code: event.deviceCode, value: seconds),
|
||||
whId);
|
||||
|
||||
if (response['success'] ?? false) {
|
||||
if (event.deviceCode == 'countdown_1') {
|
||||
deviceStatus.firstCountDown = seconds;
|
||||
}
|
||||
} else {
|
||||
emit(const WHFailedState(errorMessage: 'Something went wrong'));
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
emit(const WHFailedState(errorMessage: 'Something went wrong'));
|
||||
return;
|
||||
}
|
||||
if (seconds > 0) {
|
||||
_onStartTimer(seconds);
|
||||
} else {
|
||||
_timer?.cancel();
|
||||
emit(TimerRunComplete());
|
||||
}
|
||||
}
|
||||
|
||||
void _getCounterValue(GetCounterEvent event, Emitter<WaterHeaterState> emit) async {
|
||||
emit(WHLoadingState());
|
||||
try {
|
||||
var response = await DevicesAPI.getDeviceStatus(whId);
|
||||
List<StatusModel> statusModelList = [];
|
||||
for (var status in response['status']) {
|
||||
statusModelList.add(StatusModel.fromJson(status));
|
||||
}
|
||||
deviceStatus = WHModel.fromJson(statusModelList);
|
||||
|
||||
if (event.deviceCode == 'countdown_1') {
|
||||
deviceStatus.firstCountDown > 0
|
||||
? _onStartTimer(deviceStatus.firstCountDown)
|
||||
: emit(UpdateTimerState(seconds: deviceStatus.firstCountDown));
|
||||
}
|
||||
} catch (e) {
|
||||
WHFailedState(errorMessage: e.toString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void _onClose(OnClose event, Emitter<WaterHeaterState> emit) {
|
||||
_timer?.cancel();
|
||||
}
|
||||
|
||||
void _onStartTimer(int seconds) {
|
||||
_timer?.cancel();
|
||||
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
add(TickTimer(seconds - timer.tick));
|
||||
});
|
||||
}
|
||||
|
||||
void _onTickTimer(TickTimer event, Emitter<WaterHeaterState> emit) {
|
||||
if (event.remainingTime > 0) {
|
||||
emit(TimerRunInProgress(event.remainingTime));
|
||||
} else {
|
||||
_timer?.cancel();
|
||||
emit(TimerRunComplete());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//=====================---------- Schedule ----------------------------------------
|
||||
|
||||
|
||||
|
||||
List<Map<String, String>> days = [
|
||||
{"day": "Sun", "key": "Sun"},
|
||||
{"day": "Mon", "key": "Mon"},
|
||||
{"day": "Tue", "key": "Tue"},
|
||||
{"day": "Wed", "key": "Wed"},
|
||||
{"day": "Thu", "key": "Thu"},
|
||||
{"day": "Fri", "key": "Fri"},
|
||||
{"day": "Sat", "key": "Sat"},
|
||||
];
|
||||
|
||||
Future<void> saveSchedule(ScheduleSave event, Emitter<WaterHeaterState> emit,) async {
|
||||
try {
|
||||
if(selectedDays.isNotEmpty) {
|
||||
emit(WHLoadingState());
|
||||
final response = await DevicesAPI.postSchedule(
|
||||
category: switchCode,
|
||||
deviceId: whId,
|
||||
time: getTimeStampWithoutSeconds(selectedTime).toString(),
|
||||
code: switchCode,
|
||||
value: toggleSchedule,
|
||||
days: selectedDays);
|
||||
CustomSnackBar.displaySnackBar('Save Successfully');
|
||||
add(GetScheduleEvent());
|
||||
emit(SaveSchedule());
|
||||
toggleCreateSchedule();
|
||||
}else{
|
||||
CustomSnackBar.displaySnackBar('Please select days');
|
||||
}
|
||||
} catch (e) {
|
||||
emit(WHFailedState(errorMessage:e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getSchedule(GetScheduleEvent event, Emitter<WaterHeaterState> emit,) async {
|
||||
try {
|
||||
emit(WHLoadingState());
|
||||
final response = await DevicesAPI.getSchedule(
|
||||
category: switchCode,
|
||||
deviceId: whId ,
|
||||
);
|
||||
List<dynamic> jsonData = response;
|
||||
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
|
||||
emit(WHInitialState());
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
String errorMessage = errorData['message'];
|
||||
emit(WHFailedState(errorMessage: errorMessage.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
int? getTimeStampWithoutSeconds(DateTime? dateTime) {
|
||||
if (dateTime == null) return null;
|
||||
DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
|
||||
dateTime.day, dateTime.hour, dateTime.minute);
|
||||
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
|
||||
}
|
||||
|
||||
Future toggleChange(
|
||||
ToggleScheduleEvent event, Emitter<WaterHeaterState> emit) async {
|
||||
try {
|
||||
emit(WHLoadingState());
|
||||
final response = await DevicesAPI.changeSchedule(
|
||||
scheduleId: event.id, deviceUuid: whId, enable: event.toggle);
|
||||
if (response == true) {
|
||||
add(GetScheduleEvent());
|
||||
toggleSchedule = event.toggle;
|
||||
return toggleSchedule;
|
||||
}
|
||||
emit(IsToggleState(onOff: toggleSchedule));
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
String errorMessage = errorData['message'];
|
||||
emit(WHFailedState(errorMessage: errorMessage.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future deleteSchedule(
|
||||
DeleteScheduleEvent event, Emitter<WaterHeaterState> emit) async {
|
||||
try {
|
||||
emit(WHLoadingState());
|
||||
final response = await DevicesAPI.deleteSchedule(
|
||||
scheduleId: event.id,
|
||||
deviceUuid: whId, );
|
||||
if (response == true) {
|
||||
add(GetScheduleEvent());
|
||||
return toggleSchedule;
|
||||
}
|
||||
emit(IsToggleState(onOff: toggleSchedule));
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
String errorMessage = errorData['message'];
|
||||
emit(WHFailedState(errorMessage: errorMessage.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void toggleCreateSchedule() {
|
||||
emit(WHLoadingState());
|
||||
createSchedule = !createSchedule;
|
||||
selectedDays.clear();
|
||||
selectedTime=DateTime.now();
|
||||
emit(UpdateCreateScheduleState(createSchedule));
|
||||
}
|
||||
|
||||
void toggleCreateCirculate() {
|
||||
emit(WHLoadingState());
|
||||
createCirculate = !createCirculate;
|
||||
selectedDays.clear();
|
||||
selectedTime=DateTime.now();
|
||||
emit(UpdateCreateScheduleState(createCirculate));
|
||||
}
|
||||
|
||||
Future<void> toggleDaySelection(
|
||||
ToggleDaySelectionEvent event,
|
||||
Emitter<WaterHeaterState> emit,
|
||||
) async {
|
||||
emit(WHLoadingState());
|
||||
if (selectedDays.contains(event.key)) {
|
||||
selectedDays.remove(event.key);
|
||||
} else {
|
||||
selectedDays.add(event.key);
|
||||
}
|
||||
emit(ChangeTimeState());
|
||||
}
|
||||
|
||||
int selectedTabIndex = 0;
|
||||
|
||||
void toggleSelectedIndex(index) {
|
||||
emit(WHLoadingState());
|
||||
selectedTabIndex = index;
|
||||
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
|
||||
}
|
||||
|
||||
showTime(SelectTimeEvent event, Emitter<WaterHeaterState> emit) async {
|
||||
final TimeOfDay? timePicked = await showTimePicker(
|
||||
context: event.context,
|
||||
initialTime: TimeOfDay.now(),
|
||||
builder: (context, child) {
|
||||
return Theme(
|
||||
data: ThemeData.light().copyWith(
|
||||
colorScheme: const ColorScheme.light(
|
||||
primary: ColorsManager.primaryColor,
|
||||
onSurface: Colors.black,
|
||||
),
|
||||
buttonTheme: const ButtonThemeData(
|
||||
colorScheme: ColorScheme.light(
|
||||
primary: Colors.green,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: child!,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
abstract class WaterHeaterEvent extends Equatable {
|
||||
const WaterHeaterEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class WaterHeaterLoading extends WaterHeaterEvent {}
|
||||
|
||||
class WaterHeaterSwitch extends WaterHeaterEvent {
|
||||
final bool whSwitch;
|
||||
final String deviceId;
|
||||
final String productId;
|
||||
const WaterHeaterSwitch({required this.whSwitch, this.deviceId = '', this.productId = ''});
|
||||
|
||||
@override
|
||||
List<Object> get props => [whSwitch, deviceId, productId];
|
||||
}
|
||||
|
||||
class WaterHeaterUpdated extends WaterHeaterEvent {}
|
||||
|
||||
class WaterHeaterInitial extends WaterHeaterEvent {
|
||||
const WaterHeaterInitial();
|
||||
}
|
||||
|
||||
class WaterHeaterChangeStatus extends WaterHeaterEvent {}
|
||||
|
||||
|
||||
class GetCounterEvent extends WaterHeaterEvent {
|
||||
final String deviceCode;
|
||||
const GetCounterEvent({required this.deviceCode});
|
||||
@override
|
||||
List<Object> get props => [deviceCode];
|
||||
}
|
||||
|
||||
class SetCounterValue extends WaterHeaterEvent {
|
||||
final Duration duration;
|
||||
final String deviceCode;
|
||||
const SetCounterValue({required this.duration, required this.deviceCode});
|
||||
@override
|
||||
List<Object> get props => [duration, deviceCode];
|
||||
}
|
||||
|
||||
class StartTimer extends WaterHeaterEvent {
|
||||
final int duration;
|
||||
|
||||
const StartTimer(this.duration);
|
||||
|
||||
@override
|
||||
List<Object> get props => [duration];
|
||||
}
|
||||
|
||||
class TickTimer extends WaterHeaterEvent {
|
||||
final int remainingTime;
|
||||
|
||||
const TickTimer(this.remainingTime);
|
||||
|
||||
@override
|
||||
List<Object> get props => [remainingTime];
|
||||
}
|
||||
|
||||
class StopTimer extends WaterHeaterEvent {}
|
||||
|
||||
class OnClose extends WaterHeaterEvent {}
|
||||
|
||||
|
||||
//------------------- Schedule ----------=---------
|
||||
class GetScheduleEvent extends WaterHeaterEvent {}
|
||||
class ScheduleSave extends WaterHeaterEvent {}
|
||||
class ToggleScheduleEvent extends WaterHeaterEvent {
|
||||
final String id;
|
||||
final bool toggle;
|
||||
const ToggleScheduleEvent({required this.toggle,required this.id});
|
||||
@override
|
||||
List<Object> get props => [toggle,id];
|
||||
}
|
||||
class ToggleDaySelectionEvent extends WaterHeaterEvent {
|
||||
|
||||
final String key;
|
||||
|
||||
const ToggleDaySelectionEvent({required this.key});
|
||||
@override
|
||||
List<Object> get props => [key];
|
||||
}
|
||||
class DeleteScheduleEvent extends WaterHeaterEvent {
|
||||
final String id;
|
||||
const DeleteScheduleEvent({required this.id});
|
||||
@override
|
||||
List<Object> get props => [id];
|
||||
}
|
||||
|
||||
class SelectTimeEvent extends WaterHeaterEvent {
|
||||
final BuildContext context;
|
||||
final bool isEffective;
|
||||
const SelectTimeEvent({required this.context, required this.isEffective});
|
||||
@override
|
||||
List<Object> get props => [context, isEffective];
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_app/features/devices/model/water_heater.dart';
|
||||
|
||||
abstract class WaterHeaterState extends Equatable {
|
||||
const WaterHeaterState();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class WHInitialState extends WaterHeaterState {}
|
||||
|
||||
class WHLoadingState extends WaterHeaterState {}
|
||||
|
||||
class WHChangeLoading extends WaterHeaterState {
|
||||
// final WHStatusModel WHStatusModel;
|
||||
const WHChangeLoading(
|
||||
// {required this. WHStatusModel}
|
||||
);
|
||||
|
||||
// @override
|
||||
// List<Object> get props => [acStatusModel];
|
||||
}
|
||||
|
||||
class WHModifyingState extends WaterHeaterState {
|
||||
final WHModel whStatusModel;
|
||||
const WHModifyingState({required this.whStatusModel});
|
||||
|
||||
@override
|
||||
List<Object> get props => [whStatusModel];
|
||||
}
|
||||
|
||||
class GetWHStatusState extends WaterHeaterState {
|
||||
final WHModel whStatusModel;
|
||||
const GetWHStatusState({required this.whStatusModel});
|
||||
|
||||
@override
|
||||
List<Object> get props => [whStatusModel];
|
||||
}
|
||||
|
||||
|
||||
|
||||
class WHFailedState extends WaterHeaterState {
|
||||
final String errorMessage;
|
||||
|
||||
const WHFailedState({required this.errorMessage});
|
||||
|
||||
@override
|
||||
List<Object> get props => [errorMessage];
|
||||
}
|
||||
|
||||
|
||||
class LoadingNewSate extends WaterHeaterState {
|
||||
final WHModel whModel;
|
||||
const LoadingNewSate({required this.whModel});
|
||||
|
||||
@override
|
||||
List<Object> get props => [whModel];
|
||||
}
|
||||
class TimerRunComplete extends WaterHeaterState {}
|
||||
class UpdateTimerState extends WaterHeaterState {
|
||||
final int seconds;
|
||||
const UpdateTimerState({required this.seconds});
|
||||
|
||||
@override
|
||||
List<Object> get props => [seconds];
|
||||
}
|
||||
|
||||
class TimerRunInProgress extends WaterHeaterState {
|
||||
final int remainingTime;
|
||||
|
||||
const TimerRunInProgress(this.remainingTime);
|
||||
|
||||
@override
|
||||
List<Object> get props => [remainingTime];
|
||||
}
|
||||
|
||||
class SaveSchedule extends WaterHeaterState {}
|
||||
class ChangeTimeState extends WaterHeaterState {}
|
||||
class UpdateCreateScheduleState extends WaterHeaterState {
|
||||
final bool createSchedule;
|
||||
UpdateCreateScheduleState(this.createSchedule);
|
||||
}
|
||||
class IsToggleState extends WaterHeaterState {
|
||||
final bool? onOff;
|
||||
const IsToggleState({this.onOff});
|
||||
}
|
||||
|
||||
|
||||
class UpdateState extends WaterHeaterState {
|
||||
final WHModel whModel;
|
||||
const UpdateState({required this.whModel});
|
||||
|
||||
@override
|
||||
List<Object> get props => [WHModel];
|
||||
}
|
||||
|
||||
class ChangeSwitchStatusEvent extends WaterHeaterState {
|
||||
final bool value;
|
||||
final String deviceId;
|
||||
const ChangeSwitchStatusEvent({required this.value, this.deviceId = ''});
|
||||
@override
|
||||
List<Object> get props => [value, deviceId];
|
||||
}
|
||||
|
||||
class ChangeSlidingSegmentState extends WaterHeaterState {
|
||||
final int value;
|
||||
|
||||
const ChangeSlidingSegmentState({required this.value});
|
||||
|
||||
@override
|
||||
List<Object> get props => [value];
|
||||
}
|
@ -62,6 +62,8 @@ class DeviceModel {
|
||||
tempIcon = Assets.oneGang;
|
||||
} else if (type == DeviceType.TwoGang) {
|
||||
tempIcon = Assets.twoGang;
|
||||
}else if (type == DeviceType.WH) {
|
||||
tempIcon = Assets.waterHeaterIcon;
|
||||
} else {
|
||||
tempIcon = Assets.assetsIconsLogo;
|
||||
}
|
||||
|
141
lib/features/devices/model/water_heater.dart
Normal file
141
lib/features/devices/model/water_heater.dart
Normal file
@ -0,0 +1,141 @@
|
||||
//
|
||||
//
|
||||
// import 'package:syncrow_app/features/devices/model/status_model.dart';
|
||||
//
|
||||
// class WHModel {
|
||||
// final int activeTime;
|
||||
// final String category;
|
||||
// final String categoryName;
|
||||
// final int createTime;
|
||||
// final String gatewayId;
|
||||
// final String icon;
|
||||
// final String ip;
|
||||
// final String lat;
|
||||
// final String lon;
|
||||
// final String localKey;
|
||||
// final String model;
|
||||
// final String name;
|
||||
// final String nodeId;
|
||||
// final bool online;
|
||||
// final String ownerId;
|
||||
// final bool sub;
|
||||
// final String timeZone;
|
||||
// final int updateTime;
|
||||
// final String uuid;
|
||||
// final String productUuid;
|
||||
// final String productType;
|
||||
// final String permissionType;
|
||||
//
|
||||
// WHModel({
|
||||
// required this.activeTime,
|
||||
// required this.category,
|
||||
// required this.categoryName,
|
||||
// required this.createTime,
|
||||
// required this.gatewayId,
|
||||
// required this.icon,
|
||||
// required this.ip,
|
||||
// required this.lat,
|
||||
// required this.lon,
|
||||
// required this.localKey,
|
||||
// required this.model,
|
||||
// required this.name,
|
||||
// required this.nodeId,
|
||||
// required this.online,
|
||||
// required this.ownerId,
|
||||
// required this.sub,
|
||||
// required this.timeZone,
|
||||
// required this.updateTime,
|
||||
// required this.uuid,
|
||||
// required this.productUuid,
|
||||
// required this.productType,
|
||||
// required this.permissionType,
|
||||
// });
|
||||
//
|
||||
// // Factory method to create a SmartDevice object from JSON
|
||||
// factory WHModel.fromJson(Map<String, dynamic> json, List<StatusModel> statusModelList) {
|
||||
// return WHModel(
|
||||
// activeTime: json['activeTime'],
|
||||
// category: json['category'],
|
||||
// categoryName: json['categoryName'],
|
||||
// createTime: json['createTime'],
|
||||
// gatewayId: json['gatewayId'],
|
||||
// icon: json['icon'],
|
||||
// ip: json['ip'],
|
||||
// lat: json['lat'],
|
||||
// lon: json['lon'],
|
||||
// localKey: json['localKey'],
|
||||
// model: json['model'],
|
||||
// name: json['name'],
|
||||
// nodeId: json['nodeId'],
|
||||
// online: json['online'],
|
||||
// ownerId: json['ownerId'],
|
||||
// sub: json['sub'],
|
||||
// timeZone: json['timeZone'],
|
||||
// updateTime: json['updateTime'],
|
||||
// uuid: json['uuid'],
|
||||
// productUuid: json['productUuid'],
|
||||
// productType: json['productType'],
|
||||
// permissionType: json['permissionType'],
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// // Method to convert SmartDevice object to JSON
|
||||
// Map<String, dynamic> toJson() {
|
||||
// return {
|
||||
// 'activeTime': activeTime,
|
||||
// 'category': category,
|
||||
// 'categoryName': categoryName,
|
||||
// 'createTime': createTime,
|
||||
// 'gatewayId': gatewayId,
|
||||
// 'icon': icon,
|
||||
// 'ip': ip,
|
||||
// 'lat': lat,
|
||||
// 'lon': lon,
|
||||
// 'localKey': localKey,
|
||||
// 'model': model,
|
||||
// 'name': name,
|
||||
// 'nodeId': nodeId,
|
||||
// 'online': online,
|
||||
// 'ownerId': ownerId,
|
||||
// 'sub': sub,
|
||||
// 'timeZone': timeZone,
|
||||
// 'updateTime': updateTime,
|
||||
// 'uuid': uuid,
|
||||
// 'productUuid': productUuid,
|
||||
// 'productType': productType,
|
||||
// 'permissionType': permissionType,
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
import 'package:syncrow_app/features/devices/model/status_model.dart';
|
||||
|
||||
class WHModel {
|
||||
bool firstSwitch;
|
||||
int firstCountDown;
|
||||
|
||||
WHModel(
|
||||
{required this.firstSwitch,
|
||||
required this.firstCountDown,
|
||||
});
|
||||
|
||||
factory WHModel.fromJson(List<StatusModel> jsonList) {
|
||||
late bool _switch;
|
||||
late int _count;
|
||||
|
||||
|
||||
for (int i = 0; i < jsonList.length; i++) {
|
||||
if (jsonList[i].code == 'switch_1') {
|
||||
_switch = jsonList[i].value ?? false;
|
||||
} else if (jsonList[i].code == 'countdown_1') {
|
||||
_count = jsonList[i].value ?? 0;
|
||||
}
|
||||
}
|
||||
return WHModel(
|
||||
firstSwitch: _switch,
|
||||
firstCountDown: _count,
|
||||
);
|
||||
}
|
||||
}
|
@ -14,11 +14,11 @@ import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface
|
||||
import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_Interface.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_screen.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_Interface.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_screen.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/wall_sensor/wall_sensor_interface.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/ceiling_sensor/ceiling_sensor_interface.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_interface.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/water_heater/water_heater_page.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/utils/context_extension.dart';
|
||||
import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
|
||||
@ -148,6 +148,14 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
|
||||
PageRouteBuilder(
|
||||
pageBuilder: (context, animation1, animation2) =>
|
||||
ThreeGangInterface(gangSwitch: device)));
|
||||
|
||||
|
||||
case DeviceType.WH:
|
||||
Navigator.push(
|
||||
context,
|
||||
PageRouteBuilder(
|
||||
pageBuilder: (context, animation1, animation2) =>
|
||||
WaterHeaterPage(device: device)));
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
@ -0,0 +1,143 @@
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.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/utils/resource_manager/color_manager.dart';
|
||||
|
||||
|
||||
class InchingWidget extends StatefulWidget {
|
||||
const InchingWidget({super.key,this.onDateTimeChanged});
|
||||
final Function(DateTime)? onDateTimeChanged;
|
||||
|
||||
@override
|
||||
State<InchingWidget> createState() => _InchingWidgetState();
|
||||
}
|
||||
|
||||
class _InchingWidgetState extends State<InchingWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool isOn = true; // Boolean state for the ON/OFF toggle
|
||||
return Column(
|
||||
children: [
|
||||
DefaultContainer(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'Inching', // Change text based on state
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
CircleAvatar(
|
||||
backgroundColor: isOn
|
||||
? ColorsManager.secondaryColor.withOpacity(0.6)
|
||||
: Colors.red.withOpacity(0.6), // Change background color based on state
|
||||
child: const Icon(
|
||||
Icons.power_settings_new,
|
||||
color: ColorsManager.onPrimaryColor, // Change icon color
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10,),
|
||||
const Text('Once enabled this feature, each time the device is turned on, it will automatically turn of after a period time as pre-set.'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(right: 30,left: 30),
|
||||
child: Divider(),
|
||||
),
|
||||
Container(
|
||||
child: MinuteSecondPicker()),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(right: 30,left: 30),
|
||||
child: Divider(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
class MinuteSecondPicker extends StatefulWidget {
|
||||
const MinuteSecondPicker({super.key});
|
||||
|
||||
@override
|
||||
_MinuteSecondPickerState createState() => _MinuteSecondPickerState();
|
||||
}
|
||||
|
||||
class _MinuteSecondPickerState extends State<MinuteSecondPicker> {
|
||||
int selectedMinute = 0;
|
||||
int selectedSecond = 0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// Minutes picker
|
||||
Container(
|
||||
height: 80,
|
||||
width: 100,
|
||||
child: CupertinoPicker(
|
||||
itemExtent: 40.0,
|
||||
scrollController: FixedExtentScrollController(initialItem: selectedMinute),
|
||||
onSelectedItemChanged: (int index) {
|
||||
setState(() {
|
||||
selectedMinute = index;
|
||||
});
|
||||
},
|
||||
children: List<Widget>.generate(61, (int index) {
|
||||
return Center(
|
||||
child: BodyLarge(
|
||||
text: index.toString().padLeft(2, '0'),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 30,color: Colors.blue),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
const Text('M'),
|
||||
SizedBox(width: 20),
|
||||
// Seconds picker
|
||||
Container(
|
||||
height: 80,
|
||||
width: 100,
|
||||
child: CupertinoPicker(
|
||||
itemExtent: 40.0,
|
||||
scrollController: FixedExtentScrollController(initialItem: selectedSecond),
|
||||
onSelectedItemChanged: (int index) {
|
||||
setState(() {
|
||||
selectedSecond = index;
|
||||
});
|
||||
},
|
||||
children: List<Widget>.generate(60, (int index) {
|
||||
return Center(
|
||||
child: BodyLarge(
|
||||
text: index.toString().padLeft(2, '0'),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 30,color: Colors.blue),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
const Text('S'),
|
||||
|
||||
],
|
||||
),
|
||||
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_app/features/devices/model/schedule_model.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/empty_schedule.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/generated/assets.dart';
|
||||
|
||||
|
||||
class CirculateListView extends StatelessWidget {
|
||||
final List<ScheduleModel> listSchedule;
|
||||
final Function(String) onDismissed;
|
||||
final Function(String, bool) onToggleSchedule;
|
||||
const CirculateListView({
|
||||
super.key,
|
||||
required this.listSchedule,
|
||||
required this.onDismissed,
|
||||
required this.onToggleSchedule,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: listSchedule.isNotEmpty
|
||||
? SizedBox(
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: listSchedule.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Dismissible(
|
||||
key: Key(listSchedule[index].scheduleId),
|
||||
background: Container(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
decoration: const ShapeDecoration(
|
||||
color: Color(0xFFFF0000),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 10, right: 10),
|
||||
child: SvgPicture.asset(
|
||||
Assets.assetsDeleteIcon,
|
||||
width: 20,
|
||||
height: 22,
|
||||
),
|
||||
),
|
||||
),
|
||||
direction: DismissDirection.endToStart,
|
||||
onDismissed: (direction) {
|
||||
|
||||
onDismissed(listSchedule[index].scheduleId);
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Schedule removed')),
|
||||
);
|
||||
},
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
|
||||
},
|
||||
child: DefaultContainer(
|
||||
padding: const EdgeInsets.all(20),
|
||||
height: MediaQuery.of(context).size.height / 6.4,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
BodyLarge(
|
||||
text: '12:30 AM - 01:30 PM',
|
||||
// text: listSchedule[index].time,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontColor: Colors.black,
|
||||
fontSize: 22,
|
||||
),
|
||||
Text(listSchedule[index].days.join(' ')),
|
||||
// Text('Function ${listSchedule[index].function.value ? "ON" : "OFF"}'),
|
||||
Text('Start Duration: 0h 10m End Duration: 0h 15m'),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: const BodyMedium(
|
||||
text: '',
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
trailing: Transform.scale(
|
||||
scale: .8,
|
||||
child: CupertinoSwitch(
|
||||
value: listSchedule[index].enable,
|
||||
onChanged: (value) {
|
||||
onToggleSchedule(
|
||||
listSchedule[index].scheduleId,
|
||||
value,
|
||||
);
|
||||
},
|
||||
applyTheme: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
: const EmptySchedule()
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,177 @@
|
||||
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class CirculateWidget extends StatelessWidget {
|
||||
final bool isStartEndTime;
|
||||
final DateTime startTime;
|
||||
final DateTime endTime;
|
||||
final List<Map<String, String>> days;
|
||||
final List<String> selectedDays;
|
||||
|
||||
// Callback functions to handle user interactions
|
||||
final Function(bool) onToggleStartEndTime;
|
||||
final Function(DateTime, bool) onTimeChanged;
|
||||
final Function(String) onDaySelected;
|
||||
final Function()? endDuration;
|
||||
final Function()? startDuration;
|
||||
const CirculateWidget({
|
||||
Key? key,
|
||||
required this.isStartEndTime,
|
||||
required this.startTime,
|
||||
required this.endTime,
|
||||
required this.days,
|
||||
required this.selectedDays,
|
||||
required this.onToggleStartEndTime,
|
||||
required this.onTimeChanged,
|
||||
required this.onDaySelected,
|
||||
required this.endDuration,
|
||||
required this.startDuration,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
// Start/End time toggle buttons
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
onToggleStartEndTime(true); // Toggle to Start Time
|
||||
},
|
||||
child: BodyMedium(
|
||||
text: 'Start',
|
||||
fontColor: !isStartEndTime ? Colors.black : Colors.blue,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
onToggleStartEndTime(false); // Toggle to End Time
|
||||
},
|
||||
child: BodyMedium(
|
||||
text: 'End',
|
||||
fontColor: isStartEndTime ? Colors.black : Colors.blue,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
// Time picker based on start/end toggle
|
||||
SizedBox(
|
||||
height: 110,
|
||||
child: CupertinoDatePicker(
|
||||
mode: CupertinoDatePickerMode.time,
|
||||
initialDateTime: isStartEndTime ? startTime : endTime,
|
||||
onDateTimeChanged: (selectedTime) {
|
||||
onTimeChanged(selectedTime, isStartEndTime); // Notify parent of time change
|
||||
},
|
||||
),
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text('Select days to use Smart Mode'),
|
||||
const SizedBox(height: 20),
|
||||
// Days selection as horizontal list
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.10,
|
||||
child: ListView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: days.map((day) {
|
||||
bool isSelected = selectedDays.contains(day['key']);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
onDaySelected(day['key']!); // Notify parent of day selection
|
||||
},
|
||||
child: Container(
|
||||
width: 70,
|
||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: isSelected ? Colors.black : ColorsManager.grayColor,
|
||||
),
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(55),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
day['day']!,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: isSelected ? Colors.black : ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
DefaultContainer(child:
|
||||
Column(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: startDuration,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Start Duration'),
|
||||
Row(
|
||||
children: [
|
||||
Text('0h 0m'),
|
||||
Icon(Icons.arrow_forward_ios_sharp,color:ColorsManager.graysColor,)
|
||||
],
|
||||
),
|
||||
],),
|
||||
),
|
||||
),
|
||||
const Divider(color: ColorsManager.graysColor,),
|
||||
InkWell(
|
||||
onTap: endDuration,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('End Duration'),
|
||||
Row(
|
||||
children: [
|
||||
Text('0h 0m'),
|
||||
Icon(Icons.arrow_forward_ios_sharp,color:ColorsManager.graysColor,)
|
||||
],
|
||||
),
|
||||
],),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,181 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/water_heater.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/water_heater/wh_timer_schedule_screen.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
import 'package:syncrow_app/utils/context_extension.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class WaterHeaterPage extends StatelessWidget {
|
||||
final DeviceModel? device;
|
||||
const WaterHeaterPage({super.key, this.device});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultScaffold(
|
||||
child: BlocProvider(
|
||||
create: (context) =>
|
||||
WaterHeaterBloc(switchCode: 'switch_1', whId: device?.uuid ?? '')
|
||||
..add(const WaterHeaterInitial()),
|
||||
child: BlocBuilder<WaterHeaterBloc, WaterHeaterState>(
|
||||
builder: (context, state) {
|
||||
final waterHeaterBloc = BlocProvider.of<WaterHeaterBloc>(context);
|
||||
WHModel whModel = WHModel(firstCountDown: 0, firstSwitch: false);
|
||||
if (state is LoadingNewSate) {
|
||||
whModel = state.whModel;
|
||||
} else if (state is UpdateState) {
|
||||
whModel = state.whModel;
|
||||
}
|
||||
return state is WHLoadingState
|
||||
? const Center(
|
||||
child: DefaultContainer(
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: CircularProgressIndicator()),
|
||||
)
|
||||
: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
waterHeaterBloc.add(const WaterHeaterInitial());
|
||||
},
|
||||
child: Center(
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
InkWell(
|
||||
overlayColor: MaterialStateProperty.all(
|
||||
Colors.transparent),
|
||||
onTap: () {
|
||||
waterHeaterBloc.add(
|
||||
WaterHeaterSwitch(
|
||||
whSwitch:whModel.firstSwitch
|
||||
),);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
// color: Colors.white.withOpacity(0.1),
|
||||
borderRadius:
|
||||
BorderRadius.circular(890),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color:
|
||||
Colors.white.withOpacity(0.1),
|
||||
blurRadius: 24,
|
||||
offset: const Offset(-5, -5),
|
||||
blurStyle: BlurStyle.outer,
|
||||
),
|
||||
BoxShadow(
|
||||
color:
|
||||
Colors.black.withOpacity(0.11),
|
||||
blurRadius: 25,
|
||||
offset: const Offset(5, 5),
|
||||
blurStyle: BlurStyle.outer,
|
||||
),
|
||||
BoxShadow(
|
||||
color:
|
||||
Colors.black.withOpacity(0.13),
|
||||
blurRadius: 30,
|
||||
offset: const Offset(5, 5),
|
||||
blurStyle: BlurStyle.inner,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: SvgPicture.asset(
|
||||
whModel.firstSwitch
|
||||
? Assets.waterHeaterOn
|
||||
: Assets.waterHeaterOff,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 80),
|
||||
SizedBox(
|
||||
child: Column(
|
||||
children: [
|
||||
Card(
|
||||
elevation: 3,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(100),
|
||||
),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
PageRouteBuilder(
|
||||
pageBuilder: (context, animation1, animation2) =>
|
||||
WHTimerScheduleScreen(
|
||||
switchCode: 'switch_1', device: device!, deviceCode: 'countdown_1',
|
||||
)));
|
||||
},
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: 60,
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
borderRadius:
|
||||
BorderRadius.circular(100),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius:
|
||||
BorderRadius.circular(100),
|
||||
),
|
||||
child: Center(
|
||||
child: Icon(
|
||||
Icons.access_time,
|
||||
color: ColorsManager
|
||||
.primaryColorWithOpacity,
|
||||
size: 25,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
BodySmall(
|
||||
text: "Timer",
|
||||
style: context.bodyMedium.copyWith(
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
|
||||
class WaterHeaterSwitchIcon extends StatelessWidget {
|
||||
const WaterHeaterSwitchIcon({super.key, required this.value, required this.action});
|
||||
|
||||
final bool value;
|
||||
final Function action;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
overlayColor: MaterialStateProperty.all(Colors.transparent),
|
||||
onTap: () {
|
||||
action();
|
||||
},
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(190.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
blurStyle: BlurStyle.inner,
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
spreadRadius: 9,
|
||||
blurRadius: 2,
|
||||
offset: const Offset(3, 1),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: SvgPicture.asset(
|
||||
value ? Assets.waterHeaterOn : Assets.waterHeaterOff,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,416 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/water_heater/Inching_widget.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/water_heater/circulate_list_view.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/water_heater/circulate_widget.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/create_schedule.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/schedule_list.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
|
||||
import 'package:syncrow_app/generated/assets.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/font_manager.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/water_heater_bloc/water_heater_event.dart';
|
||||
|
||||
class WHTimerScheduleScreen extends StatelessWidget {
|
||||
final DeviceModel device;
|
||||
final String deviceCode;
|
||||
final String switchCode;
|
||||
const WHTimerScheduleScreen(
|
||||
{required this.device,
|
||||
required this.deviceCode,
|
||||
required this.switchCode,
|
||||
super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnnotatedRegion(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
|
||||
statusBarIconBrightness: Brightness.light,
|
||||
),
|
||||
child: BlocProvider(
|
||||
create: (context) =>
|
||||
WaterHeaterBloc(switchCode: switchCode, whId: device.uuid ?? '')
|
||||
..add(GetCounterEvent(deviceCode: deviceCode))
|
||||
..add(GetScheduleEvent()),
|
||||
child: BlocBuilder<WaterHeaterBloc, WaterHeaterState>(
|
||||
builder: (context, state) {
|
||||
final waterHeaterBloc = BlocProvider.of<WaterHeaterBloc>(context);
|
||||
Duration duration = Duration.zero;
|
||||
int countNum = 0;
|
||||
if (state is UpdateTimerState) {
|
||||
countNum = state.seconds;
|
||||
} else if (state is TimerRunInProgress) {
|
||||
countNum = state.remainingTime;
|
||||
} else if (state is TimerRunComplete) {
|
||||
countNum = 0;
|
||||
} else if (state is LoadingNewSate) {
|
||||
countNum = 0;
|
||||
}
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvoked: (didPop) {
|
||||
if (!didPop) {
|
||||
waterHeaterBloc.add(OnClose());
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
child: DefaultTabController(
|
||||
length: 4,
|
||||
child: DefaultScaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
centerTitle: true,
|
||||
title: const BodyLarge(
|
||||
text: 'Schedule',
|
||||
fontColor: ColorsManager.primaryColor,
|
||||
fontWeight: FontsManager.bold,
|
||||
),
|
||||
actions: [
|
||||
waterHeaterBloc.createSchedule == true && waterHeaterBloc.selectedTabIndex == 1 ?
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
waterHeaterBloc.add(ScheduleSave());
|
||||
},
|
||||
child: const Text('Save')) : waterHeaterBloc.selectedTabIndex == 1
|
||||
? IconButton(
|
||||
onPressed: () {
|
||||
waterHeaterBloc.toggleCreateSchedule();
|
||||
},
|
||||
icon: const Icon(Icons.add),
|
||||
)
|
||||
: const SizedBox(),
|
||||
waterHeaterBloc.createCirculate == true &&waterHeaterBloc.selectedTabIndex==2 ?
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
waterHeaterBloc.add(ScheduleSave());
|
||||
},
|
||||
child: const Text('Save'))
|
||||
: waterHeaterBloc.selectedTabIndex == 2
|
||||
? IconButton(
|
||||
onPressed: () {
|
||||
waterHeaterBloc.toggleCreateCirculate();
|
||||
},
|
||||
icon: const Icon(Icons.add),
|
||||
)
|
||||
: const SizedBox(),
|
||||
],
|
||||
),
|
||||
child: state is WHLoadingState
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: const ShapeDecoration(
|
||||
color: ColorsManager.onPrimaryColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(30)),
|
||||
),
|
||||
),
|
||||
child: TabBar(
|
||||
indicatorPadding: EdgeInsets.zero,
|
||||
padding: EdgeInsets.zero,
|
||||
labelPadding: EdgeInsets.zero,
|
||||
onTap: (value) {
|
||||
if (value == 0) {
|
||||
if (waterHeaterBloc.createSchedule == true) {
|
||||
waterHeaterBloc.toggleCreateSchedule();
|
||||
}
|
||||
waterHeaterBloc.toggleSelectedIndex(value);
|
||||
} else if (value == 2) {
|
||||
if (waterHeaterBloc.createCirculate == true) {
|
||||
waterHeaterBloc.toggleCreateCirculate();
|
||||
}
|
||||
waterHeaterBloc.toggleSelectedIndex(value);
|
||||
} else {
|
||||
if (waterHeaterBloc.createSchedule == true) {
|
||||
waterHeaterBloc.toggleCreateSchedule();
|
||||
}
|
||||
waterHeaterBloc.toggleSelectedIndex(value);
|
||||
}
|
||||
},
|
||||
indicatorColor: Colors.white,
|
||||
dividerHeight: 0,
|
||||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
indicator: const ShapeDecoration(
|
||||
color: ColorsManager.slidingBlueColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(20)),
|
||||
),
|
||||
),
|
||||
isScrollable: false,
|
||||
labelColor: Colors.white, // Text color when selected
|
||||
unselectedLabelColor: ColorsManager.blackColor, // Text color when not selected
|
||||
tabs: [
|
||||
Tab(
|
||||
icon: SvgPicture.asset(
|
||||
Assets.scheduleTimeIcon,
|
||||
color: waterHeaterBloc.selectedTabIndex == 0
|
||||
? Colors.white
|
||||
: ColorsManager.blackColor, // Change icon color based on selectedIndex
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10),
|
||||
child: BodySmall(
|
||||
text: 'Countdown',
|
||||
style: context.bodySmall.copyWith(
|
||||
color: waterHeaterBloc.selectedTabIndex == 0
|
||||
? Colors.white
|
||||
: ColorsManager
|
||||
.blackColor, // Text color based on selectedTabIndex
|
||||
fontSize: 8,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
icon: SvgPicture.asset(
|
||||
Assets.scheduleCelenderIcon,
|
||||
color: waterHeaterBloc.selectedTabIndex == 1
|
||||
? Colors.white
|
||||
: ColorsManager.blackColor,
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10),
|
||||
child: Text(
|
||||
'Schedule',
|
||||
style: context.bodySmall.copyWith(
|
||||
color: waterHeaterBloc.selectedTabIndex == 1
|
||||
? Colors.white
|
||||
: ColorsManager.blackColor,
|
||||
fontSize: 8,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
icon: SvgPicture.asset(
|
||||
Assets.scheduleCirculateIcon,
|
||||
color: waterHeaterBloc.selectedTabIndex == 2
|
||||
? Colors.white
|
||||
: ColorsManager.blackColor,
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10),
|
||||
child: Text(
|
||||
'Circulate',
|
||||
style: context.bodySmall.copyWith(
|
||||
color: waterHeaterBloc
|
||||
.selectedTabIndex == 2
|
||||
? Colors.white
|
||||
: ColorsManager.blackColor,
|
||||
fontSize: 8,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
icon: SvgPicture.asset(
|
||||
Assets.scheduleInchingIcon,
|
||||
color: waterHeaterBloc
|
||||
.selectedTabIndex == 3
|
||||
? Colors.white
|
||||
: ColorsManager.blackColor,
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10),
|
||||
child: Text(
|
||||
'Inching',
|
||||
style: context.bodySmall.copyWith(
|
||||
color: waterHeaterBloc
|
||||
.selectedTabIndex == 3
|
||||
? Colors.white
|
||||
: ColorsManager.blackColor,
|
||||
fontSize: 8,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
physics:
|
||||
const NeverScrollableScrollPhysics(), // Disable swiping
|
||||
children: [
|
||||
Center(
|
||||
child: Container(
|
||||
child: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
countNum > 0
|
||||
? BodyLarge(
|
||||
text: _formatDuration(
|
||||
countNum),
|
||||
fontColor: ColorsManager
|
||||
.slidingBlueColor,
|
||||
fontSize: 40,
|
||||
)
|
||||
: CupertinoTimerPicker(
|
||||
mode:
|
||||
CupertinoTimerPickerMode
|
||||
.hm,
|
||||
onTimerDurationChanged:
|
||||
(Duration
|
||||
newDuration) {
|
||||
duration = newDuration;
|
||||
},
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (state
|
||||
is LoadingNewSate) {
|
||||
return;
|
||||
}
|
||||
if (countNum > 0) {
|
||||
waterHeaterBloc.add(
|
||||
SetCounterValue(
|
||||
deviceCode:
|
||||
deviceCode,
|
||||
duration: Duration
|
||||
.zero));
|
||||
} else if (duration !=
|
||||
Duration.zero) {
|
||||
waterHeaterBloc.add(
|
||||
SetCounterValue(
|
||||
deviceCode:
|
||||
deviceCode,
|
||||
duration:
|
||||
duration));
|
||||
}
|
||||
},
|
||||
child: SvgPicture.asset(
|
||||
countNum > 0
|
||||
? Assets.pauseIcon
|
||||
: Assets.playIcon)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Column(
|
||||
mainAxisAlignment: waterHeaterBloc
|
||||
.listSchedule.isNotEmpty
|
||||
? MainAxisAlignment.start
|
||||
: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
child: waterHeaterBloc.createSchedule == true
|
||||
? CreateSchedule(
|
||||
onToggleChanged: (bool isOn) {
|
||||
waterHeaterBloc.toggleSchedule = isOn;
|
||||
},
|
||||
onDateTimeChanged: (DateTime dateTime) {
|
||||
waterHeaterBloc.selectedTime = dateTime;
|
||||
},
|
||||
days: waterHeaterBloc.days,
|
||||
selectDays: (List<String>
|
||||
selectedDays) {
|
||||
waterHeaterBloc
|
||||
.selectedDays =
|
||||
selectedDays;
|
||||
},
|
||||
)
|
||||
: Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: ScheduleListView(
|
||||
listSchedule: waterHeaterBloc.listSchedule, // Pass the schedule list here
|
||||
onDismissed:
|
||||
(scheduleId) {
|
||||
waterHeaterBloc.listSchedule.removeWhere(
|
||||
(schedule) => schedule.scheduleId == scheduleId);
|
||||
waterHeaterBloc.add(
|
||||
DeleteScheduleEvent(id: scheduleId));
|
||||
},
|
||||
onToggleSchedule: (scheduleId, isEnabled) {
|
||||
|
||||
waterHeaterBloc.add(ToggleScheduleEvent(
|
||||
id: scheduleId, toggle: isEnabled,
|
||||
));
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Center(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
waterHeaterBloc.createCirculate == true
|
||||
?
|
||||
CirculateWidget(
|
||||
endDuration: () {
|
||||
waterHeaterBloc.add(SelectTimeEvent(context: context, isEffective: false));
|
||||
},
|
||||
startDuration: () {
|
||||
waterHeaterBloc.add(SelectTimeEvent(context: context, isEffective: false));
|
||||
|
||||
},
|
||||
isStartEndTime: true,
|
||||
startTime: DateTime.now(),
|
||||
endTime: DateTime.now(),
|
||||
days: waterHeaterBloc.days,
|
||||
selectedDays: [],
|
||||
onToggleStartEndTime: (c) {},
|
||||
onTimeChanged: (x, f) {
|
||||
},
|
||||
onDaySelected: (p0) {},
|
||||
):CirculateListView(
|
||||
listSchedule: waterHeaterBloc.listSchedule, // Pass the schedule list here
|
||||
onDismissed: (scheduleId) {
|
||||
waterHeaterBloc.listSchedule.removeWhere((schedule) => schedule.scheduleId == scheduleId);
|
||||
waterHeaterBloc.add(DeleteScheduleEvent(id: scheduleId));
|
||||
},
|
||||
onToggleSchedule: (scheduleId, isEnabled) {
|
||||
waterHeaterBloc.add(ToggleScheduleEvent(
|
||||
id: scheduleId, toggle: isEnabled,
|
||||
));
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(children: [
|
||||
SizedBox(height: 20),
|
||||
Container(child: InchingWidget(),),],)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _formatDuration(int seconds) {
|
||||
final hours = (seconds ~/ 3600).toString().padLeft(2, '0');
|
||||
final minutes = ((seconds % 3600) ~/ 60).toString().padLeft(2, '0');
|
||||
final secs = (seconds % 60).toString().padLeft(2, '0');
|
||||
return '$hours:$minutes:$secs';
|
||||
}
|
||||
}
|
@ -1041,4 +1041,16 @@ class Assets {
|
||||
static const String twoGang = "assets/icons/2gang.svg";
|
||||
|
||||
static const String emptySchedule = "assets/icons/emptySchedule.svg";
|
||||
static const String waterHeaterOn = "assets/icons/water_heater_on.svg";
|
||||
static const String waterHeaterOff = "assets/icons/water_heater_off.svg";
|
||||
|
||||
static const String scheduleCelenderIcon = "assets/icons/schedule_celender_icon.svg";
|
||||
static const String scheduleCirculateIcon = "assets/icons/schedule_circulate_icon.svg";
|
||||
static const String scheduleInchingIcon = "assets/icons/schedule_Inching_icon.svg";
|
||||
static const String scheduleTimeIcon = "assets/icons/schedule_time_icon.svg";
|
||||
static const String waterHeaterIcon = "assets/icons/water_heater_icon.svg";
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ class DevicesAPI {
|
||||
static Future<Map<String, dynamic>> controlDevice(
|
||||
DeviceControlModel controlModel, String deviceId) async {
|
||||
try {
|
||||
|
||||
final response = await _httpService.post(
|
||||
path: ApiEndpoints.controlDevice.replaceAll('{deviceUuid}', deviceId),
|
||||
body: controlModel.toJson(),
|
||||
@ -40,6 +39,7 @@ class DevicesAPI {
|
||||
expectedResponseModel: (json) {
|
||||
return json;
|
||||
},
|
||||
|
||||
);
|
||||
return response;
|
||||
} catch (e) {
|
||||
@ -278,17 +278,7 @@ class DevicesAPI {
|
||||
required String code,
|
||||
required bool value,
|
||||
required List<String> days,
|
||||
|
||||
}) async {
|
||||
print( {
|
||||
"category": category,
|
||||
"time": time,
|
||||
"function":{
|
||||
"code": code,
|
||||
"value":value,
|
||||
},
|
||||
"days": days
|
||||
});
|
||||
final response = await _httpService.post(
|
||||
path: ApiEndpoints.saveSchedule.replaceAll('{deviceUuid}', deviceId),
|
||||
showServerMessage: false,
|
||||
|
@ -49,6 +49,7 @@ enum DeviceType {
|
||||
Gateway,
|
||||
CeilingSensor,
|
||||
WallSensor,
|
||||
WH,
|
||||
Other,
|
||||
}
|
||||
|
||||
@ -73,6 +74,7 @@ Map<String, DeviceType> devicesTypesMap = {
|
||||
"2G": DeviceType.TwoGang,
|
||||
"1G": DeviceType.OneGang,
|
||||
"CUR": DeviceType.Curtain,
|
||||
"WH": DeviceType.WH,
|
||||
};
|
||||
Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
|
||||
DeviceType.AC: [
|
||||
@ -185,7 +187,6 @@ Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
|
||||
values: ValueModel.fromJson({"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})
|
||||
),
|
||||
],
|
||||
|
||||
DeviceType.ThreeGang: [
|
||||
FunctionModel(
|
||||
code: 'switch_1', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})),
|
||||
@ -221,6 +222,43 @@ Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
|
||||
{"unit": "%", "min": 0, "max": 100, "scale": 0, "step": 1})
|
||||
),
|
||||
],
|
||||
DeviceType.WH: [
|
||||
FunctionModel(
|
||||
code: 'switch_1',
|
||||
type: functionTypesMap['Boolean'],
|
||||
values: ValueModel.fromJson({})
|
||||
),
|
||||
FunctionModel(
|
||||
code: 'countdown_1',
|
||||
type: functionTypesMap['Integer'],
|
||||
values: ValueModel.fromJson(
|
||||
{"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})
|
||||
),
|
||||
FunctionModel(
|
||||
code: 'relay_status',
|
||||
type: functionTypesMap['Enum'],
|
||||
values: ValueModel.fromJson(
|
||||
{"range": [ "off", "on"]})
|
||||
),
|
||||
FunctionModel(
|
||||
code: 'switch_backlight',
|
||||
type: functionTypesMap['Boolean'],
|
||||
values: ValueModel.fromJson(
|
||||
{})
|
||||
),
|
||||
FunctionModel(
|
||||
code: 'switch_inching',
|
||||
type: functionTypesMap['String'],
|
||||
values: ValueModel.fromJson(
|
||||
{"maxlen": 255,})
|
||||
),
|
||||
FunctionModel(
|
||||
code: 'cycle_timing',
|
||||
type: functionTypesMap['Raw'],
|
||||
values: ValueModel.fromJson(
|
||||
{"maxlen": 255})
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
enum TempModes { hot, cold, wind }
|
||||
|
Reference in New Issue
Block a user