count_down_ac

This commit is contained in:
mohammad
2025-01-08 17:17:52 +03:00
parent cff8c4728c
commit 7a22bb4bc8
18 changed files with 779 additions and 99 deletions

View File

@ -1,4 +1,5 @@
import 'dart:io'; import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart';
@ -55,7 +56,8 @@ class HomeCubit extends Cubit<HomeState> {
Future fetchUserInfo() async { Future fetchUserInfo() async {
try { try {
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey); var uuid =
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
user = await ProfileApi().fetchUserInfo(uuid); user = await ProfileApi().fetchUserInfo(uuid);
emit(HomeUserInfoLoaded(user!)); // Emit state after fetching user info emit(HomeUserInfoLoaded(user!)); // Emit state after fetching user info
} catch (e) { } catch (e) {
@ -123,7 +125,9 @@ class HomeCubit extends Cubit<HomeState> {
return; return;
} }
var userUuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ?? ''; var userUuid =
await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ??
'';
if (userUuid.isNotEmpty) { if (userUuid.isNotEmpty) {
await OneSignal.login(userUuid); await OneSignal.login(userUuid);
} }
@ -219,7 +223,8 @@ class HomeCubit extends Cubit<HomeState> {
//////////////////////////////////////// API //////////////////////////////////////// //////////////////////////////////////// API ////////////////////////////////////////
generateInvitation(SpaceModel unit) async { generateInvitation(SpaceModel unit) async {
try { try {
final invitationCode = await SpacesAPI.generateInvitationCode(unit.id, unit.community.uuid); final invitationCode =
await SpacesAPI.generateInvitationCode(unit.id, unit.community.uuid);
if (invitationCode.isNotEmpty) { if (invitationCode.isNotEmpty) {
Share.share('The invitation code is $invitationCode'); Share.share('The invitation code is $invitationCode');
CustomSnackBar.displaySnackBar( CustomSnackBar.displaySnackBar(
@ -235,7 +240,9 @@ class HomeCubit extends Cubit<HomeState> {
Future<bool> joinAUnit(String code) async { Future<bool> joinAUnit(String code) async {
try { try {
var userUuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ?? ''; var userUuid =
await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ??
'';
Map<String, String> body = {'inviteCode': code}; Map<String, String> body = {'inviteCode': code};
final success = await SpacesAPI.joinUnit(userUuid, body); final success = await SpacesAPI.joinUnit(userUuid, body);
@ -271,7 +278,8 @@ class HomeCubit extends Cubit<HomeState> {
fetchRoomsByUnitId(SpaceModel space) async { fetchRoomsByUnitId(SpaceModel space) async {
emitSafe(GetSpaceRoomsLoading()); emitSafe(GetSpaceRoomsLoading());
try { try {
space.subspaces = await SpacesAPI.getSubSpaceBySpaceId(space.community.uuid, space.id); space.subspaces =
await SpacesAPI.getSubSpaceBySpaceId(space.community.uuid, space.id);
} catch (failure) { } catch (failure) {
emitSafe(GetSpaceRoomsError(failure.toString())); emitSafe(GetSpaceRoomsError(failure.toString()));
return; return;
@ -283,6 +291,28 @@ class HomeCubit extends Cubit<HomeState> {
} }
} }
activationCode(activationCode) async {
try {
emitSafe(GetSpaceRoomsLoading());
var uuid =
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
var res = await SpacesAPI.activationCodeSpace(
activationCode: activationCode, userUuid: uuid);
if (res['success'] == true) {
fetchUserInfo();
fetchUnitsByUserId();
}
emitSafe(GetSpacesSuccess(spaces!));
} on DioException catch (e) {
final errorMessage = e.response?.data['error']['message'];
emitSafe(ActivationError(errMessage: errorMessage));
return errorMessage;
} catch (e) {
emitSafe(ActivationError(errMessage: e.toString()));
return e.toString();
}
}
/////////////////////////////////////// Nav /////////////////////////////////////// /////////////////////////////////////// Nav ///////////////////////////////////////
static int pageIndex = 0; static int pageIndex = 0;
@ -353,7 +383,8 @@ class HomeCubit extends Cubit<HomeState> {
size: 32, size: 32,
), ),
style: ButtonStyle( style: ButtonStyle(
foregroundColor: WidgetStateProperty.all(ColorsManager.textPrimaryColor), foregroundColor:
WidgetStateProperty.all(ColorsManager.textPrimaryColor),
), ),
onPressed: () { onPressed: () {
Navigator.pushNamed( Navigator.pushNamed(
@ -374,7 +405,8 @@ class HomeCubit extends Cubit<HomeState> {
NavigationService.navigatorKey.currentContext! NavigationService.navigatorKey.currentContext!
.read<SmartSceneSelectBloc>() .read<SmartSceneSelectBloc>()
.add(const SmartSceneClearEvent()); .add(const SmartSceneClearEvent());
BlocProvider.of<EffectPeriodBloc>(NavigationService.navigatorKey.currentState!.context) BlocProvider.of<EffectPeriodBloc>(
NavigationService.navigatorKey.currentState!.context)
.add(ResetEffectivePeriod()); .add(ResetEffectivePeriod());
NavigationService.navigatorKey.currentContext! NavigationService.navigatorKey.currentContext!
.read<CreateSceneBloc>() .read<CreateSceneBloc>()
@ -447,7 +479,8 @@ class HomeCubit extends Cubit<HomeState> {
void updateDevice(String deviceId) async { void updateDevice(String deviceId) async {
try { try {
final response = await DevicesAPI.firmwareDevice(deviceId: deviceId, firmwareVersion: '0'); final response = await DevicesAPI.firmwareDevice(
deviceId: deviceId, firmwareVersion: '0');
if (response['success'] ?? false) { if (response['success'] ?? false) {
CustomSnackBar.displaySnackBar('No updates available'); CustomSnackBar.displaySnackBar('No updates available');
} }
@ -455,7 +488,8 @@ class HomeCubit extends Cubit<HomeState> {
} }
} }
BottomNavigationBarItem defaultBottomNavBarItem({required String icon, required String label}) { BottomNavigationBarItem defaultBottomNavBarItem(
{required String icon, required String label}) {
return BottomNavigationBarItem( return BottomNavigationBarItem(
icon: SvgPicture.asset(icon), icon: SvgPicture.asset(icon),
activeIcon: SvgPicture.asset( activeIcon: SvgPicture.asset(

View File

@ -32,6 +32,12 @@ class GetSpacesError extends HomeError {
//get rooms //get rooms
class GetSpaceRoomsLoading extends HomeLoading {} class GetSpaceRoomsLoading extends HomeLoading {}
class ActivationError extends HomeLoading {
final String errMessage;
ActivationError({this.errMessage = ''});
}
class GetSpaceRoomsSuccess extends HomeSuccess { class GetSpaceRoomsSuccess extends HomeSuccess {
final List<SubSpaceModel> rooms; final List<SubSpaceModel> rooms;
@ -58,6 +64,7 @@ class RoomSelected extends HomeState {
class RoomUnSelected extends HomeState {} class RoomUnSelected extends HomeState {}
class NavChangePage extends HomeState {} class NavChangePage extends HomeState {}
// Define new state classes // Define new state classes
class HomeUserInfoLoaded extends HomeState { class HomeUserInfoLoaded extends HomeState {
final UserModel user; final UserModel user;

View File

@ -204,7 +204,7 @@ class AuthCubit extends Cubit<AuthState> {
const FlutterSecureStorage().write( const FlutterSecureStorage().write(
key: UserModel.userUuidKey, key: UserModel.userUuidKey,
value: Token.decodeToken(token.accessToken)['uuid'].toString()); value: Token.decodeToken(token.accessToken)['uuid'].toString());
user = UserModel.fromToken(token); user = UserModel.fromToken(token);
emailController.clear(); emailController.clear();
passwordController.clear(); passwordController.clear();

View File

@ -1,8 +1,39 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:syncrow_app/features/auth/model/token.dart'; import 'package:syncrow_app/features/auth/model/token.dart';
class Role {
final String uuid;
final DateTime createdAt;
final DateTime updatedAt;
final String type;
Role({
required this.uuid,
required this.createdAt,
required this.updatedAt,
required this.type,
});
factory Role.fromJson(Map<String, dynamic> json) {
return Role(
uuid: json['uuid'],
createdAt: DateTime.parse(json['createdAt']),
updatedAt: DateTime.parse(json['updatedAt']),
type: json['type'],
);
}
Map<String, dynamic> toJson() {
return {
'uuid': uuid,
'createdAt': createdAt.toIso8601String(),
'updatedAt': updatedAt.toIso8601String(),
'type': type,
};
}
}
class UserModel { class UserModel {
static String userUuidKey = 'userUuid'; static String userUuidKey = 'userUuid';
final String? uuid; final String? uuid;
@ -16,6 +47,7 @@ class UserModel {
final String? timeZone; final String? timeZone;
final String? regionUuid; final String? regionUuid;
final bool? isAgreementAccepted; final bool? isAgreementAccepted;
final Role? role;
UserModel({ UserModel({
required this.uuid, required this.uuid,
@ -27,8 +59,9 @@ class UserModel {
required this.isEmailVerified, required this.isEmailVerified,
required this.regionUuid, required this.regionUuid,
required this.isAgreementAccepted, required this.isAgreementAccepted,
required this.regionName, // Add this line required this.regionName,
required this.timeZone, // Add this line required this.timeZone,
required this.role,
}); });
factory UserModel.fromJson(Map<String, dynamic> json) { factory UserModel.fromJson(Map<String, dynamic> json) {
@ -41,13 +74,13 @@ class UserModel {
phoneNumber: json['phoneNumber'], phoneNumber: json['phoneNumber'],
isEmailVerified: json['isEmailVerified'], isEmailVerified: json['isEmailVerified'],
isAgreementAccepted: json['isAgreementAccepted'], isAgreementAccepted: json['isAgreementAccepted'],
regionName: json['region']?['regionName'], // Extract regionName regionName: json['region']?['regionName'],
timeZone: json['timeZone']?['timeZoneOffset'], // Extract regionName timeZone: json['timeZone']?['timeZoneOffset'],
regionUuid: json['region']?['uuid'], regionUuid: json['region']?['uuid'],
role: json['role'] != null ? Role.fromJson(json['role']) : null,
); );
} }
//uuid to json
//from token
factory UserModel.fromToken(Token token) { factory UserModel.fromToken(Token token) {
Map<String, dynamic> tempJson = Token.decodeToken(token.accessToken); Map<String, dynamic> tempJson = Token.decodeToken(token.accessToken);
return UserModel( return UserModel(
@ -62,6 +95,7 @@ class UserModel {
regionUuid: null, regionUuid: null,
regionName: tempJson['region']?['regionName'], regionName: tempJson['region']?['regionName'],
timeZone: tempJson['timezone']?['timeZoneOffset'], timeZone: tempJson['timezone']?['timeZoneOffset'],
role: tempJson['role'] != null ? Role.fromJson(tempJson['role']) : null,
); );
} }
@ -74,14 +108,18 @@ class UserModel {
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {
'id': uuid, 'uuid': uuid,
'email': email, 'email': email,
'lastName': lastName,
'firstName': firstName, 'firstName': firstName,
'photoUrl': profilePicture, 'lastName': lastName,
'profilePicture': profilePicture != null ? base64.encode(profilePicture!) : null,
'phoneNumber': phoneNumber, 'phoneNumber': phoneNumber,
'isEmailVerified': isEmailVerified, 'isEmailVerified': isEmailVerified,
'regionUuid': regionUuid,
'isAgreementAccepted': isAgreementAccepted, 'isAgreementAccepted': isAgreementAccepted,
'regionName': regionName,
'timeZone': timeZone,
'role': role?.toJson(),
}; };
} }
} }

View File

@ -14,6 +14,7 @@ import 'package:syncrow_app/utils/resource_manager/constants.dart';
class ACsBloc extends Bloc<AcsEvent, AcsState> { class ACsBloc extends Bloc<AcsEvent, AcsState> {
final String acId; final String acId;
AcStatusModel deviceStatus = AcStatusModel( AcStatusModel deviceStatus = AcStatusModel(
countdown1: 0,
uuid: '', uuid: '',
acSwitch: true, acSwitch: true,
modeString: 'hot', modeString: 'hot',
@ -41,6 +42,12 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
on<IncreaseAllTemp>(_increaseAllTemp); on<IncreaseAllTemp>(_increaseAllTemp);
on<DecreaseAllTemp>(_decreaseAllTemp); on<DecreaseAllTemp>(_decreaseAllTemp);
on<AcUpdated>(_onAcUpdated); on<AcUpdated>(_onAcUpdated);
on<OnClose>(_onClose);
on<GetCounterEvent>(_getCounterValue);
on<SetCounterValue>(_setCounterValue);
on<TickTimer>(_onTickTimer);
// on<SetTimeOutValue>(_setTimeOutAlarm);
} }
void _fetchAcsStatus(AcsInitial event, Emitter<AcsState> emit) async { void _fetchAcsStatus(AcsInitial event, Emitter<AcsState> emit) async {
@ -61,7 +68,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
for (var status in response['status']) { for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status)); statusModelList.add(StatusModel.fromJson(status));
} }
deviceStatus = AcStatusModel.fromJson(response['productUuid'], statusModelList); deviceStatus =
AcStatusModel.fromJson(response['productUuid'], statusModelList);
emit(GetAcStatusState(acStatusModel: deviceStatus)); emit(GetAcStatusState(acStatusModel: deviceStatus));
Future.delayed(const Duration(milliseconds: 500)); Future.delayed(const Duration(milliseconds: 500));
// _listenToChanges(); // _listenToChanges();
@ -74,18 +82,22 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
_listenToChanges() { _listenToChanges() {
try { try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$acId'); DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$acId');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) { stream.listen((DatabaseEvent event) {
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>; Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = []; List<StatusModel> statusList = [];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value'])); statusList
.add(StatusModel(code: element['code'], value: element['value']));
}); });
deviceStatus = AcStatusModel.fromJson(usersMap['productUuid'], statusList); deviceStatus =
AcStatusModel.fromJson(usersMap['productUuid'], statusList);
add(AcUpdated()); add(AcUpdated());
}); });
} catch (_) {} } catch (_) {}
@ -102,12 +114,14 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
HomeCubit.getInstance().selectedSpace?.id ?? '', 'AC'); HomeCubit.getInstance().selectedSpace?.id ?? '', 'AC');
for (int i = 0; i < devicesList.length; i++) { for (int i = 0; i < devicesList.length; i++) {
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = []; List<StatusModel> statusModelList = [];
for (var status in response['status']) { for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status)); statusModelList.add(StatusModel.fromJson(status));
} }
deviceStatusList.add(AcStatusModel.fromJson(response['productUuid'], statusModelList)); deviceStatusList.add(
AcStatusModel.fromJson(response['productUuid'], statusModelList));
} }
_setAllAcsTempsAndSwitches(); _setAllAcsTempsAndSwitches();
} }
@ -129,7 +143,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
emit(AcModifyingState(acStatusModel: deviceStatus)); emit(AcModifyingState(acStatusModel: deviceStatus));
} }
await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'switch', value: acSwitchValue); await _runDeBouncerForOneDevice(
deviceId: event.deviceId, code: 'switch', value: acSwitchValue);
} }
void _changeAllAcSwitch(ChangeAllSwitch event, Emitter<AcsState> emit) async { void _changeAllAcSwitch(ChangeAllSwitch event, Emitter<AcsState> emit) async {
@ -190,7 +205,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
deviceStatus.childLock = lockValue; deviceStatus.childLock = lockValue;
emit(AcModifyingState(acStatusModel: deviceStatus)); emit(AcModifyingState(acStatusModel: deviceStatus));
await _runDeBouncerForOneDevice(deviceId: acId, code: 'child_lock', value: lockValue); await _runDeBouncerForOneDevice(
deviceId: acId, code: 'child_lock', value: lockValue);
} }
void _increaseCoolTo(IncreaseCoolToTemp event, Emitter<AcsState> emit) async { void _increaseCoolTo(IncreaseCoolToTemp event, Emitter<AcsState> emit) async {
@ -218,7 +234,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
emit(AcModifyingState(acStatusModel: deviceStatus)); emit(AcModifyingState(acStatusModel: deviceStatus));
} }
await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'temp_set', value: value); await _runDeBouncerForOneDevice(
deviceId: event.deviceId, code: 'temp_set', value: value);
} }
void _decreaseCoolTo(DecreaseCoolToTemp event, Emitter<AcsState> emit) async { void _decreaseCoolTo(DecreaseCoolToTemp event, Emitter<AcsState> emit) async {
@ -246,7 +263,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
emit(AcModifyingState(acStatusModel: deviceStatus)); emit(AcModifyingState(acStatusModel: deviceStatus));
} }
await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'temp_set', value: value); await _runDeBouncerForOneDevice(
deviceId: event.deviceId, code: 'temp_set', value: value);
} }
void _changeAcMode(ChangeAcMode event, Emitter<AcsState> emit) async { void _changeAcMode(ChangeAcMode event, Emitter<AcsState> emit) async {
@ -268,7 +286,9 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
} }
await _runDeBouncerForOneDevice( await _runDeBouncerForOneDevice(
deviceId: event.deviceId, code: 'mode', value: getACModeString(tempMode)); deviceId: event.deviceId,
code: 'mode',
value: getACModeString(tempMode));
} }
void _changeFanSpeed(ChangeFanSpeed event, Emitter<AcsState> emit) async { void _changeFanSpeed(ChangeFanSpeed event, Emitter<AcsState> emit) async {
@ -281,19 +301,23 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
for (AcStatusModel ac in deviceStatusList) { for (AcStatusModel ac in deviceStatusList) {
if (ac.uuid == event.productId) { if (ac.uuid == event.productId) {
ac.fanSpeedsString = getNextFanSpeedKey(fanSpeed); ac.fanSpeedsString = getNextFanSpeedKey(fanSpeed);
ac.acFanSpeed = AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed)); ac.acFanSpeed =
AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
} }
} }
_emitAcsStatus(emit); _emitAcsStatus(emit);
} else { } else {
emit(AcChangeLoading(acStatusModel: deviceStatus)); emit(AcChangeLoading(acStatusModel: deviceStatus));
deviceStatus.fanSpeedsString = getNextFanSpeedKey(fanSpeed); deviceStatus.fanSpeedsString = getNextFanSpeedKey(fanSpeed);
deviceStatus.acFanSpeed = AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed)); deviceStatus.acFanSpeed =
AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
emit(AcModifyingState(acStatusModel: deviceStatus)); emit(AcModifyingState(acStatusModel: deviceStatus));
} }
await _runDeBouncerForOneDevice( await _runDeBouncerForOneDevice(
deviceId: event.deviceId, code: 'level', value: getNextFanSpeedKey(fanSpeed)); deviceId: event.deviceId,
code: 'level',
value: getNextFanSpeedKey(fanSpeed));
} }
String getACModeString(TempModes value) { String getACModeString(TempModes value) {
@ -338,7 +362,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
for (int i = 0; i < deviceStatusList.length; i++) { for (int i = 0; i < deviceStatusList.length; i++) {
try { try {
await DevicesAPI.controlDevice( await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: devicesList[i].uuid, code: code, value: value), DeviceControlModel(
deviceId: devicesList[i].uuid, code: code, value: value),
devicesList[i].uuid ?? ''); devicesList[i].uuid ?? '');
} catch (_) { } catch (_) {
await Future.delayed(const Duration(milliseconds: 500)); await Future.delayed(const Duration(milliseconds: 500));
@ -360,7 +385,10 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
_timer = Timer(const Duration(seconds: 1), () async { _timer = Timer(const Duration(seconds: 1), () async {
try { try {
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: allAcsPage ? deviceId : acId, code: code, value: value), DeviceControlModel(
deviceId: allAcsPage ? deviceId : acId,
code: code,
value: value),
allAcsPage ? deviceId : acId); allAcsPage ? deviceId : acId);
if (!response['success']) { if (!response['success']) {
@ -377,7 +405,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
if (value >= 20 && value <= 30) { if (value >= 20 && value <= 30) {
return true; return true;
} else { } else {
emit(const AcsFailedState(errorMessage: 'The temperature must be between 20 and 30')); emit(const AcsFailedState(
errorMessage: 'The temperature must be between 20 and 30'));
emit(GetAllAcsStatusState( emit(GetAllAcsStatusState(
allAcsStatues: deviceStatusList, allAcsStatues: deviceStatusList,
allAcs: devicesList, allAcs: devicesList,
@ -396,4 +425,90 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
allTempSame: allTempSame, allTempSame: allTempSame,
temp: globalTemp)); temp: globalTemp));
} }
void _setCounterValue(SetCounterValue event, Emitter<AcsState> emit) async {
emit(AcsLoadingState());
int seconds = 0;
try {
seconds = event.seconds;
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: acId, code: 'countdown_time', value: event.duration),
acId);
if (response['success'] ?? false) {
deviceStatus.countdown1 = seconds;
emit(UpdateTimerState(seconds: deviceStatus.countdown1));
} else {
emit(const AcsFailedState(errorMessage: 'Something went wrong'));
return;
}
} catch (e) {
emit(AcsFailedState(errorMessage: e.toString()));
return;
}
if (seconds > 0) {
_onStartTimer(seconds);
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
void _getCounterValue(GetCounterEvent event, Emitter<AcsState> emit) async {
try {
emit(AcsLoadingState());
var response = await DevicesAPI.getDeviceStatus(acId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus =
AcStatusModel.fromJson(response['productUuid'], statusModelList);
if (event.deviceCode == 'countdown_time') {
deviceStatus.countdown1 > 0
? _onStartTimer(deviceStatus.countdown1)
: emit(UpdateTimerState(seconds: deviceStatus.countdown1));
}
} catch (e) {
emit(AcsFailedState(errorMessage: e.toString()));
return;
}
}
void _onStartTimer(int seconds) {
_timer?.cancel(); // Cancel any existing timer
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
final remainingTime = seconds - timer.tick;
if (remainingTime > 0) {
if (!isClosed) {
// Check if the Bloc is still active
add(TickTimer(remainingTime: remainingTime));
}
} else {
_timer?.cancel();
if (!isClosed) {
emit(TimerRunComplete());
}
}
});
}
void _onTickTimer(TickTimer event, Emitter<AcsState> emit) {
if (!isClosed) {
// Check if the Bloc is still active
if (event.remainingTime > 0) {
emit(TimerRunInProgress(event.remainingTime));
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
}
void _onClose(OnClose event, Emitter<AcsState> emit) {
_timer?.cancel(); // Cancel the timer
}
} }

View File

@ -14,7 +14,8 @@ class AcSwitch extends AcsEvent {
final bool acSwitch; final bool acSwitch;
final String deviceId; final String deviceId;
final String productId; final String productId;
const AcSwitch({required this.acSwitch, this.deviceId = '', this.productId = ''}); const AcSwitch(
{required this.acSwitch, this.deviceId = '', this.productId = ''});
@override @override
List<Object> get props => [acSwitch, deviceId, productId]; List<Object> get props => [acSwitch, deviceId, productId];
@ -35,7 +36,8 @@ class IncreaseCoolToTemp extends AcsEvent {
final double value; final double value;
final String deviceId; final String deviceId;
final String productId; final String productId;
const IncreaseCoolToTemp({required this.value, this.deviceId = '', this.productId = ''}); const IncreaseCoolToTemp(
{required this.value, this.deviceId = '', this.productId = ''});
@override @override
List<Object> get props => [value, deviceId]; List<Object> get props => [value, deviceId];
@ -46,7 +48,8 @@ class DecreaseCoolToTemp extends AcsEvent {
final String deviceId; final String deviceId;
final String productId; final String productId;
const DecreaseCoolToTemp({required this.value, this.deviceId = '', this.productId = ''}); const DecreaseCoolToTemp(
{required this.value, this.deviceId = '', this.productId = ''});
@override @override
List<Object> get props => [value, deviceId]; List<Object> get props => [value, deviceId];
@ -56,7 +59,8 @@ class ChangeAcMode extends AcsEvent {
final TempModes tempModes; final TempModes tempModes;
final String deviceId; final String deviceId;
final String productId; final String productId;
const ChangeAcMode({required this.tempModes, this.deviceId = '', this.productId = ''}); const ChangeAcMode(
{required this.tempModes, this.deviceId = '', this.productId = ''});
@override @override
List<Object> get props => [tempModes, deviceId, productId]; List<Object> get props => [tempModes, deviceId, productId];
@ -67,7 +71,8 @@ class ChangeFanSpeed extends AcsEvent {
final String deviceId; final String deviceId;
final String productId; final String productId;
const ChangeFanSpeed({required this.fanSpeeds, this.deviceId = '', this.productId = ''}); const ChangeFanSpeed(
{required this.fanSpeeds, this.deviceId = '', this.productId = ''});
@override @override
List<Object> get props => [fanSpeeds, deviceId, productId]; List<Object> get props => [fanSpeeds, deviceId, productId];
@ -104,3 +109,52 @@ class DecreaseAllTemp extends AcsEvent {
@override @override
List<Object> get props => [value]; List<Object> get props => [value];
} }
class SetCounterValue extends AcsEvent {
final int duration;
final String deviceCode;
final int seconds;
const SetCounterValue(
{required this.duration,
required this.deviceCode,
required this.seconds});
@override
List<Object> get props => [duration, deviceCode, seconds];
}
class SetTimeOutValue extends AcsEvent {
final Duration duration;
final String deviceCode;
const SetTimeOutValue({required this.duration, required this.deviceCode});
@override
List<Object> get props => [duration, deviceCode];
}
class StartTimer extends AcsEvent {
final int duration;
const StartTimer(this.duration);
@override
List<Object> get props => [duration];
}
class TickTimer extends AcsEvent {
final int remainingTime;
const TickTimer({required this.remainingTime});
@override
List<Object> get props => [remainingTime];
}
class StopTimer extends AcsEvent {}
class GetCounterEvent extends AcsEvent {
final String deviceCode;
const GetCounterEvent({required this.deviceCode});
@override
List<Object> get props => [deviceCode];
}
class OnClose extends AcsEvent {}

View File

@ -63,3 +63,22 @@ class AcsFailedState extends AcsState {
@override @override
List<Object> get props => [errorMessage]; List<Object> get props => [errorMessage];
} }
class UpdateTimerState extends AcsState {
final int seconds;
const UpdateTimerState({required this.seconds});
@override
List<Object> get props => [seconds];
}
class TimerRunInProgress extends AcsState {
final int remainingTime;
const TimerRunInProgress(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class TimerRunComplete extends AcsState {}

View File

@ -65,7 +65,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
batteryPercentage: 0, batteryPercentage: 0,
); );
void _fetchStatus(GarageDoorInitial event, Emitter<GarageDoorSensorState> emit) async { void _fetchStatus(
GarageDoorInitial event, Emitter<GarageDoorSensorState> emit) async {
emit(GarageDoorLoadingState()); emit(GarageDoorLoadingState());
try { try {
var response = await DevicesAPI.getDeviceStatus(GDId); var response = await DevicesAPI.getDeviceStatus(GDId);
@ -113,8 +114,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
} }
} }
void _toggleClosingReminder( void _toggleClosingReminder(ToggleClosingReminderEvent event,
ToggleClosingReminderEvent event, Emitter<GarageDoorSensorState> emit) async { Emitter<GarageDoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus)); emit(LoadingNewSate(doorSensor: deviceStatus));
try { try {
closingReminder = event.isClosingReminderEnabled; closingReminder = event.isClosingReminderEnabled;
@ -132,7 +133,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
} }
} }
void _toggleDoorAlarm(ToggleDoorAlarmEvent event, Emitter<GarageDoorSensorState> emit) async { void _toggleDoorAlarm(
ToggleDoorAlarmEvent event, Emitter<GarageDoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus)); emit(LoadingNewSate(doorSensor: deviceStatus));
try { try {
doorAlarm = event.isDoorAlarmEnabled; doorAlarm = event.isDoorAlarmEnabled;
@ -150,7 +152,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
} }
} }
DeviceReport recordGroups = DeviceReport(startTime: '0', endTime: '0', data: []); DeviceReport recordGroups =
DeviceReport(startTime: '0', endTime: '0', data: []);
Future<void> fetchLogsForLastMonth( Future<void> fetchLogsForLastMonth(
ReportLogsInitial event, Emitter<GarageDoorSensorState> emit) async { ReportLogsInitial event, Emitter<GarageDoorSensorState> emit) async {
@ -179,14 +182,16 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
_listenToChanges() { _listenToChanges() {
try { try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$GDId'); DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$GDId');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) async { stream.listen((DatabaseEvent event) async {
if (_timer != null) { if (_timer != null) {
await Future.delayed(const Duration(seconds: 2)); await Future.delayed(const Duration(seconds: 2));
} }
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>; Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = []; List<StatusModel> statusList = [];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: true)); statusList.add(StatusModel(code: element['code'], value: true));
@ -261,7 +266,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
deviceId: GDId, deviceId: GDId,
); );
List<dynamic> jsonData = response; List<dynamic> jsonData = response;
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(UpdateState(garageSensor: deviceStatus)); emit(UpdateState(garageSensor: deviceStatus));
} on DioException catch (e) { } on DioException catch (e) {
final errorData = e.response!.data; final errorData = e.response!.data;
@ -272,12 +278,13 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
int? getTimeStampWithoutSeconds(DateTime? dateTime) { int? getTimeStampWithoutSeconds(DateTime? dateTime) {
if (dateTime == null) return null; if (dateTime == null) return null;
DateTime dateTimeWithoutSeconds = DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute); dateTime.day, dateTime.hour, dateTime.minute);
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000; return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
} }
Future toggleChange(ToggleScheduleEvent event, Emitter<GarageDoorSensorState> emit) async { Future toggleChange(
ToggleScheduleEvent event, Emitter<GarageDoorSensorState> emit) async {
try { try {
emit(GarageDoorLoadingState()); emit(GarageDoorLoadingState());
final response = await DevicesAPI.changeSchedule( final response = await DevicesAPI.changeSchedule(
@ -295,7 +302,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
} }
} }
Future deleteSchedule(DeleteScheduleEvent event, Emitter<GarageDoorSensorState> emit) async { Future deleteSchedule(
DeleteScheduleEvent event, Emitter<GarageDoorSensorState> emit) async {
try { try {
emit(GarageDoorLoadingState()); emit(GarageDoorLoadingState());
final response = await DevicesAPI.deleteSchedule( final response = await DevicesAPI.deleteSchedule(
@ -314,13 +322,15 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
} }
} }
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<GarageDoorSensorState> emit) { void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<GarageDoorSensorState> emit) {
emit(GarageDoorLoadingState()); emit(GarageDoorLoadingState());
selectedTabIndex = event.index; selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex)); emit(ChangeSlidingSegmentState(value: selectedTabIndex));
} }
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<GarageDoorSensorState> emit) { void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<GarageDoorSensorState> emit) {
emit(GarageDoorLoadingState()); emit(GarageDoorLoadingState());
createSchedule = !createSchedule; createSchedule = !createSchedule;
selectedDays.clear(); selectedDays.clear();
@ -337,13 +347,16 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
int secondSelected = 0; int secondSelected = 0;
bool toggleDoor = false; bool toggleDoor = false;
Future<void> selectSeconds(SelectSecondsEvent event, Emitter<GarageDoorSensorState> emit) async { Future<void> selectSeconds(
SelectSecondsEvent event, Emitter<GarageDoorSensorState> emit) async {
try { try {
emit(GarageDoorLoadingState()); emit(GarageDoorLoadingState());
secondSelected = event.seconds; secondSelected = event.seconds;
await DevicesAPI.controlDevice( await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: GDId, code: 'tr_timecon', value: secondSelected), GDId); DeviceControlModel(
deviceId: GDId, code: 'tr_timecon', value: secondSelected),
GDId);
emit(UpdateState(garageSensor: deviceStatus)); emit(UpdateState(garageSensor: deviceStatus));
} on DioException catch (e) { } on DioException catch (e) {
final errorData = e.response!.data; final errorData = e.response!.data;
@ -352,12 +365,15 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
} }
} }
openCloseGarageDoor(ToggleDoorEvent event, Emitter<GarageDoorSensorState> emit) async { openCloseGarageDoor(
ToggleDoorEvent event, Emitter<GarageDoorSensorState> emit) async {
emit(GarageDoorLoadingState()); emit(GarageDoorLoadingState());
try { try {
toggleDoor = !event.toggle; toggleDoor = !event.toggle;
await DevicesAPI.controlDevice( await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: GDId, code: 'switch_1', value: toggleDoor), GDId); DeviceControlModel(
deviceId: GDId, code: 'switch_1', value: toggleDoor),
GDId);
add(const GarageDoorInitial()); add(const GarageDoorInitial());
emit(UpdateState(garageSensor: deviceStatus)); emit(UpdateState(garageSensor: deviceStatus));
} on DioException catch (e) { } on DioException catch (e) {
@ -367,13 +383,16 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
} }
} }
void _setCounterValue(SetCounterValue event, Emitter<GarageDoorSensorState> emit) async { void _setCounterValue(
SetCounterValue event, Emitter<GarageDoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus)); emit(LoadingNewSate(doorSensor: deviceStatus));
int seconds = 0; int seconds = 0;
try { try {
seconds = event.duration.inSeconds; seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: GDId, code: 'countdown_1', value: seconds), GDId); DeviceControlModel(
deviceId: GDId, code: 'countdown_1', value: seconds),
GDId);
if (response['success'] ?? false) { if (response['success'] ?? false) {
deviceStatus.countdown1 = seconds; deviceStatus.countdown1 = seconds;
@ -393,7 +412,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
} }
} }
void _getCounterValue(GetCounterEvent event, Emitter<GarageDoorSensorState> emit) async { void _getCounterValue(
GetCounterEvent event, Emitter<GarageDoorSensorState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
var response = await DevicesAPI.getDeviceStatus(GDId); var response = await DevicesAPI.getDeviceStatus(GDId);
@ -434,7 +454,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
List<GroupGarageModel> groupList = []; List<GroupGarageModel> groupList = [];
bool allSwitchesOn = true; bool allSwitchesOn = true;
void _fetchWizardStatus(InitialWizardEvent event, Emitter<GarageDoorSensorState> emit) async { void _fetchWizardStatus(
InitialWizardEvent event, Emitter<GarageDoorSensorState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
devicesList = []; devicesList = [];
@ -444,7 +465,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
HomeCubit.getInstance().selectedSpace?.id ?? '', 'GD'); HomeCubit.getInstance().selectedSpace?.id ?? '', 'GD');
for (int i = 0; i < devicesList.length; i++) { for (int i = 0; i < devicesList.length; i++) {
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = []; List<StatusModel> statusModelList = [];
for (var status in response['status']) { for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status)); statusModelList.add(StatusModel.fromJson(status));
@ -473,7 +495,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
} }
} }
void _groupAllOn(GroupAllOnEvent event, Emitter<GarageDoorSensorState> emit) async { void _groupAllOn(
GroupAllOnEvent event, Emitter<GarageDoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus)); emit(LoadingNewSate(doorSensor: deviceStatus));
try { try {
// Set all switches (firstSwitch and secondSwitch) based on the event value (on/off) // Set all switches (firstSwitch and secondSwitch) based on the event value (on/off)
@ -485,7 +508,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
emit(UpdateGroupState(garageList: groupList, allSwitches: true)); emit(UpdateGroupState(garageList: groupList, allSwitches: true));
// Get a list of all device IDs // Get a list of all device IDs
List<String> allDeviceIds = groupList.map((device) => device.deviceId).toList(); List<String> allDeviceIds =
groupList.map((device) => device.deviceId).toList();
// First call for switch_1 // First call for switch_1
final response = await DevicesAPI.deviceBatchController( final response = await DevicesAPI.deviceBatchController(
@ -505,7 +529,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
} }
} }
void _groupAllOff(GroupAllOffEvent event, Emitter<GarageDoorSensorState> emit) async { void _groupAllOff(
GroupAllOffEvent event, Emitter<GarageDoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus)); emit(LoadingNewSate(doorSensor: deviceStatus));
try { try {
// Set all switches (firstSwitch and secondSwitch) based on the event value (on/off) // Set all switches (firstSwitch and secondSwitch) based on the event value (on/off)
@ -517,7 +542,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
emit(UpdateGroupState(garageList: groupList, allSwitches: false)); emit(UpdateGroupState(garageList: groupList, allSwitches: false));
// Get a list of all device IDs // Get a list of all device IDs
List<String> allDeviceIds = groupList.map((device) => device.deviceId).toList(); List<String> allDeviceIds =
groupList.map((device) => device.deviceId).toList();
// First call for switch_1 // First call for switch_1
final response = await DevicesAPI.deviceBatchController( final response = await DevicesAPI.deviceBatchController(
@ -538,8 +564,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
} }
} }
void _changeFirstWizardSwitch( void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
ChangeFirstWizardSwitchStatusEvent event, Emitter<GarageDoorSensorState> emit) async { Emitter<GarageDoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus)); emit(LoadingNewSate(doorSensor: deviceStatus));
try { try {
bool allSwitchesValue = true; bool allSwitchesValue = true;
@ -552,7 +578,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
} }
}); });
emit(UpdateGroupState(garageList: groupList, allSwitches: allSwitchesValue)); emit(UpdateGroupState(
garageList: groupList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController( final response = await DevicesAPI.deviceBatchController(
code: 'switch_1', code: 'switch_1',
@ -568,13 +595,16 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
} }
} }
void _setTimeOutAlarm(SetTimeOutValue event, Emitter<GarageDoorSensorState> emit) async { void _setTimeOutAlarm(
SetTimeOutValue event, Emitter<GarageDoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus)); emit(LoadingNewSate(doorSensor: deviceStatus));
int seconds = 0; int seconds = 0;
try { try {
seconds = event.duration.inSeconds; seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: GDId, code: 'countdown_alarm', value: seconds), GDId); DeviceControlModel(
deviceId: GDId, code: 'countdown_alarm', value: seconds),
GDId);
if (response['success'] ?? false) { if (response['success'] ?? false) {
deviceStatus.countdownAlarm = seconds; deviceStatus.countdownAlarm = seconds;

View File

@ -11,12 +11,14 @@ class AcStatusModel {
bool childLock; bool childLock;
late TempModes acMode; late TempModes acMode;
late FanSpeeds acFanSpeed; late FanSpeeds acFanSpeed;
int countdown1;
AcStatusModel( AcStatusModel(
{required this.uuid, {required this.uuid,
required this.acSwitch, required this.acSwitch,
required this.modeString, required this.modeString,
required this.tempSet, required this.tempSet,
required this.countdown1,
required this.currentTemp, required this.currentTemp,
required this.fanSpeedsString, required this.fanSpeedsString,
required this.childLock}) { required this.childLock}) {
@ -30,6 +32,7 @@ class AcStatusModel {
late int _tempSet; late int _tempSet;
late int _currentTemp; late int _currentTemp;
late String _fanSpeeds; late String _fanSpeeds;
late int _countdown1;
late bool _childLock; late bool _childLock;
for (int i = 0; i < jsonList.length; i++) { for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'switch') { if (jsonList[i].code == 'switch') {
@ -44,6 +47,8 @@ class AcStatusModel {
_fanSpeeds = jsonList[i].value ?? 210; _fanSpeeds = jsonList[i].value ?? 210;
} else if (jsonList[i].code == 'child_lock') { } else if (jsonList[i].code == 'child_lock') {
_childLock = jsonList[i].value ?? false; _childLock = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'countdown_time') {
_countdown1 = jsonList[i].value ?? 0;
} }
} }
return AcStatusModel( return AcStatusModel(
@ -53,6 +58,7 @@ class AcStatusModel {
tempSet: _tempSet, tempSet: _tempSet,
currentTemp: _currentTemp, currentTemp: _currentTemp,
fanSpeedsString: _fanSpeeds, fanSpeedsString: _fanSpeeds,
countdown1: _countdown1,
childLock: _childLock); childLock: _childLock);
} }

View File

@ -0,0 +1,52 @@
import 'package:flutter/material.dart';
class CustomHalfHourPicker extends StatefulWidget {
final Function(double) onValueChanged;
const CustomHalfHourPicker({Key? key, required this.onValueChanged})
: super(key: key);
@override
_CustomHalfHourPickerState createState() => _CustomHalfHourPickerState();
}
class _CustomHalfHourPickerState extends State<CustomHalfHourPicker> {
double selectedValue = 0.0;
@override
Widget build(BuildContext context) {
return SizedBox(
height: 200,
child: ListWheelScrollView.useDelegate(
itemExtent: 50,
perspective: 0.005,
physics: const FixedExtentScrollPhysics(),
overAndUnderCenterOpacity: 0.3,
onSelectedItemChanged: (index) {
setState(() {
selectedValue =
index * 0.5; // Convert index to half-hour increments
widget.onValueChanged(selectedValue);
});
},
childDelegate: ListWheelChildBuilderDelegate(
builder: (context, index) {
if (index < 0 || index > 48)
return null; // Limit to 24.0 (48 * 0.5)
return Center(
child: Text(
(index * 0.5)
.toStringAsFixed(1), // Display value as 0.0, 0.5, etc.
style: const TextStyle(
fontSize: 25,
color: Colors.black,
fontWeight: FontWeight.w800),
),
);
},
childCount: 49, // 0.0 to 24.0 (inclusive)
),
),
);
}
}

View File

@ -28,6 +28,7 @@ class AcInterface extends StatelessWidget {
}, },
builder: (context, state) { builder: (context, state) {
AcStatusModel statusModel = AcStatusModel( AcStatusModel statusModel = AcStatusModel(
countdown1: 0,
uuid: ac.uuid ?? '', uuid: ac.uuid ?? '',
acSwitch: true, acSwitch: true,
modeString: 'hot', modeString: 'hot',

View File

@ -7,11 +7,13 @@ import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_state.dart';
import 'package:syncrow_app/features/devices/model/ac_model.dart'; import 'package:syncrow_app/features/devices/model/ac_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_mode_control_unit.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_mode_control_unit.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_timer_page.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
class AcInterfaceControls extends StatelessWidget { class AcInterfaceControls extends StatelessWidget {
const AcInterfaceControls({super.key, required this.deviceModel, required this.deviceStatus}); const AcInterfaceControls(
{super.key, required this.deviceModel, required this.deviceStatus});
final DeviceModel deviceModel; final DeviceModel deviceModel;
final AcStatusModel deviceStatus; final AcStatusModel deviceStatus;
@ -20,8 +22,9 @@ class AcInterfaceControls extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<ACsBloc, AcsState>( return BlocBuilder<ACsBloc, AcsState>(
builder: (context, state) { builder: (context, state) {
String lockIconName = String lockIconName = deviceStatus.childLock
deviceStatus.childLock ? Assets.assetsIconsLock : Assets.assetsIconsUnLock; ? Assets.assetsIconsLock
: Assets.assetsIconsUnLock;
return Column( return Column(
children: [ children: [
@ -34,11 +37,22 @@ class AcInterfaceControls extends StatelessWidget {
children: [ children: [
Flexible( Flexible(
child: GestureDetector( child: GestureDetector(
onTap: () {}, onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
AcTimerPage(
device: deviceModel,
deviceCode: deviceModel.type!,
switchCode: '',
)));
},
child: DefaultContainer( child: DefaultContainer(
height: 55, height: 55,
child: Center( child: Center(
child: SvgPicture.asset(Assets.assetsIconsAutomatedClock), child:
SvgPicture.asset(Assets.assetsIconsAutomatedClock),
), ),
), ),
), ),

View File

@ -0,0 +1,170 @@
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/svg.dart';
import 'package:syncrow_app/features/devices/bloc/6_scene_switch_bloc/6_scene_state.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_event.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/CustomHalfHourTimerPicker.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class AcTimerPage extends StatelessWidget {
final DeviceModel device;
final String deviceCode;
final String switchCode;
const AcTimerPage(
{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) => ACsBloc(acId: device.uuid ?? ''),
child: BlocBuilder<ACsBloc, AcsState>(
builder: (context, state) {
final oneGangBloc = BlocProvider.of<ACsBloc>(context);
Duration duration = Duration.zero;
int selectedValue = 0;
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) {
oneGangBloc.add(OnClose());
Navigator.pop(context);
}
},
child: DefaultTabController(
length: 2,
child: DefaultScaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: const BodyLarge(
text: 'Countdown',
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
),
child: state is AcsLoadingState
? const Center(child: CircularProgressIndicator())
: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: MediaQuery.of(context).size.width,
decoration: const ShapeDecoration(
color: ColorsManager.onPrimaryColor,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(30)),
),
),
),
Center(
child: Container(
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
countNum > 0
? BodyLarge(
text: formatDuration(countNum),
fontColor: ColorsManager
.slidingBlueColor,
fontSize: 40,
)
: Container(
child: CustomHalfHourPicker(
onValueChanged: (value) {
selectedValue =
(value * 10).toInt();
if (selectedValue == 5) {
duration = const Duration(
minutes:
30); // 0.5 translates to 30 minutes
countNum =
duration.inSeconds;
} else {
duration = Duration(
minutes: selectedValue *
6); // Each step represents 6 minutes
countNum =
duration.inSeconds;
}
print(
"Selected Value: $selectedValue, Duration: $duration");
},
),
),
GestureDetector(
onTap: () {
if (state is LoadingNewSate) {
return;
}
if (countNum > 0) {
oneGangBloc.add(SetCounterValue(
seconds: countNum,
deviceCode:
'countdown_time',
duration: selectedValue));
} else if (duration !=
Duration.zero) {
oneGangBloc.add(SetCounterValue(
seconds: 0,
deviceCode:
'countdown_time',
duration: selectedValue));
}
},
child: SvgPicture.asset(countNum > 0
? Assets.pauseIcon
: Assets.playIcon)),
],
),
),
),
],
),
)));
},
),
),
);
}
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';
}
}

View File

@ -1,15 +1,142 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
// import 'package:flutter_svg/svg.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
// import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart'; import 'package:flutter_svg/flutter_svg.dart';
// import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
// import 'package:syncrow_app/navigation/routing_constants.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class CreateUnitWidget extends StatelessWidget { class CreateUnitWidget extends StatelessWidget {
const CreateUnitWidget({super.key}); const CreateUnitWidget({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container(); TextEditingController textEditingController = TextEditingController();
return BlocConsumer<HomeCubit, HomeState>(
listener: (context, state) {
if (state is ActivationError) {}
},
builder: (context, state) {
return SingleChildScrollView(
child: Column(
children: [
const Text(
'Join a Space',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700,
color: ColorsManager.secondaryColor),
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.6,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
Assets.assetsIconsMenuIconsHomeManagementIconsJoinAHome,
width: 70,
height: 70,
color: ColorsManager.grayButtonColors,
),
const Padding(
padding: EdgeInsets.symmetric(
vertical: 30,
),
child: BodyMedium(
fontWeight: FontWeight.w400,
textAlign: TextAlign.center,
text: 'Please enter your invitation code'),
),
Column(
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: state is ActivationError
? ColorsManager.red // Red border for error
: ColorsManager
.grayBox, // Default border color
width: 1.5, // Border width
),
borderRadius:
BorderRadius.circular(20.0), // Border radius
),
padding: const EdgeInsets.symmetric(
vertical: 5,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: TextFormField(
validator: (value) {},
controller: textEditingController,
decoration: InputDecoration(
hintText: 'Invitation code',
hintStyle: context.bodyMedium.copyWith(
color: Colors.grey,
),
border: InputBorder.none,
),
),
),
IconButton(
onPressed: () async {
if (textEditingController.text.isEmpty) {
CustomSnackBar.displaySnackBar(
'Please enter the invitation code');
return;
}
//3Hsn4X
if (await HomeCubit.getInstance()
.activationCode(
textEditingController.text)) {
CustomSnackBar.displaySnackBar(
'Done successfully');
Navigator.of(context).pop();
} else {
CustomSnackBar.displaySnackBar(
'Wrong code!');
}
},
icon: const Icon(
Icons.arrow_right_alt,
),
),
],
),
),
state is ActivationError
? Text(
state.errMessage,
style: const TextStyle(
color: ColorsManager.red,
fontWeight: FontWeight.w400),
)
: const SizedBox()
],
),
],
),
),
),
],
),
);
// return state is! GetSpacesLoading
// ? state is! GetSpaceRoomsLoading
// ? HomeCubit.getInstance().pages[HomeCubit.pageIndex]
// : const Center(child: CircularProgressIndicator())
// : const Center(child: CircularProgressIndicator());
},
);
}
}
// return SizedBox( // return SizedBox(
// width: MediaQuery.sizeOf(context).width, // width: MediaQuery.sizeOf(context).width,
// height: MediaQuery.sizeOf(context).height, // height: MediaQuery.sizeOf(context).height,
@ -47,5 +174,5 @@ class CreateUnitWidget extends StatelessWidget {
// ], // ],
// ), // ),
// ); // );
} // }
} // }

