Compare commits

..

5 Commits

Author SHA1 Message Date
5aec3d37fb fix password 2024-08-07 17:20:19 +03:00
afe37dd68a Merge pull request #44 from SyncrowIOT/automation_fixes3
Automation fixes3
2024-08-06 15:28:38 +03:00
f83224ce60 Merge pull request #43 from SyncrowIOT/update_door_lock
door lock password update
2024-08-06 15:07:12 +03:00
3f0fcc79aa set default value for tempreture at confirm 2024-08-05 21:39:11 +03:00
33ec234c0d push fixes to days un-select and temp_current normilization 2024-08-05 21:19:07 +03:00
15 changed files with 312 additions and 116 deletions

View File

@ -1,6 +1,7 @@
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_event.dart';
@ -12,6 +13,7 @@ import 'package:syncrow_app/features/devices/model/smart_door_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/features/devices/model/create_temporary_password_model.dart';
import 'package:syncrow_app/features/devices/model/temporary_password_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/hour_picker_dialog.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
@ -32,7 +34,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
on<SetStartEndTimeEvent>(setStartEndTime);
on<ChangeTimeEvent>(changeTime);
on<GeneratePasswordEvent>(generate7DigitNumber);
on<SelectTimeEvent>(selectTime);
on<SelectTimeEvent>(selectTimeOfLinePassword);
on<SelectTimeOnlinePasswordEvent>(selectTimeOnlinePassword);
on<DeletePasswordEvent>(deletePassword);
on<GenerateAndSavePasswordTimeLimitEvent>(generateAndSavePasswordTimeLimited);
on<GenerateAndSavePasswordOneTimeEvent>(generateAndSavePasswordOneTime);
@ -66,7 +69,6 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
return passwordController.text;
}
Future generateAndSavePasswordOneTime (GenerateAndSavePasswordOneTimeEvent event, Emitter<SmartDoorState> emit) async {
try {
if (isSavingPassword) return;
@ -76,6 +78,10 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
ApiResponse pass= ApiResponse.fromJson(res);
passwordController.text =pass.data.offlineTempPassword;
passwordId=pass.data.offlineTempPasswordId;
Future.delayed(const Duration(seconds: 1), () {
Clipboard.setData(ClipboardData(text: passwordController.text));
});
emit(const GeneratePasswordOneTimestate(generated: true));
} catch (_) {
emit(FailedState(errorMessage: _.toString()));
@ -108,6 +114,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
doorLockUuid:deviceId ,
passwordId:passwordId
);
add(InitialOneTimePassword());
add(InitialTimeLimitPassword());
emit(UpdateState(smartDoorModel: deviceStatus));
} catch (e) {
emit(FailedState(errorMessage: e.toString()));
@ -150,6 +158,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
if (response is List) {
timeLimitPasswords = response.map((item) => OfflinePasswordModel.fromJson(item)).toList();
}
emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!));
} catch (e) {
emit(FailedState(errorMessage: e.toString()));
@ -192,7 +201,56 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
emit(UpdateState(smartDoorModel: deviceStatus));
}
Future<void> selectTime(SelectTimeEvent event, Emitter<SmartDoorState> emit) async {
Future<void> selectTimeOfLinePassword(SelectTimeEvent event, Emitter<SmartDoorState> emit) async {
emit(ChangeTimeState());
final DateTime? picked = await showDatePicker(
context: event.context,
initialDate: DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2101),
);
if (picked != null) {
final TimeOfDay? timePicked = await showHourPicker(
context: event.context,
initialTime: TimeOfDay.now(),
);
if (timePicked != null) {
final selectedDateTime = DateTime(
picked.year,
picked.month,
picked.day,
timePicked.hour,
0,
);
final selectedTimestamp = DateTime(
selectedDateTime.year,
selectedDateTime.month,
selectedDateTime.day,
selectedDateTime.hour,
selectedDateTime.minute,
).millisecondsSinceEpoch ~/ 1000; // Divide by 1000 to remove milliseconds
if (event.isEffective) {
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.');
} else {
effectiveTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
effectiveTimeTimeStamp = selectedTimestamp;
}
} else {
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar('Expiration Time cannot be earlier than Effective Time.');
} else {
expirationTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
expirationTimeTimeStamp = selectedTimestamp;
}
}
emit(TimeSelectedState());
}
}
}
Future<void> selectTimeOnlinePassword(SelectTimeOnlinePasswordEvent event, Emitter<SmartDoorState> emit) async {
emit(ChangeTimeState());
final DateTime? picked = await showDatePicker(
context: event.context,
@ -294,16 +352,22 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
try {
isSavingPassword = true;
emit(LoadingInitialState());
var res = await DevicesAPI.generateMultiTimePassword(deviceId: deviceId,
var res = await DevicesAPI.generateMultiTimePassword(
deviceId: deviceId,
effectiveTime: effectiveTimeTimeStamp.toString(),
invalidTime: expirationTimeTimeStamp.toString(), );
invalidTime: expirationTimeTimeStamp.toString(),
);
ApiResponse pass= ApiResponse.fromJson(res);
passwordController.text =pass.data.offlineTempPassword;
passwordId=pass.data.offlineTempPasswordId;
CustomSnackBar.displaySnackBar('Save Successfully');
add(InitialTimeLimitPassword());
Future.delayed(const Duration(seconds: 1), () {
Clipboard.setData(ClipboardData(text: passwordController.text));
});
emit(const GeneratePasswordOneTimestate(generated: true));
} catch (_) {
emit(FailedState(errorMessage: e.toString()));
add(InitialPasswordsPage());
}
finally {
isSavingPassword = false;
@ -328,6 +392,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
CustomSnackBar.displaySnackBar('Password less than 7');
return true;
}
if (passwordController.text.isEmpty) {
CustomSnackBar.displaySnackBar('Password required');
return true;
@ -336,20 +401,24 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
CustomSnackBar.displaySnackBar('Password name required');
return true;
}
if (effectiveTime == 'Select Time' || effectiveTimeTimeStamp == null) {
CustomSnackBar.displaySnackBar('Select effective time');
return true;
}
if (expirationTime == 'Select Time' || expirationTimeTimeStamp == null) {
CustomSnackBar.displaySnackBar('Select expiration time');
return true;
}
if (repeat == true && (endTime == null || startTime == null || selectedDays == null)) {
CustomSnackBar.displaySnackBar('Start Time and End time and the days required ');
return true;
}
return false;
}
bool timeLimitValidate() {
if (effectiveTime == 'Select Time' || effectiveTimeTimeStamp == null) {
@ -392,3 +461,6 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}

View File

@ -53,6 +53,14 @@ class SelectTimeEvent extends SmartDoorEvent {
List<Object> get props => [context,isEffective];
}
class SelectTimeOnlinePasswordEvent extends SmartDoorEvent {
final BuildContext context;
final bool isEffective;
const SelectTimeOnlinePasswordEvent({required this.context,required this.isEffective});
@override
List<Object> get props => [context,isEffective];
}
class ToggleRepeatEvent extends SmartDoorEvent {}
class SetStartEndTimeEvent extends SmartDoorEvent {
final bool val;

View File

@ -0,0 +1,92 @@
import 'package:flutter/material.dart';
class HourPickerDialog extends StatefulWidget {
final TimeOfDay initialTime;
HourPickerDialog({required this.initialTime});
@override
_HourPickerDialogState createState() => _HourPickerDialogState();
}
class _HourPickerDialogState extends State<HourPickerDialog> {
late int _selectedHour;
bool _isPm = false;
@override
void initState() {
super.initState();
_selectedHour = widget.initialTime.hour > 12 ? widget.initialTime.hour - 12 : widget.initialTime.hour;
_isPm = widget.initialTime.period == DayPeriod.pm;
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Select Hour'),
content: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
DropdownButton<int>(
value: _selectedHour,
items: List.generate(12, (index) {
int displayHour = index + 1;
return DropdownMenuItem(
value: displayHour,
child: Text(displayHour.toString()),
);
}),
onChanged: (value) {
setState(() {
_selectedHour = value!;
});
},
),
SizedBox(width: 16.0),
DropdownButton<bool>(
value: _isPm,
items: [
DropdownMenuItem(
value: false,
child: Text('AM'),
),
DropdownMenuItem(
value: true,
child: Text('PM'),
),
],
onChanged: (value) {
setState(() {
_isPm = value!;
});
},
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(null),
child: Text('Cancel'),
),
TextButton(
onPressed: () {
int hour = _isPm ? _selectedHour + 12 : _selectedHour;
Navigator.of(context).pop(TimeOfDay(hour: hour, minute: 0));
},
child: Text('OK'),
),
],
);
}
}
Future<TimeOfDay?> showHourPicker({
required BuildContext context,
required TimeOfDay initialTime,
}) {
return showDialog<TimeOfDay>(
context: context,
builder: (context) => HourPickerDialog(initialTime: initialTime),
);
}

View File

@ -60,7 +60,7 @@ class NameTimeWidget extends StatelessWidget {
child: InkWell(
onTap: () {
BlocProvider.of<SmartDoorBloc>(context).add(SelectTimeEvent(context: context, isEffective: true));
BlocProvider.of<SmartDoorBloc>(context).add(SelectTimeOnlinePasswordEvent(context: context, isEffective: true));
},
child: Text(
BlocProvider.of<SmartDoorBloc>(context).effectiveTime,
@ -92,7 +92,7 @@ class NameTimeWidget extends StatelessWidget {
child: InkWell(
onTap: () {
BlocProvider.of<SmartDoorBloc>(context).add(
SelectTimeEvent(
SelectTimeOnlinePasswordEvent(
context: context, isEffective: false));
},
child: Text(

View File

@ -13,6 +13,7 @@ import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/door_lock_button.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
@ -28,11 +29,8 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(listener: (context, state) {
if (state is FailedState) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.errorMessage),
backgroundColor: Colors.red,
),
CustomSnackBar.displaySnackBar(
state.errorMessage
);
}
if (state is IsRepeatState){
@ -104,6 +102,7 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
Expanded(
child: Row(
children: [
Expanded(
child: BodyLarge(
style: const TextStyle(
@ -114,8 +113,9 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
wordSpacing: 2),
textAlign: TextAlign.center,
text: smartDoorBloc.passwordController.text,
fontSize: 25,
fontSize: 23,
),),
IconButton(
onPressed: () async {
await Clipboard.setData(ClipboardData(
@ -166,7 +166,6 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
],
),
],
),
),
@ -195,9 +194,6 @@ class OfflineOneTimePasswordPage extends StatelessWidget {
onPressed: () async {
if(generated==false){
smartDoorBloc.add(GenerateAndSavePasswordOneTimeEvent(context: context));
await Clipboard.setData(
ClipboardData(text: smartDoorBloc.passwordController.text)
);
}else{
if(smartDoorBloc.passwordNameController.text.isNotEmpty){
smartDoorBloc.add(RenamePasswordEvent());

View File

@ -11,6 +11,7 @@ import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/door_lock_button.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
@ -27,11 +28,8 @@ class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) {
if (state is FailedState) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.errorMessage),
backgroundColor: Colors.red,
),
CustomSnackBar.displaySnackBar(
state.errorMessage
);
}
if (state is IsRepeatState) {
@ -240,8 +238,7 @@ class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
),
const BodyMedium(
textAlign: TextAlign.center,
text:
'Use the time-limited password at least once within 24 hours after the password takes effect. Otherwise, the password becomes invalid.',
text: 'Use the time-limited password at least once within 24 hours after the password takes effect. Otherwise, the password becomes invalid.',
fontWeight: FontWeight.normal,
fontColor: ColorsManager.grayColor,
),
@ -259,14 +256,10 @@ class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
backgroundColor: ColorsManager.primaryColor,
onPressed: () async {
if (generated == false) {
smartDoorBloc.add(
GenerateAndSavePasswordTimeLimitEvent(context: context));
await Clipboard.setData(
ClipboardData(text: smartDoorBloc.passwordController.text)
);
smartDoorBloc.add(GenerateAndSavePasswordTimeLimitEvent(context: context));
} else {
if(smartDoorBloc.passwordNameController.text.isNotEmpty){
smartDoorBloc.add(RenamePasswordEvent());
smartDoorBloc.add(RenamePasswordEvent());
}
Navigator.of(context).pop(true);
}

View File

@ -9,6 +9,7 @@ import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'door_dialog.dart';
@ -22,11 +23,8 @@ class TimeLimitedPasswordPage extends StatelessWidget {
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) {
if (state is FailedState) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.errorMessage),
backgroundColor: Colors.red,
),
CustomSnackBar.displaySnackBar(
state.errorMessage
);
}
},
@ -40,10 +38,8 @@ class TimeLimitedPasswordPage extends StatelessWidget {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => CreateOfflineTimeLimitPasswordPage(deviceId: deviceId,)
)).then((result) {
if (result != null) {
smartDoorBloc.add(InitialTimeLimitPassword());
smartDoorBloc.add(InitialTimeLimitPassword());
}
smartDoorBloc.add(InitialTimeLimitPassword());
smartDoorBloc.add(InitialTimeLimitPassword());
});
},
icon: const Icon(Icons.add)

View File

@ -1,6 +1,5 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_event.dart';

View File

@ -34,6 +34,7 @@ mixin SceneLogicHelper {
required List<SceneStaticFunction> conditions,
}) {
final sceneBloc = context.read<CreateSceneBloc>();
final effectiveTime = sceneBloc.effectiveTime;
if (isOnlyDelayOrDelayLast(actions)) {
context.showCustomSnackbar(
@ -46,6 +47,17 @@ mixin SceneLogicHelper {
return;
}
if (isAutomation == true && effectiveTime?.loops == '0000000') {
context.showCustomSnackbar(
message: 'At least one day in Effective Period must be selected!',
icon: const Icon(
Icons.error,
color: Colors.red,
),
);
return;
}
if (isAutomation) {
final createAutomationModel = CreateAutomationModel(
unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '',
@ -81,7 +93,7 @@ mixin SceneLogicHelper {
executorProperty: CreateSceneExecutorProperty(
functionCode: '',
functionValue: '',
delaySeconds: task.functionValue,
delaySeconds: task.functionValue ?? 1,
),
);
}
@ -159,21 +171,24 @@ mixin SceneLogicHelper {
}
}
Widget getTheCorrectDialogBody(SceneStaticFunction taskItem, dynamic functionValue,
Widget getTheCorrectDialogBody(
SceneStaticFunction taskItem, dynamic functionValue,
{required bool isAutomation}) {
if (taskItem.operationDialogType == OperationDialogType.temperature) {
return AlertDialogTemperatureBody(
taskItem: taskItem,
functionValue: functionValue ?? taskItem.functionValue,
);
} else if ((taskItem.operationDialogType == OperationDialogType.countdown) ||
} else if ((taskItem.operationDialogType ==
OperationDialogType.countdown) ||
(taskItem.operationDialogType == OperationDialogType.delay)) {
return AlertDialogCountdown(
durationValue: taskItem.functionValue ?? 0,
functionValue: functionValue ?? taskItem.functionValue,
function: taskItem,
);
} else if (taskItem.operationDialogType == OperationDialogType.integerSteps) {
} else if (taskItem.operationDialogType ==
OperationDialogType.integerSteps) {
return AlertDialogSliderSteps(
taskItem: taskItem,
functionValue: functionValue ?? taskItem.functionValue,

View File

@ -15,10 +15,12 @@ class SceneAutoSettings extends StatelessWidget {
@override
Widget build(BuildContext context) {
final sceneSettings = ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>? ?? {};
final sceneSettings =
ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>? ??
{};
final sceneId = sceneSettings['sceneId'] as String? ?? '';
final isAutomation =
context.read<CreateSceneBloc>().sceneType == CreateSceneEnum.deviceStatusChanges;
final isAutomation = context.read<CreateSceneBloc>().sceneType ==
CreateSceneEnum.deviceStatusChanges;
final sceneName = sceneSettings['sceneName'] as String? ?? '';
return DefaultScaffold(
@ -48,9 +50,11 @@ class SceneAutoSettings extends StatelessWidget {
Visibility(
visible: isAutomation,
child: SceneListTile(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
padding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 8),
titleString: "Effective Period",
trailingWidget: const Icon(Icons.arrow_forward_ios_rounded),
trailingWidget:
const Icon(Icons.arrow_forward_ios_rounded),
onPressed: () {
context.customBottomSheet(
child: const EffectPeriodBottomSheetContent(),

View File

@ -48,12 +48,21 @@ class _AlertDialogSliderStepsState extends State<AlertDialogSliderSteps> {
}
}
}
if (widget.functionValue != null) {
groupValue = _normalizeValue(widget.functionValue);
if (widget.taskItem.code == 'temp_current') {
if (widget.functionValue != null) {
groupValue = _normalizeValue(
double.tryParse(widget.functionValue.toString()) ??
widget.taskItem.operationalValues[0].minValue);
} else {
groupValue = widget.taskItem.operationalValues[0].minValue;
}
} else {
groupValue =
_normalizeValue(widget.taskItem.operationalValues[0].minValue);
if (widget.functionValue != null) {
groupValue = _normalizeValue(widget.functionValue);
} else {
groupValue =
_normalizeValue(widget.taskItem.operationalValues[0].minValue);
}
}
setState(() {});
@ -68,14 +77,6 @@ class _AlertDialogSliderStepsState extends State<AlertDialogSliderSteps> {
);
}
double _normalizeValue(dynamic value) {
if (((widget.taskItem.code == "temp_set" && value > 199) ||
widget.taskItem.code == "temp_current")) {
return (value) / 10;
}
return value.toDouble();
}
int _comparatorToIndex(String? comparator) {
switch (comparator) {
case "<":
@ -216,7 +217,7 @@ class _AlertDialogSliderStepsState extends State<AlertDialogSliderSteps> {
: null,
onChanged: (value) {
setState(() {
groupValue = normalizeValue(value);
groupValue = normalizeToDoubleValue(value);
});
context.read<CreateSceneBloc>().add(SelectedValueEvent(
value: _deNormalizeValue(groupValue),
@ -237,8 +238,16 @@ class _AlertDialogSliderStepsState extends State<AlertDialogSliderSteps> {
);
}
double normalizeValue(double value) {
return double.parse(value.toStringAsFixed(1));
double _normalizeValue(dynamic value) {
if ((widget.taskItem.code == "temp_set" && value > 199) ||
(widget.taskItem.code == "temp_current" && value >= -99.0)) {
return (value) / 10;
}
return value.toDouble();
}
double? normalizeToDoubleValue(double value) {
return double.tryParse(value.toStringAsFixed(1));
}
double _deNormalizeValue(double? value) {

View File

@ -50,10 +50,10 @@ class _AlertDialogTemperatureBodyState
});
}
// context.read<CreateSceneBloc>().add(SelectedValueEvent(
// value: temperature * 10,
// code: widget.taskItem.code,
// ));
context.read<CreateSceneBloc>().add(SelectedValueEvent(
value: temperature * 10,
code: widget.taskItem.code,
));
}
int _normalizeTemperature(dynamic value) {

View File

@ -19,18 +19,8 @@ class EffectPeriodBottomSheetContent extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Expanded(
// child: TextButton(
// onPressed: () => Navigator.pop(context),
// child: BodySmall(
// text: 'Save',
// style:
// context.bodySmall.copyWith(color: ColorsManager.primaryColorWithOpacity),
// )),
// ),
const Spacer(),
Expanded(
// flex: 2,
child: BodyMedium(
text: 'Effective Period',
fontColor: ColorsManager.primaryColorWithOpacity,

View File

@ -4,6 +4,9 @@ import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_b
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_event.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_state.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class RepeatDays extends StatelessWidget {
const RepeatDays({super.key});
@ -27,44 +30,63 @@ class RepeatDays extends StatelessWidget {
const SizedBox(width: 8),
BlocBuilder<EffectPeriodBloc, EffectPeriodState>(
builder: (context, state) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: daysMap.entries.map((entry) {
final day = entry.key;
final abbreviation = entry.value;
final dayIndex = _getDayIndex(day);
final isSelected = state.selectedDaysBinary[dayIndex] == '1';
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 3.0),
child: GestureDetector(
onTap: () {
context.read<EffectPeriodBloc>().add(ToggleDay(day));
},
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color:
isSelected ? Colors.grey : Colors.grey.shade300,
width: 1,
),
),
child: CircleAvatar(
radius: 15,
backgroundColor: Colors.white,
child: Text(
abbreviation,
style: TextStyle(
fontSize: 16,
color:
isSelected ? Colors.grey : Colors.grey.shade300,
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: daysMap.entries.map((entry) {
final day = entry.key;
final abbreviation = entry.value;
final dayIndex = _getDayIndex(day);
final isSelected =
state.selectedDaysBinary[dayIndex] == '1';
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 3.0),
child: GestureDetector(
onTap: () {
context.read<EffectPeriodBloc>().add(ToggleDay(day));
},
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: isSelected
? Colors.grey
: Colors.grey.shade300,
width: 1,
),
),
child: CircleAvatar(
radius: 15,
backgroundColor: Colors.white,
child: Text(
abbreviation,
style: TextStyle(
fontSize: 16,
color: isSelected
? Colors.grey
: Colors.grey.shade300,
),
),
),
),
),
),
);
}).toList(),
),
const SizedBox(
height: 8,
),
if (state.selectedDaysBinary == '0000000')
BodySmall(
text: 'At least one day must be selected',
style:
context.bodyMedium.copyWith(color: ColorsManager.red),
),
);
}).toList(),
],
);
},
),

View File

@ -197,13 +197,13 @@ class DevicesAPI {
required String invalidTime,
required String deviceId,
List<Schedule>? scheduleList,}) async {
Map<String, dynamic> body = {
"name": name,
"password": password,
"effectiveTime": effectiveTime,
"invalidTime": invalidTime,
};
print('createPassword =$body');
if (scheduleList != null) {
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList();
}
@ -235,7 +235,7 @@ class DevicesAPI {
try {
final response = await _httpService.post(
path: ApiEndpoints.addMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false,
showServerMessage: true,
body: {
"effectiveTime": effectiveTime,
"invalidTime": invalidTime