Merge pull request #29 from SyncrowIOT/sep_bug_fixes2

schedule bug fixes,  icons and design fixes
This commit is contained in:
Abdullah
2024-10-01 10:28:57 +03:00
committed by GitHub
18 changed files with 245 additions and 100 deletions

5
assets/icons/ac_lock.svg Normal file
View File

@ -0,0 +1,5 @@
<svg width="25" height="35" viewBox="0 0 25 35" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.3952 0C7.16271 0.00642578 2.92244 4.24662 2.91602 9.47919V15.3125C2.91602 15.7152 3.2425 16.0417 3.64521 16.0417H6.5619C6.9646 16.0417 7.29109 15.7152 7.29109 15.3125V9.47919C7.29102 6.66019 9.57627 4.375 12.3952 4.375C15.2141 4.375 17.4994 6.66019 17.4994 9.47919V15.3125C17.4994 15.7152 17.8259 16.0417 18.2286 16.0417H21.1452C21.5479 16.0417 21.8744 15.7152 21.8744 15.3125V9.47919C21.868 4.24662 17.6277 0.00642578 12.3952 0Z" fill="#455A64"/>
<path d="M3.64581 14.5833H21.1458C23.1593 14.5833 24.7916 16.2155 24.7916 18.2291V31.3541C24.7916 33.3677 23.1593 34.9999 21.1458 34.9999H3.64581C1.63229 34.9999 0 33.3677 0 31.3541V18.2291C0 16.2155 1.63229 14.5833 3.64581 14.5833Z" fill="#2F66D3"/>
<path d="M16.0417 22.6041C16.0501 20.5906 14.4248 18.9514 12.4112 18.9429C10.3977 18.9344 8.75851 20.5598 8.75003 22.5733C8.74415 23.9651 9.53118 25.2388 10.7785 25.8562L10.2156 29.7937C10.1592 30.1924 10.4367 30.5613 10.8355 30.6177C10.8692 30.6225 10.9034 30.6249 10.9375 30.6249H13.8542C14.2569 30.629 14.5866 30.3059 14.5907 29.9032C14.591 29.8661 14.5886 29.8289 14.5833 29.7922L14.0203 25.8547C15.2524 25.2381 16.0337 23.9817 16.0417 22.6041Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -18,6 +18,7 @@ class DefaultButton extends StatelessWidget {
this.height,
this.padding,
this.borderColor,
this.elevation,
});
final void Function()? onPressed;
final Widget child;
@ -33,6 +34,7 @@ class DefaultButton extends StatelessWidget {
final Color? backgroundColor;
final Color? foregroundColor;
final Color? borderColor;
final double? elevation;
@override
Widget build(BuildContext context) {
@ -45,7 +47,9 @@ class DefaultButton extends StatelessWidget {
textStyle: WidgetStateProperty.all(
customTextStyle ??
Theme.of(context).textTheme.bodySmall!.copyWith(
fontSize: 13, color: foregroundColor, fontWeight: FontWeight.normal),
fontSize: 13,
color: foregroundColor,
fontWeight: FontWeight.normal),
),
foregroundColor: WidgetStateProperty.all(
isSecondary
@ -54,7 +58,8 @@ class DefaultButton extends StatelessWidget {
? foregroundColor ?? Colors.white
: Colors.black,
),
backgroundColor: WidgetStateProperty.resolveWith<Color>((Set<WidgetState> states) {
backgroundColor: WidgetStateProperty.resolveWith<Color>(
(Set<WidgetState> states) {
return enabled
? backgroundColor ?? ColorsManager.primaryColor
: Colors.black.withOpacity(0.2);
@ -74,6 +79,7 @@ class DefaultButton extends StatelessWidget {
minimumSize: WidgetStateProperty.all(
const Size.fromHeight(50),
),
elevation: WidgetStateProperty.all(elevation ?? 0),
),
child: SizedBox(
height: height ?? 50,

View File

@ -46,11 +46,11 @@ class AcDeviceBatchControlView extends StatelessWidget
),
children: [
ToggleWidget(
icon: Assets.ac,
deviceId: devicesIds.first,
code: 'switch',
value: state.status.acSwitch,
label: 'ThermoState',
icon: Assets.ac,
onChange: (value) {
context.read<AcBloc>().add(AcBatchControlEvent(
devicesIds: devicesIds,
@ -80,8 +80,7 @@ class AcDeviceBatchControlView extends StatelessWidget
code: 'child_lock',
value: state.status.childLock,
label: 'Child Lock',
icon:
state.status.childLock ? Assets.childLock : Assets.unlock,
icon: state.status.childLock ? Assets.unlock : Assets.acLock,
onChange: (value) {
context.read<AcBloc>().add(AcBatchControlEvent(
devicesIds: devicesIds,

View File

@ -4,10 +4,10 @@ import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_state.dart';
import 'package:syncrow_web/pages/device_managment/ac/view/control_list/ac_mode.dart';
import 'package:syncrow_web/pages/device_managment/ac/view/control_list/ac_toggle.dart';
import 'package:syncrow_web/pages/device_managment/ac/view/control_list/current_temp.dart';
import 'package:syncrow_web/pages/device_managment/ac/view/control_list/fan_speed.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
@ -42,10 +42,21 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
mainAxisSpacing: 12,
),
children: [
AcToggle(
ToggleWidget(
label: 'Thermostat',
value: state.status.acSwitch,
code: 'switch',
deviceId: device.uuid!,
icon: Assets.ac,
onChange: (value) {
context.read<AcBloc>().add(
AcControlEvent(
deviceId: device.uuid!,
code: 'switch',
value: value,
),
);
},
),
CurrentTemp(
currentTemp: state.status.currentTemp,
@ -63,13 +74,21 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
code: 'level',
deviceId: device.uuid!,
),
AcToggle(
value: state.status.childLock,
code: 'child_lock',
ToggleWidget(
deviceId: device.uuid!,
description: 'Child Lock',
icon:
state.status.childLock ? Assets.childLock : Assets.unlock,
code: 'child_lock',
value: state.status.childLock,
label: 'Child Lock',
icon: state.status.childLock ? Assets.unlock : Assets.acLock,
onChange: (value) {
context.read<AcBloc>().add(
AcControlEvent(
deviceId: device.uuid!,
code: 'child_lock',
value: value,
),
);
},
),
],
);

View File

@ -39,16 +39,21 @@ class AcToggle extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipOval(
child: Container(
color: ColorsManager.whiteColors,
child: SvgPicture.asset(
icon ?? Assets.lightPulp,
width: 60,
height: 60,
fit: BoxFit.cover,
Container(
width: 60,
height: 60,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: ColorsManager.whiteColors,
),
)),
padding: const EdgeInsets.all(8),
child: ClipOval(
child: SvgPicture.asset(
icon ?? Assets.lightPulp,
fit: BoxFit.contain,
),
),
),
SizedBox(
height: 20,
width: 35,

View File

@ -37,8 +37,8 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
offlineCount = state.offlineCount;
lowBatteryCount = state.lowBatteryCount;
isControlButtonEnabled = state.isControlButtonEnabled;
selectedDevices =
state.selectedDevice ?? context.read<DeviceManagementBloc>().selectedDevices;
selectedDevices = state.selectedDevice ??
context.read<DeviceManagementBloc>().selectedDevices;
} else if (state is DeviceManagementFiltered) {
devicesToShow = state.filteredDevices;
selectedIndex = state.selectedIndex;
@ -46,8 +46,8 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
offlineCount = state.offlineCount;
lowBatteryCount = state.lowBatteryCount;
isControlButtonEnabled = state.isControlButtonEnabled;
selectedDevices =
state.selectedDevice ?? context.read<DeviceManagementBloc>().selectedDevices;
selectedDevices = state.selectedDevice ??
context.read<DeviceManagementBloc>().selectedDevices;
} else if (state is DeviceManagementInitial) {
devicesToShow = [];
selectedIndex = 0;
@ -61,13 +61,15 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
'Low Battery ($lowBatteryCount)',
];
final buttonLabel = (selectedDevices.length > 1) ? 'Batch Control' : 'Control';
final buttonLabel =
(selectedDevices.length > 1) ? 'Batch Control' : 'Control';
return Column(
children: [
Container(
padding:
isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
padding: isLargeScreenSize(context)
? const EdgeInsets.all(30)
: const EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -76,7 +78,9 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
tabs: tabs,
selectedIndex: selectedIndex,
onTabChanged: (index) {
context.read<DeviceManagementBloc>().add(SelectedFilterChanged(index));
context
.read<DeviceManagementBloc>()
.add(SelectedFilterChanged(index));
},
),
const SizedBox(height: 20),
@ -98,12 +102,14 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
),
);
} else if (selectedDevices.length > 1) {
final productTypes =
selectedDevices.map((device) => device.productType).toSet();
final productTypes = selectedDevices
.map((device) => device.productType)
.toSet();
if (productTypes.length == 1) {
showDialog(
context: context,
builder: (context) => DeviceBatchControlDialog(
builder: (context) =>
DeviceBatchControlDialog(
devices: selectedDevices,
),
);
@ -117,7 +123,9 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
color: isControlButtonEnabled ? Colors.white : Colors.grey,
color: isControlButtonEnabled
? Colors.white
: Colors.grey,
),
),
),
@ -136,7 +144,9 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
cellDecoration: containerDecoration,
onRowSelected: (index, isSelected, row) {
final selectedDevice = devicesToShow[index];
context.read<DeviceManagementBloc>().add(SelectDevice(selectedDevice));
context
.read<DeviceManagementBloc>()
.add(SelectDevice(selectedDevice));
},
withCheckBox: true,
size: context.screenSize,
@ -154,21 +164,25 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
],
data: devicesToShow.map((device) {
return [
device.categoryName ?? '',
device.name ?? '',
device.categoryName ?? '',
device.uuid ?? '',
device.unit?.name ?? '',
device.room?.name ?? '',
device.batteryLevel != null ? '${device.batteryLevel}%' : '-',
formatDateTime(
DateTime.fromMillisecondsSinceEpoch((device.createTime ?? 0) * 1000)),
device.batteryLevel != null
? '${device.batteryLevel}%'
: '-',
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
(device.createTime ?? 0) * 1000)),
device.online == true ? 'Online' : 'Offline',
formatDateTime(
DateTime.fromMillisecondsSinceEpoch((device.updateTime ?? 0) * 1000)),
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
(device.updateTime ?? 0) * 1000)),
];
}).toList(),
onSelectionChanged: (selectedRows) {
context.read<DeviceManagementBloc>().add(UpdateSelection(selectedRows));
context
.read<DeviceManagementBloc>()
.add(UpdateSelection(selectedRows));
},
initialSelectedIds: context
.read<DeviceManagementBloc>()

View File

@ -70,8 +70,8 @@ class _DeviceItem extends StatelessWidget {
Container(
width: 60,
height: 60,
decoration: const BoxDecoration(
shape: BoxShape.circle,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
color: ColorsManager.whiteColors,
),
margin: const EdgeInsets.symmetric(horizontal: 4),

View File

@ -80,7 +80,9 @@ class MainDoorSensorControlView extends StatelessWidget
icon: Assets.openCloseDoor,
onTap: () {},
status: status.doorContactState,
textColor: ColorsManager.red,
textColor: status.doorContactState
? ColorsManager.red
: ColorsManager.blackColor,
paddingAmount: 8,
),
IconNameStatusContainer(

View File

@ -1,47 +1,113 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
class FactoryResetWidget extends StatelessWidget {
class FactoryResetWidget extends StatefulWidget {
const FactoryResetWidget({super.key, required this.callFactoryReset});
final Null Function() callFactoryReset;
final Function() callFactoryReset;
@override
State<FactoryResetWidget> createState() => _FactoryResetWidgetState();
}
class _FactoryResetWidgetState extends State<FactoryResetWidget> {
bool _showConfirmation = false;
void _toggleConfirmation() {
setState(() {
_showConfirmation = !_showConfirmation;
});
}
@override
Widget build(BuildContext context) {
return DeviceControlsContainer(
child: GestureDetector(
onTap: callFactoryReset,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ClipOval(
child: Container(
color: ColorsManager.whiteColors,
height: 60,
width: 60,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: SvgPicture.asset(
Assets.factoryReset,
fit: BoxFit.cover,
child: _showConfirmation
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Factory Reset',
style: context.textTheme.titleMedium!.copyWith(
fontWeight: FontWeight.bold,
color: ColorsManager.blackColor,
),
),
),
)),
Text(
'Factory Reset',
style: context.textTheme.titleMedium!.copyWith(
fontWeight: FontWeight.w400,
color: ColorsManager.blackColor,
Text(
'Are you sure?',
style: context.textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor,
),
),
const SizedBox(height: 16),
Row(
children: [
Flexible(
child: DefaultButton(
height: 20,
elevation: 0,
onPressed: _toggleConfirmation,
backgroundColor: ColorsManager.greyColor,
child: Text(
'Cancel',
style: context.textTheme.bodyMedium,
),
),
),
const SizedBox(width: 8),
Flexible(
child: DefaultButton(
height: 20,
elevation: 0,
onPressed: widget.callFactoryReset,
backgroundColor: ColorsManager.red,
child: Text(
'Reset',
style: context.textTheme.bodyMedium!
.copyWith(color: ColorsManager.whiteColors),
),
),
),
],
),
],
)
: GestureDetector(
onTap: _toggleConfirmation,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ClipOval(
child: Container(
color: ColorsManager.whiteColors,
height: 60,
width: 60,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: SvgPicture.asset(
Assets.factoryReset,
fit: BoxFit.cover,
),
),
),
),
Text(
'Factory Reset',
style: context.textTheme.titleMedium!.copyWith(
fontWeight: FontWeight.w400,
color: ColorsManager.blackColor,
),
),
],
),
),
],
),
),
);
}
}

View File

@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/device_managment/all_devices/helper/route_cont
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/format_date_time.dart';
class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
final AllDevicesModel device;
@ -91,8 +92,7 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
],
),
TableRow(children: [
_buildInfoRow('Virtual Address:',
'Area - Street 1 - Building 1 - First Floor'),
_buildInfoRow('Virtual Address:', device.ip ?? '-'),
const SizedBox.shrink(),
]),
TableRow(
@ -103,14 +103,38 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
),
TableRow(
children: [
_buildInfoRow('Installation Date and Time:', '09/08/2024 13:30'),
const SizedBox.shrink(),
_buildInfoRow(
'Installation Date and Time:',
formatDateTime(
DateTime.fromMillisecondsSinceEpoch(
((device.createTime ?? 0) * 1000),
),
),
),
_buildInfoRow(
'Battery Level:',
device.batteryLevel != null
? '${device.batteryLevel ?? 0}%'
: "-",
statusColor: device.batteryLevel != null
? (device.batteryLevel! < 20
? ColorsManager.red
: ColorsManager.green)
: null,
),
],
),
TableRow(
children: [
_buildInfoRow('Status:', 'Online', statusColor: Colors.green),
_buildInfoRow('Last Offline Date and Time:', '-'),
_buildInfoRow(
'Last Offline Date and Time:',
formatDateTime(
DateTime.fromMillisecondsSinceEpoch(
((device.activeTime ?? 0) * 1000),
),
),
),
],
),
],

View File

@ -65,6 +65,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
Emitter<WaterHeaterState> emit,
) {
final currentState = state as WaterHeaterDeviceStatusLoaded;
emit(currentState.copyWith(selectedTime: event.selectedTime));
}

View File

@ -130,7 +130,7 @@ class InitializeAddScheduleEvent extends WaterHeaterEvent {
}
class UpdateSelectedTimeEvent extends WaterHeaterEvent {
final TimeOfDay selectedTime;
final TimeOfDay? selectedTime;
const UpdateSelectedTimeEvent(this.selectedTime);

View File

@ -99,7 +99,7 @@ class WaterHeaterDeviceStatusLoaded extends WaterHeaterState {
isInchingActive: isInchingActive ?? this.isInchingActive,
schedules: schedules ?? this.schedules,
selectedDays: selectedDays ?? this.selectedDays,
selectedTime: selectedTime ?? this.selectedTime,
selectedTime: selectedTime,
functionOn: functionOn ?? this.functionOn,
isEditing: isEditing ?? this.isEditing,
);

View File

@ -11,7 +11,15 @@ class ScheduleDialogHelper {
{ScheduleModel? schedule, int? index, bool? isEdit}) {
final bloc = context.read<WaterHeaterBloc>();
if (schedule != null) {
if (schedule == null) {
bloc.add((const UpdateSelectedTimeEvent(null)));
bloc.add(InitializeAddScheduleEvent(
selectedTime: null,
selectedDays: List.filled(7, false),
functionOn: false,
isEditing: false,
));
} else {
final time = _convertStringToTimeOfDay(schedule.time);
final selectedDays = _convertDaysStringToBooleans(schedule.days);
@ -22,16 +30,6 @@ class ScheduleDialogHelper {
isEditing: true,
index: index,
));
} else {
bloc.add(
const InitializeAddScheduleEvent(
selectedDays: [false, false, false, false, false, false, false],
functionOn: false,
isEditing: false,
index: null,
selectedTime: null,
),
);
}
showDialog(
@ -183,7 +181,7 @@ class ScheduleDialogHelper {
}
static List<bool> _convertDaysStringToBooleans(List<String> selectedDays) {
final daysOfWeek = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
final daysOfWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
List<bool> daysBoolean = List.filled(7, false);
for (int i = 0; i < daysOfWeek.length; i++) {
@ -198,7 +196,7 @@ class ScheduleDialogHelper {
static Widget _buildDayCheckboxes(
BuildContext context, List<bool> selectedDays,
{bool? isEdit}) {
final dayLabels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
final dayLabels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
return Row(
children: List.generate(7, (index) {

View File

@ -62,6 +62,7 @@ class WaterHeaterDeviceControlView extends StatelessWidget
deviceId: device.uuid!,
code: 'switch_1',
value: status.heaterSwitch,
icon: Assets.waterHeater,
label: 'Water Heater',
onChange: (value) {
context.read<WaterHeaterBloc>().add(ToggleWaterHeaterEvent(

View File

@ -24,6 +24,7 @@ class _BuildScheduleViewState extends State<BuildScheduleView> {
@override
Widget build(BuildContext context) {
final bloc = BlocProvider.of<WaterHeaterBloc>(context);
return BlocProvider.value(
value: bloc,
child: Dialog(
@ -51,12 +52,13 @@ class _BuildScheduleViewState extends State<BuildScheduleView> {
if (state.scheduleMode == ScheduleModes.schedule)
ScheduleManagementUI(
state: state,
onAddSchedule: () =>
ScheduleDialogHelper.showAddScheduleDialog(
context,
schedule: null,
index: null,
isEdit: false),
onAddSchedule: () {
ScheduleDialogHelper.showAddScheduleDialog(
context,
schedule: null,
index: null,
isEdit: false);
},
),
if (state.scheduleMode == ScheduleModes.countdown ||
state.scheduleMode == ScheduleModes.inching)

View File

@ -210,7 +210,7 @@ class ScheduleTableWidget extends StatelessWidget {
}
String _getSelectedDays(List<bool> selectedDays) {
final days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
final days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
List<String> selectedDaysStr = [];
for (int i = 0; i < selectedDays.length; i++) {
if (selectedDays[i]) {

View File

@ -166,4 +166,7 @@ class Assets {
//assets/icons/water_heater.svg
static const String waterHeater = 'assets/icons/water_heater.svg';
//assets/icons/ac_lock.svg
static const String acLock = 'assets/icons/ac_lock.svg';
}