push living room refactor

This commit is contained in:
ashrafzarkanisala
2024-08-26 21:46:01 +03:00
parent 191801d9a8
commit 2dc5a1e7ed
12 changed files with 287 additions and 69 deletions

View File

@ -12,7 +12,7 @@ mixin RouteControlsBasedCode {
switch (device.productType) {
case '3G':
return LivingRoomDeviceControl(
device: device,
deviceId: device.uuid!,
);
case 'GW':
return GateWayControls(

View File

@ -11,7 +11,8 @@ import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presen
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
class CeilingSensorControls extends StatelessWidget with HelperResponsiveLayout {
class CeilingSensorControls extends StatelessWidget
with HelperResponsiveLayout {
const CeilingSensorControls({super.key, required this.device});
final AllDevicesModel device;
@ -21,8 +22,8 @@ class CeilingSensorControls extends StatelessWidget with HelperResponsiveLayout
final isLarge = isLargeScreenSize(context);
final isMedium = isMediumScreenSize(context);
return BlocProvider(
create: (context) =>
CeilingSensorBloc(deviceId: device.uuid ?? '')..add(CeilingInitialEvent()),
create: (context) => CeilingSensorBloc(deviceId: device.uuid ?? '')
..add(CeilingInitialEvent()),
child: BlocBuilder<CeilingSensorBloc, CeilingSensorState>(
builder: (context, state) {
if (state is CeilingLoadingInitialState) {
@ -86,14 +87,17 @@ class CeilingSensorControls extends StatelessWidget with HelperResponsiveLayout
),
),
PresenceUpdateData(
value: (state.ceilingSensorModel.noBodyTime.toDouble() / 3600).roundToDouble(),
value:
(state.ceilingSensorModel.noBodyTime.toDouble() / 3600)
.roundToDouble(),
title: 'Nobody Time:',
minValue: 0,
maxValue: 300000,
steps: 5000,
description: 'hr',
action: (int value) =>
context.read<CeilingSensorBloc>().add(CeilingChangeValueEvent(
action: (int value) => context
.read<CeilingSensorBloc>()
.add(CeilingChangeValueEvent(
code: 'none_body_time',
value: value,
))),

View File

@ -34,7 +34,7 @@ class GateWayControls extends StatelessWidget with HelperResponsiveLayout {
: isMedium
? 2
: 1,
mainAxisExtent: 150,
mainAxisExtent: 133,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
),

View File

@ -1,15 +1,21 @@
import 'dart:async';
// ignore_for_file: invalid_use_of_visible_for_testing_member
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
import 'package:syncrow_web/pages/device_managment/living_room_switch/models/living_room_model.dart';
import 'package:syncrow_web/services/devices_mang_api.dart';
part 'living_room_event.dart';
part 'living_room_state.dart';
class LivingRoomBloc extends Bloc<LivingRoomEvent, LivingRoomState> {
LivingRoomBloc() : super(LivingRoomInitial()) {
late LivingRoomStatusModel deviceStatus;
final String deviceId;
Timer? _timer;
LivingRoomBloc({required this.deviceId}) : super(LivingRoomInitial()) {
on<LivingRoomFetchDeviceStatus>(_onFetchDeviceStatus);
on<LivingRoomControl>(_livingRoomControl);
}
@ -20,7 +26,9 @@ class LivingRoomBloc extends Bloc<LivingRoomEvent, LivingRoomState> {
try {
final status =
await DevicesManagementApi().getDeviceStatus(event.deviceId);
emit(LivingRoomDeviceStatusLoaded(status));
deviceStatus =
LivingRoomStatusModel.fromJson(event.deviceId, status.status);
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
} catch (e) {
emit(LivingRoomDeviceManagementError(e.toString()));
}
@ -28,22 +36,84 @@ class LivingRoomBloc extends Bloc<LivingRoomEvent, LivingRoomState> {
FutureOr<void> _livingRoomControl(
LivingRoomControl event, Emitter<LivingRoomState> emit) async {
emit(LivingRoomControlLoading());
try {
final status = Status(code: event.code, value: event.value);
final response =
await DevicesManagementApi().deviceControl(event.deviceId, status);
final oldValue = _getValueByCode(event.code);
if (response) {
await Future.delayed(const Duration(milliseconds: 500));
final newStatus =
await DevicesManagementApi().getDeviceStatus(event.deviceId);
emit(LivingRoomDeviceStatusLoaded(newStatus));
} else {
emit(const LivingRoomControlError('Failed to control the device.'));
_updateLocalValue(event.code, event.value);
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
await _runDebounce(
deviceId: event.deviceId,
code: event.code,
value: event.value,
oldValue: oldValue,
emit: emit,
);
}
Future<void> _runDebounce({
required String deviceId,
required String code,
required dynamic value,
required dynamic oldValue,
required Emitter<LivingRoomState> emit,
}) async {
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(seconds: 1), () async {
try {
final response = await DevicesManagementApi()
.deviceControl(deviceId, Status(code: code, value: value));
if (!response) {
_revertValueAndEmit(deviceId, code, oldValue, emit);
}
} catch (e) {
emit(LivingRoomControlError('Error controlling the device: $e'));
_revertValueAndEmit(deviceId, code, oldValue, emit);
}
});
}
void _revertValueAndEmit(String deviceId, String code, dynamic oldValue,
Emitter<LivingRoomState> emit) {
_updateLocalValue(code, oldValue);
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
emit(const LivingRoomControlError('Failed to control the device.'));
}
void _updateLocalValue(String code, dynamic value) {
switch (code) {
case 'switch_1':
if (value is bool) {
deviceStatus = deviceStatus.copyWith(switch1: value);
}
break;
case 'switch_2':
if (value is bool) {
deviceStatus = deviceStatus.copyWith(switch2: value);
}
break;
case 'switch_3':
if (value is bool) {
deviceStatus = deviceStatus.copyWith(switch3: value);
}
break;
default:
break;
}
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
}
dynamic _getValueByCode(String code) {
switch (code) {
case 'switch_1':
return deviceStatus.switch1;
case 'switch_2':
return deviceStatus.switch2;
case 'switch_3':
return deviceStatus.switch3;
default:
return null;
}
}
}

View File

@ -12,7 +12,7 @@ final class LivingRoomInitial extends LivingRoomState {}
class LivingRoomDeviceStatusLoading extends LivingRoomState {}
class LivingRoomDeviceStatusLoaded extends LivingRoomState {
final DeviceStatus status;
final LivingRoomStatusModel status;
const LivingRoomDeviceStatusLoaded(this.status);
@ -29,8 +29,6 @@ class LivingRoomDeviceManagementError extends LivingRoomState {
List<Object> get props => [message];
}
class LivingRoomControlSuccess extends LivingRoomState {}
class LivingRoomControlError extends LivingRoomState {
final String message;
@ -39,5 +37,3 @@ class LivingRoomControlError extends LivingRoomState {
@override
List<Object> get props => [message];
}
class LivingRoomControlLoading extends LivingRoomState {}

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/device_managment/living_room_switch/control_list/cieling_light.dart';
import 'package:syncrow_web/pages/device_managment/living_room_switch/control_list/spot_light.dart';
import 'package:syncrow_web/pages/device_managment/living_room_switch/control_list/wall_light.dart';
import 'package:syncrow_web/pages/device_managment/living_room_switch/widgets/cieling_light.dart';
import 'package:syncrow_web/pages/device_managment/living_room_switch/widgets/spot_light.dart';
import 'package:syncrow_web/pages/device_managment/living_room_switch/widgets/wall_light.dart';
mixin LivingRoomHelper {
Widget livingRoomControlWidgets(

View File

@ -0,0 +1,56 @@
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
class LivingRoomStatusModel {
final String uuid;
final bool switch1;
final bool switch2;
final bool switch3;
LivingRoomStatusModel({
required this.uuid,
required this.switch1,
required this.switch2,
required this.switch3,
});
factory LivingRoomStatusModel.fromJson(String id, List<Status> jsonList) {
late bool switch1;
late bool switch2;
late bool switch3;
for (var status in jsonList) {
switch (status.code) {
case 'switch_1':
switch1 = status.value ?? false; // default to false if null
break;
case 'switch_2':
switch2 = status.value ?? false; // default to false if null
break;
case 'switch_3':
switch3 = status.value ?? false; // default to false if null
break;
}
}
return LivingRoomStatusModel(
uuid: id,
switch1: switch1,
switch2: switch2,
switch3: switch3,
);
}
LivingRoomStatusModel copyWith({
String? uuid,
bool? switch1,
bool? switch2,
bool? switch3,
}) {
return LivingRoomStatusModel(
uuid: uuid ?? this.uuid,
switch1: switch1 ?? this.switch1,
switch2: switch2 ?? this.switch2,
switch3: switch3 ?? this.switch3,
);
}
}

View File

@ -1,30 +1,30 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
import 'package:syncrow_web/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart';
import 'package:syncrow_web/pages/device_managment/living_room_switch/helper/living_room_helper.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/pages/device_managment/living_room_switch/models/living_room_model.dart';
import 'package:syncrow_web/pages/device_managment/living_room_switch/widgets/living_toggle_widget.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
class LivingRoomDeviceControl extends StatelessWidget with LivingRoomHelper {
const LivingRoomDeviceControl({super.key, required this.device});
class LivingRoomDeviceControl extends StatelessWidget
with HelperResponsiveLayout {
final String deviceId;
final AllDevicesModel device;
const LivingRoomDeviceControl({super.key, required this.deviceId});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) =>
LivingRoomBloc()..add(LivingRoomFetchDeviceStatus(device.uuid!)),
create: (context) => LivingRoomBloc(deviceId: deviceId)
..add(LivingRoomFetchDeviceStatus(deviceId)),
child: BlocBuilder<LivingRoomBloc, LivingRoomState>(
builder: (context, state) {
if (state is LivingRoomDeviceStatusLoading) {
return const Center(child: CircularProgressIndicator());
} else if (state is LivingRoomDeviceStatusLoaded) {
return _buildStatusControls(state.status.status);
} else if ((state is LivingRoomDeviceManagementError) ||
(state is LivingRoomControlError)) {
return const Center(child: Text('Error fetching status'));
return _buildStatusControls(context, state.status);
} else if (state is LivingRoomDeviceManagementError ||
state is LivingRoomControlError) {
return Center(child: Text(state.toString()));
} else {
return const Center(child: CircularProgressIndicator());
}
@ -33,32 +33,44 @@ class LivingRoomDeviceControl extends StatelessWidget with LivingRoomHelper {
);
}
Widget _buildStatusControls(List<Status> statuses) {
return GridView.builder(
padding: const EdgeInsets.symmetric(horizontal: 40),
Widget _buildStatusControls(
BuildContext context, LivingRoomStatusModel status) {
final isLarge = isLargeScreenSize(context);
final isMedium = isMediumScreenSize(context);
return GridView(
padding: const EdgeInsets.symmetric(horizontal: 50),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: isLarge
? 3
: isMedium
? 2
: 1,
mainAxisExtent: 133,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
),
itemCount: 3,
itemBuilder: (context, index) {
final status = statuses[index];
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: ColorsManager.greyColor.withOpacity(0.2),
border: Border.all(color: ColorsManager.boxDivider),
children: [
ToggleWidget(
value: status.switch1,
code: 'switch_1',
deviceId: deviceId,
label: 'Wall Light',
),
padding: const EdgeInsets.all(16),
child: livingRoomControlWidgets(
value: status.value, code: status.code, deviceId: device.uuid!),
);
},
ToggleWidget(
value: status.switch2,
code: 'switch_2',
deviceId: deviceId,
label: 'Ceiling Light',
),
ToggleWidget(
value: status.switch3,
code: 'switch_3',
deviceId: deviceId,
label: 'Spotlight',
),
],
);
}
}

View File

@ -0,0 +1,80 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
class ToggleWidget extends StatelessWidget {
final bool value;
final String code;
final String deviceId;
final String label;
const ToggleWidget({
super.key,
required this.value,
required this.code,
required this.deviceId,
required this.label,
});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: ColorsManager.greyColor.withOpacity(0.2),
border: Border.all(color: ColorsManager.boxDivider),
),
padding: const EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ClipOval(
child: Container(
color: ColorsManager.whiteColors,
child: SvgPicture.asset(
Assets.lightPulp,
width: 60,
height: 60,
fit: BoxFit.cover,
),
)),
SizedBox(
height: 20,
width: 35,
child: CupertinoSwitch(
value: value,
activeColor: ColorsManager.dialogBlueTitle,
onChanged: (newValue) {
context.read<LivingRoomBloc>().add(
LivingRoomControl(
deviceId: deviceId,
code: code,
value: newValue,
),
);
},
),
),
],
),
const Spacer(),
Text(
label,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
],
),
);
}
}