View File

@ -63,6 +63,8 @@ abstract class ApiEndpoints {
static const String unitUser = '/unit/user/'; static const String unitUser = '/unit/user/';
static const String invitationCode = static const String invitationCode =
'/projects/{projectUuid}/communities/{communityUuid}/spaces/{unitUuid}/invitation-code'; '/projects/{projectUuid}/communities/{communityUuid}/spaces/{unitUuid}/invitation-code';
static const String activationCode =
'/invite-user/activation';
//PUT //PUT
static const String renameUnit = '/unit/{unitUuid}'; static const String renameUnit = '/unit/{unitUuid}';

View File

@ -1,5 +1,4 @@
import 'dart:io'; import 'dart:io';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart'; import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';

View File

@ -31,8 +31,10 @@ class ServerFailure extends Failure {
{ {
// var document = parser.parse(dioError.response!.data.toString()); // var document = parser.parse(dioError.response!.data.toString());
// var message = document.body!.text; // var message = document.body!.text;
return ServerFailure.fromResponse(dioError.response!.statusCode!, return ServerFailure.fromResponse(
dioError.response?.data['error']['message'] ?? "Something went wrong"); dioError.response!.statusCode!,
dioError.response?.data['error']['message'] ??
"Something went wrong");
} }
case DioExceptionType.cancel: case DioExceptionType.cancel:
return ServerFailure("The request to ApiServer was canceled"); return ServerFailure("The request to ApiServer was canceled");
@ -54,15 +56,7 @@ class ServerFailure extends Failure {
case 403: case 403:
return ServerFailure(responseMessage); return ServerFailure(responseMessage);
case 400: case 400:
List<String> errors = []; return ServerFailure(responseMessage);
if (responseMessage is List) {
for (var error in responseMessage) {
errors.add(error);
}
} else {
return ServerFailure(responseMessage);
}
return ServerFailure(errors.join('\n'));
case 404: case 404:
return ServerFailure(""); return ServerFailure("");
case 500: case 500:

View File

@ -1,3 +1,4 @@
import 'package:dio/dio.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart'; import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/auth/model/user_model.dart'; import 'package:syncrow_app/features/auth/model/user_model.dart';
@ -95,4 +96,21 @@ class SpacesAPI {
); );
return response; return response;
} }
static Future activationCodeSpace({
String? activationCode,
String? userUuid,
}) async {
Map body = {"activationCode": activationCode, "userUuid": userUuid};
final response = await _httpService.post(
path: ApiEndpoints.activationCode,
showServerMessage: true,
body: body,
expectedResponseModel: (json) {
return json;
},
);
return response;
}
} }