mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2026-10-23 09:27:56 +00:00
Refactor AC mode control unit widget
Move fan speed and temperature mode logic to the DevicesCubit for better separation of concerns and improved code readability. Update widget to use BlocBuilder for state management and simplify control logic.
This commit is contained in:
@@ -23,7 +23,7 @@ import 'package:syncrow_app/utils/resource_manager/constants.dart';
|
||||
part 'devices_state.dart';
|
||||
|
||||
class DevicesCubit extends Cubit<DevicesState> {
|
||||
DevicesCubit() : super(DevicesInitial()) {
|
||||
DevicesCubit._() : super(DevicesInitial()) {
|
||||
if (HomeCubit.getInstance().selectedSpace != null) {
|
||||
fetchGroups(HomeCubit.getInstance().selectedSpace!.id!);
|
||||
for (var room in HomeCubit.getInstance().selectedSpace!.rooms!) {
|
||||
@@ -33,16 +33,19 @@ class DevicesCubit extends Cubit<DevicesState> {
|
||||
}
|
||||
bool _isClosed = false;
|
||||
|
||||
// static DevicesCubit? _instance;
|
||||
// static DevicesCubit.get(context) {
|
||||
// // If an instance already exists, return it
|
||||
// _instance ??= DevicesCubit._();
|
||||
// return _instance!;
|
||||
// }
|
||||
static DevicesCubit? _instance;
|
||||
static DevicesCubit getInstance() {
|
||||
// If an instance already exists, return it
|
||||
_instance ??= DevicesCubit._();
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
DeviceModel? selectedDevice;
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_isClosed = true;
|
||||
_instance = null;
|
||||
return super.close();
|
||||
}
|
||||
|
||||
@@ -246,11 +249,28 @@ class DevicesCubit extends Cubit<DevicesState> {
|
||||
emitSafe(DevicesCategoryChanged());
|
||||
}
|
||||
|
||||
deviceControl(DeviceControlModel control) async {
|
||||
emitSafe(DeviceControlLoading());
|
||||
///////////////////////// API CALLS //////////////////////////
|
||||
deviceControl(DeviceControlModel control, String deviceId) async {
|
||||
emitSafe(DeviceControlLoading(
|
||||
code: control.code,
|
||||
));
|
||||
try {
|
||||
await DevicesAPI.controlDevice(control);
|
||||
emitSafe(DeviceControlSuccess());
|
||||
await DevicesAPI.controlDevice(control).then((value) {
|
||||
emitSafe(DeviceControlSuccess(
|
||||
code: control.code,
|
||||
));
|
||||
if (value['result'] ?? false) {
|
||||
Future.delayed(const Duration(milliseconds: 400), () {
|
||||
getDevicesStatues(
|
||||
deviceId,
|
||||
HomeCubit.getInstance().selectedSpace!.rooms!.indexOf(
|
||||
HomeCubit.getInstance().selectedRoom!,
|
||||
),
|
||||
code: control.code,
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
} on DioException catch (e) {
|
||||
emitSafe(DeviceControlError(ServerFailure.fromDioError(e).errMessage));
|
||||
}
|
||||
@@ -297,11 +317,11 @@ class DevicesCubit extends Cubit<DevicesState> {
|
||||
}
|
||||
}
|
||||
|
||||
getDevicesStatues(String deviceId, int roomIndex) async {
|
||||
getDevicesStatues(String deviceId, int roomIndex, {String? code}) async {
|
||||
if (_isClosed) return;
|
||||
|
||||
try {
|
||||
emitSafe(GetDeviceStatusLoading());
|
||||
emitSafe(GetDeviceStatusLoading(code: code));
|
||||
int deviceIndex = HomeCubit.getInstance()
|
||||
.selectedSpace!
|
||||
.rooms![roomIndex]
|
||||
@@ -310,7 +330,8 @@ class DevicesCubit extends Cubit<DevicesState> {
|
||||
|
||||
List<StatusModel> statuses = [];
|
||||
var response = await DevicesAPI.getDeviceStatus(deviceId);
|
||||
print('response : $response');
|
||||
// if (response['result']['status'].length > 4)
|
||||
// print('response : ${response['result']['status'][4]}');
|
||||
|
||||
for (var status in response['result']['status']) {
|
||||
statuses.add(StatusModel.fromJson(status));
|
||||
@@ -321,7 +342,7 @@ class DevicesCubit extends Cubit<DevicesState> {
|
||||
.rooms![roomIndex]
|
||||
.devices![deviceIndex]
|
||||
.status = statuses;
|
||||
emitSafe(GetDeviceStatusSuccess());
|
||||
emitSafe(GetDeviceStatusSuccess(code: code));
|
||||
} on DioException catch (error) {
|
||||
emitSafe(
|
||||
GetDeviceStatusError(ServerFailure.fromDioError(error).errMessage),
|
||||
|
||||
@@ -15,9 +15,17 @@ class ChangeIndex extends DevicesState {}
|
||||
|
||||
// Devices
|
||||
|
||||
class GetDeviceStatusLoading extends DevicesState {}
|
||||
class GetDeviceStatusLoading extends DevicesState {
|
||||
final String? code;
|
||||
|
||||
class GetDeviceStatusSuccess extends DevicesState {}
|
||||
GetDeviceStatusLoading({this.code});
|
||||
}
|
||||
|
||||
class GetDeviceStatusSuccess extends DevicesState {
|
||||
final String? code;
|
||||
|
||||
GetDeviceStatusSuccess({this.code});
|
||||
}
|
||||
|
||||
class GetDeviceStatusError extends DevicesState {
|
||||
final String errorMsg;
|
||||
@@ -44,9 +52,17 @@ class DeviceSwitchChanged extends DevicesState {}
|
||||
class DeviceSelected extends DevicesState {}
|
||||
|
||||
// Device Control
|
||||
class DeviceControlLoading extends DevicesState {}
|
||||
class DeviceControlLoading extends DevicesState {
|
||||
final String? code;
|
||||
|
||||
class DeviceControlSuccess extends DevicesState {}
|
||||
DeviceControlLoading({this.code});
|
||||
}
|
||||
|
||||
class DeviceControlSuccess extends DevicesState {
|
||||
final String? code;
|
||||
|
||||
DeviceControlSuccess({this.code});
|
||||
}
|
||||
|
||||
class DeviceControlError extends DevicesState {
|
||||
final String errorMsg;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class DeviceControlModel {
|
||||
String? deviceId;
|
||||
String? code;
|
||||
bool? value;
|
||||
dynamic value;
|
||||
|
||||
DeviceControlModel({
|
||||
required this.deviceId,
|
||||
|
||||
@@ -24,65 +24,78 @@ class AcInterface extends StatelessWidget {
|
||||
statusBarIconBrightness: Brightness.light,
|
||||
),
|
||||
child: SafeArea(
|
||||
child: Scaffold(
|
||||
backgroundColor: ColorsManager.backgroundColor,
|
||||
extendBodyBehindAppBar: true,
|
||||
extendBody: true,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
centerTitle: true,
|
||||
title: BodyLarge(
|
||||
text: deviceModel.name ?? "",
|
||||
fontColor: ColorsManager.primaryColor,
|
||||
fontWeight: FontsManager.bold,
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
height: MediaQuery.sizeOf(context).height,
|
||||
decoration: const BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(
|
||||
Assets.imagesBackground,
|
||||
child: BlocConsumer<DevicesCubit, DevicesState>(
|
||||
listener: (context, state) {
|
||||
if (state is DeviceControlError) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(state.errorMsg),
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
opacity: 0.4,
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: Constants.appBarHeight,
|
||||
left: Constants.defaultPadding,
|
||||
right: Constants.defaultPadding,
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 380,
|
||||
),
|
||||
child: AcInterfaceTempUnit(
|
||||
deviceModel: deviceModel,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 120,
|
||||
),
|
||||
child: AcInterfaceControls(
|
||||
deviceModel: deviceModel,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
return Scaffold(
|
||||
backgroundColor: ColorsManager.backgroundColor,
|
||||
extendBodyBehindAppBar: true,
|
||||
extendBody: true,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
centerTitle: true,
|
||||
title: BodyLarge(
|
||||
text: deviceModel.name ?? "",
|
||||
fontColor: ColorsManager.primaryColor,
|
||||
fontWeight: FontsManager.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
height: MediaQuery.sizeOf(context).height,
|
||||
decoration: const BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(
|
||||
Assets.imagesBackground,
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
opacity: 0.4,
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: Constants.appBarHeight,
|
||||
left: Constants.defaultPadding,
|
||||
right: Constants.defaultPadding,
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 380,
|
||||
),
|
||||
child: AcInterfaceTempUnit(
|
||||
deviceModel: deviceModel,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 120,
|
||||
),
|
||||
child: AcInterfaceControls(
|
||||
deviceModel: deviceModel,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,79 +1,96 @@
|
||||
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/devices_cubit.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/shared_widgets/default_container.dart';
|
||||
|
||||
import '../../../../../generated/assets.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/constants.dart';
|
||||
|
||||
class ACModeControlUnit extends StatefulWidget {
|
||||
const ACModeControlUnit({
|
||||
super.key,
|
||||
required this.model,
|
||||
required this.acDevice,
|
||||
});
|
||||
|
||||
final DeviceModel model;
|
||||
final DeviceModel acDevice;
|
||||
|
||||
@override
|
||||
State<ACModeControlUnit> createState() => _ACModeControlUnitState();
|
||||
}
|
||||
|
||||
class _ACModeControlUnitState extends State<ACModeControlUnit> {
|
||||
Map<String, String> fanSpeedsMap = {
|
||||
'auto': Assets.iconsFan0,
|
||||
'iconsFan1': Assets.iconsFan1,
|
||||
'iconsFan2': Assets.iconsFan2,
|
||||
'iconsFan3': Assets.iconsFan3,
|
||||
};
|
||||
|
||||
Map<String, String> tempModesMap = {
|
||||
'sunny': Assets.iconsSunnyMode,
|
||||
'cold': Assets.iconsColdMode,
|
||||
'windy': Assets.iconsWindyMode,
|
||||
};
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
//TODO Move the fanSpeeds and tempModes to the Cubit
|
||||
return Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
// widget.model.fanSpeed =
|
||||
// widget.model.fanSpeed == 3 ? 0 : widget.model.fanSpeed + 1;
|
||||
});
|
||||
},
|
||||
child: DefaultContainer(
|
||||
height: 55,
|
||||
child: Center(
|
||||
child: SvgPicture.asset(fanSpeedsMap[widget.model.status
|
||||
.firstWhere((element) => element.code == 'level')
|
||||
.value]!),
|
||||
return BlocBuilder<DevicesCubit, DevicesState>(
|
||||
builder: (context, state) {
|
||||
FanSpeeds fanSpeed = fanSpeedsMap[widget.acDevice.status
|
||||
.firstWhere((element) => element.code == 'level')
|
||||
.value]!;
|
||||
TempModes tempMode = tempModesMap[widget.acDevice.status
|
||||
.firstWhere((element) => element.code == 'mode')
|
||||
.value]!;
|
||||
return Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
// print(
|
||||
// '\n\ncurrentFanSpeed:$fanSpeed \nchanged to:\t${fanSpeedsMap[getNextFanSpeedKey(fanSpeed)]!}\nKey:\t\t\"${reversedFanSpeedsMap[fanSpeedsMap[getNextFanSpeedKey(fanSpeed)]!]!}\"');
|
||||
|
||||
fanSpeed = fanSpeedsMap[getNextFanSpeedKey(fanSpeed)]!;
|
||||
|
||||
DevicesCubit.getInstance().deviceControl(
|
||||
DeviceControlModel(
|
||||
deviceId: widget.acDevice.id,
|
||||
code: 'level',
|
||||
value: reversedFanSpeedsMap[fanSpeed]!),
|
||||
widget.acDevice.id!);
|
||||
},
|
||||
child: DefaultContainer(
|
||||
height: 55,
|
||||
child: Center(
|
||||
child: state is GetDeviceStatusLoading &&
|
||||
state.code == 'level' ||
|
||||
state is DeviceControlSuccess &&
|
||||
state.code == 'level' ||
|
||||
state is DeviceControlLoading &&
|
||||
state.code == 'level'
|
||||
? const CircularProgressIndicator()
|
||||
: SvgPicture.asset(fanSpeedsIconMap[fanSpeed]!)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Flexible(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
// widget.model.tempMode =
|
||||
// widget.model.tempMode == 2 ? 0 : widget.model.tempMode + 1;
|
||||
});
|
||||
},
|
||||
child: DefaultContainer(
|
||||
height: 55,
|
||||
child: Center(
|
||||
child: SvgPicture.asset(tempModesMap[widget.model.status
|
||||
.firstWhere((element) => element.code == 'mode')
|
||||
.value]!),
|
||||
const SizedBox(width: 10),
|
||||
Flexible(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
tempMode = tempModesMap[getNextItem(tempModesMap, tempMode)]!;
|
||||
DevicesCubit.getInstance().deviceControl(
|
||||
DeviceControlModel(
|
||||
deviceId: widget.acDevice.id,
|
||||
code: 'mode',
|
||||
value: reversedTempModesMap[tempMode]!),
|
||||
widget.acDevice.id!);
|
||||
},
|
||||
child: DefaultContainer(
|
||||
height: 55,
|
||||
child: Center(
|
||||
child: state is GetDeviceStatusLoading &&
|
||||
state.code == 'mode' ||
|
||||
state is DeviceControlSuccess &&
|
||||
state.code == 'mode' ||
|
||||
state is DeviceControlLoading &&
|
||||
state.code == 'mode'
|
||||
? const CircularProgressIndicator()
|
||||
: SvgPicture.asset(tempModesIconMap[tempMode]!),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user