add device filter and select time repeat widget

This commit is contained in:
mohammad
2024-08-20 16:36:05 +03:00
parent 0cf5053f8b
commit 1204563c55
13 changed files with 346 additions and 124 deletions

View File

@ -59,7 +59,7 @@ class MyApp extends StatelessWidget {
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), // Set up color scheme
useMaterial3: true, // Enable Material 3
),
// home: VisitorPasswordDialog()
// home: AddDeviceDialog()
home:isLoggedIn == 'Success' ? const HomePage() : const LoginPage(),
));
}

View File

@ -237,7 +237,7 @@ class AccessManagementPage extends StatelessWidget {
? DynamicTable(
withCheckBox: false,
size: size,
// cellDecoration: containerDecoration,
cellDecoration: containerDecoration,
headers: const [
'Name',
'Access Type',

View File

@ -155,7 +155,7 @@ class _DynamicTableState extends State<DynamicTable> {
return Expanded(
child: Container(
height: 80,
padding: const EdgeInsets.all(20.0),
padding: const EdgeInsets.all(15.0),
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(

View File

@ -72,7 +72,10 @@ class CustomWebTextField extends StatelessWidget {
controller: controller,
style: const TextStyle(color: Colors.black),
decoration: textBoxDecoration()!
.copyWith(hintText: 'Please enter'),
.copyWith(
errorStyle: const TextStyle(height: 0), // Hide the error text space
hintText: 'Please enter'),
),
),
),

View File

@ -0,0 +1,74 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
class InfoDialog extends StatelessWidget {
final String title;
final String content;
final Size? size;
final List<Widget>? actions;
InfoDialog({
required this.title,
required this.content,
this.actions,
this.size,
});
@override
Widget build(BuildContext context) {
return AlertDialog(
alignment: Alignment.center,
content: SizedBox(
height: size!.height * 0.25,
child: Column(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
child: SvgPicture.asset(
Assets.deviceNoteIcon,
height: 35,
width: 35,
),
),
Text(
title,
style: Theme.of(context).textTheme.headlineLarge!.copyWith(
fontSize: 30,
fontWeight: FontWeight.w400,
color: Colors.black),
),
],
),
const SizedBox(
width: 15,
),
Text(
content,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.w400,
fontSize: 18),
),
],
),
),
actionsAlignment: MainAxisAlignment.center,
actions: actions ??
<Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('OK'),
),
],
);
}
}

View File

@ -23,6 +23,7 @@ class VisitorPasswordBloc
on<ToggleRepeatEvent>(toggleRepeat);
on<ToggleDaySelectionEvent>(toggleDaySelection);
on<SelectDeviceEvent>(selectDevice);
on<UpdateFilteredDevicesEvent>(_onUpdateFilteredDevices);
on<OnlineOneTimePasswordEvent>(postOnlineOneTimePassword);
on<OnlineMultipleTimePasswordEvent>(postOnlineMultipleTimePassword);
@ -39,6 +40,8 @@ class VisitorPasswordBloc
final TextEditingController unitNameController = TextEditingController();
final TextEditingController virtualAddressController = TextEditingController();
List<DeviceModel> data = [];
List<String> selectedDeviceIds = [];
@ -55,11 +58,18 @@ class VisitorPasswordBloc
int? effectiveTimeTimeStamp;
int? expirationTimeTimeStamp;
int? repeatEffectiveTimeTimeStamp;
int? repeatExpirationTimeTimeStamp;
String startTime = 'Start Time';
String endTime = 'End Time';
DateTime? repeatStartTime=DateTime.now();
DateTime? repeatEndTime;
String repeatStartTime = 'Start Time';
String repeatEndTime = 'End Time';
// DateTime? repeatStartTime=DateTime.now();
// DateTime? repeatEndTime;
selectAccessType(
SelectPasswordType event, Emitter<VisitorPasswordState> emit) {
@ -80,7 +90,7 @@ class VisitorPasswordBloc
context: event.context,
initialDate: DateTime.now(),
firstDate: DateTime(2015, 8),
lastDate: DateTime(2101),
lastDate: DateTime(3101),
);
if (picked != null) {
final TimeOfDay? timePicked = await showTimePicker(
@ -120,33 +130,34 @@ class VisitorPasswordBloc
).millisecondsSinceEpoch ~/
1000; // Divide by 1000 to remove milliseconds
if (event.isStart) {
if (expirationTimeTimeStamp != null &&
selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Effective Time cannot be later than Expiration Time.');
if (expirationTimeTimeStamp != null && selectedTimestamp >expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.');
} else {
startTime = selectedDateTime
.toString()
.split('.')
.first; // Remove seconds and milliseconds
if(event.isRepeat==true)
{repeatStartTime = selectedDateTime.toString().split('.').first;}
else // Remove seconds and milliseconds
{startTime = selectedDateTime.toString().split('.').first;}
effectiveTimeTimeStamp = selectedTimestamp;
emit(ChangeTimeState());
}
emit(ChangeTimeState());
} else {
if (effectiveTimeTimeStamp != null &&
selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Expiration Time cannot be earlier than Effective Time.');
CustomSnackBar.displaySnackBar('Expiration Time cannot be earlier than Effective Time.');
} else {
endTime = selectedDateTime
.toString()
.split('.')
.first; // Remove seconds and milliseconds
if(event.isRepeat==true)
{repeatEndTime = selectedDateTime.toString().split('.').first;}
else
{endTime = selectedDateTime.toString().split('.').first;}
expirationTimeTimeStamp = selectedTimestamp;
}
emit(VisitorPasswordInitial());
emit(ChangeTimeState());
}
emit(ChangeTimeState());
emit(VisitorPasswordInitial());
}
}
}
@ -225,12 +236,12 @@ class VisitorPasswordBloc
// emit(DeviceLoaded());
await AccessMangApi().postOnlineMultipleTime(
scheduleList:[
if (repeat)
Schedule(
effectiveTime: getTimeOnly(repeatStartTime),
invalidTime: getTimeOnly(repeatEndTime).toString(),
workingDay: selectedDays,
),
// if (repeat)
// Schedule(
// effectiveTime: getTimeOnly(repeatStartTime),
// invalidTime: getTimeOnly(repeatEndTime).toString(),
// workingDay: selectedDays,
// ),
] ,
password: passwordController,
invalidTime:event.invalidTime ,
@ -297,7 +308,7 @@ class VisitorPasswordBloc
String? validate(String? value) {
if (value == null || value.isEmpty) {
return 'Field is required';
return '';
}
return null;
}
@ -317,4 +328,34 @@ class VisitorPasswordBloc
if (dateTime == null) return '';
return DateFormat('HH:mm').format(dateTime);
}
void filterDevices() {
final deviceName = deviceNameController.text.toLowerCase();
final deviceId = deviceIdController.text.toLowerCase();
final unitName = unitNameController.text.toLowerCase();
final filteredData = data.where((device) {
final matchesDeviceName = device.name.toLowerCase().contains(deviceName);
final matchesDeviceId = device.uuid.toLowerCase().contains(deviceId);
// final matchesUnitName = device.unitName.toLowerCase().contains(unitName); // Assuming unitName is a property of the device
return matchesDeviceName && matchesDeviceId ;
}).toList();
// emit(TableLoaded(filteredData));
add(UpdateFilteredDevicesEvent(filteredData));
}
@override
Stream<VisitorPasswordState> mapEventToState(VisitorPasswordEvent event) async* {
if (event is FetchDevice) {
// Fetching logic...
} else if (event is UpdateFilteredDevicesEvent) {
yield TableLoaded(event.filteredData);
}
}
void _onUpdateFilteredDevices(UpdateFilteredDevicesEvent event, Emitter<VisitorPasswordState> emit) {
emit(TableLoaded(event.filteredData));
}
}

View File

@ -1,5 +1,6 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
import 'package:syncrow_web/pages/visitor_password/model/device_model.dart';
abstract class VisitorPasswordEvent extends Equatable {
const VisitorPasswordEvent();
@ -28,11 +29,12 @@ class SelectUsageFrequency extends VisitorPasswordEvent {
class SelectTimeVisitorPassword extends VisitorPasswordEvent {
final BuildContext context;
final bool isStart;
final bool isRepeat;
const SelectTimeVisitorPassword({ required this.context,required this.isStart});
const SelectTimeVisitorPassword({ required this.context,required this.isStart,required this.isRepeat});
@override
List<Object> get props => [context,isStart];
List<Object> get props => [context,isStart,isRepeat];
}
@ -96,4 +98,21 @@ class OfflineMultipleTimePasswordEvent extends VisitorPasswordEvent {
class SelectDeviceEvent extends VisitorPasswordEvent {
final String deviceId;
const SelectDeviceEvent(this.deviceId);
}
class FilterDataEvent extends VisitorPasswordEvent {
final String? passwordName;
final int? startTime;
final int? endTime;
const FilterDataEvent({
this.passwordName,
this.startTime,
this.endTime,
});
}
class UpdateFilteredDevicesEvent extends VisitorPasswordEvent {
final List<DeviceModel> filteredData;
UpdateFilteredDevicesEvent(this.filteredData);
}

View File

@ -16,9 +16,7 @@ class VisitorPasswordInitial extends VisitorPasswordState {}
class PasswordTypeSelected extends VisitorPasswordState {
final String selectedType;
const PasswordTypeSelected(this.selectedType);
@override
List<Object> get props => [selectedType];
}
@ -45,19 +43,17 @@ class LoadingInitialState extends VisitorPasswordState {}
class ChangeTimeState extends VisitorPasswordState {}
class DeviceLoaded extends VisitorPasswordState {}
class GeneratePasswordState extends VisitorPasswordState {}
class FailedState extends VisitorPasswordState {
final String message;
FailedState(this.message);
const FailedState(this.message);
@override
List<Object> get props => [message];
}
class TableLoaded extends VisitorPasswordState {
final List<DeviceModel> data;
const TableLoaded(this.data);
@override
List<Object> get props => [data];
}

View File

@ -1,5 +1,7 @@
import 'package:syncrow_web/utils/constants/const.dart';
class DeviceModel {
dynamic productUuid;
dynamic productType;
@ -15,7 +17,7 @@ class DeviceModel {
dynamic lon;
dynamic model;
dynamic name;
dynamic online;
DeviseStatus online;
dynamic ownerId;
dynamic sub;
dynamic timeZone;
@ -62,7 +64,7 @@ class DeviceModel {
lon: json['lon'] ,
model: json['model'] ,
name: json['name'],
online: json['online'],
online: OnlineTypeExtension.fromString(json['online']),
ownerId: json['ownerId'] ,
sub: json['sub'],
timeZone: json['timeZone'],

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
@ -10,6 +9,7 @@ import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_event.d
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_state.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/constants/const.dart';
import 'package:syncrow_web/utils/style.dart';
@ -34,13 +34,13 @@ class AddDeviceDialog extends StatelessWidget {
child: Column(
children: <Widget>[
Container(
width: size.width,
padding: EdgeInsets.all(15),
decoration:containerDecoration.copyWith(
color: ColorsManager.worningColor,
border: Border.all(color: Color(0xffFFD22F)),
boxShadow: []
),
width: size.width,
padding: EdgeInsets.all(15),
decoration:containerDecoration.copyWith(
color: ColorsManager.worningColor,
border: Border.all(color: Color(0xffFFD22F)),
boxShadow: []
),
child: Row(
children: [
SizedBox(
@ -73,7 +73,7 @@ class AddDeviceDialog extends StatelessWidget {
Expanded(
flex: 2,
child: CustomWebTextField(
controller: visitorBloc.deviceNameController,
controller: visitorBloc.deviceIdController,
isRequired: true,
textFieldName: 'Device ID',
description: '',
@ -103,7 +103,7 @@ class AddDeviceDialog extends StatelessWidget {
child: Center(
child: DefaultButton(
onPressed: () {
// Your search function here
visitorBloc.filterDevices(); // Call filter function
},
borderRadius: 9,
child: const Text('Search'),
@ -133,6 +133,12 @@ class AddDeviceDialog extends StatelessWidget {
'Reset',
style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.black),
),
onPressed: () {
visitorBloc.deviceNameController.clear();
visitorBloc.deviceIdController.clear();
visitorBloc.unitNameController.clear();
visitorBloc.add(FetchDevice()); // Reset to original list
},
),
),
),
@ -145,7 +151,7 @@ class AddDeviceDialog extends StatelessWidget {
const SizedBox(height: 20),
Expanded(
child: state is TableLoaded
? Container(
? Container(
decoration: containerDecoration,
child: DynamicTable(
selectAll: (p0) {
@ -160,14 +166,14 @@ class AddDeviceDialog extends StatelessWidget {
},
withCheckBox: true,
size: size*0.5,
headers: const [ 'Device Name', 'Device ID', 'Access Type', 'Unit Name', 'Status'],
headers: const [ 'Device Name', 'Device ID', 'Access Type', 'Unit Name', 'Status'],
data: state.data.map((item) {
return [
item.name.toString(),
item.uuid.toString(),
item.productType.toString(),
'',
item.online.toString(),
item.online.value.toString(),
];
}).toList(),
),
@ -195,13 +201,11 @@ class AddDeviceDialog extends StatelessWidget {
),
),
Container(
decoration: containerDecoration,
width: size.width * 0.2,
child: DefaultButton(
onPressed: () {
Navigator.of(context).pop(); // Close the dialog
},
borderRadius: 8,
child: Text('Ok'),
@ -211,5 +215,6 @@ class AddDeviceDialog extends StatelessWidget {
);
},
),
); }
);
}
}

View File

@ -20,29 +20,6 @@ class RepeatWidget extends StatelessWidget {
final smartDoorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
return Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: DateTimeWebWidget(
isRequired: true,
title: 'Access Period',
size: size,
endTime: () {
smartDoorBloc.add(SelectTimeVisitorPassword(context: context, isStart: false));
},
startTime: () {
smartDoorBloc.add(SelectTimeVisitorPassword(context: context, isStart: true));
},
firstString: smartDoorBloc.startTime,
secondString: smartDoorBloc.endTime,
),
),
const Divider(
color: ColorsManager.graysColor,
),
const Divider(
color: ColorsManager.graysColor,
),
const SizedBox(height: 20),
Container(
width: size.width * 0.8,
height: size.height * 0.06, // Adjust height as needed
@ -72,6 +49,29 @@ class RepeatWidget extends StatelessWidget {
}).toList(),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: DateTimeWebWidget(
isRequired: false,
title: '',
size: size,
endTime: () {
smartDoorBloc.add(SelectTimeVisitorPassword(
isRepeat: true,
context: context, isStart: false
));
},
startTime: () {
smartDoorBloc.add(SelectTimeVisitorPassword(
isRepeat: true,
context: context, isStart: true
));
},
firstString: smartDoorBloc.repeatStartTime.toString(),
secondString: smartDoorBloc.repeatEndTime.toString(),
),
),
const SizedBox(height: 20),
],

View File

@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/custom_web_textfield.dart';
import 'package:syncrow_web/pages/common/date_time_widget.dart';
import 'package:syncrow_web/pages/common/default_button.dart';
import 'package:syncrow_web/pages/common/info_dialog.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_event.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_state.dart';
@ -79,7 +80,6 @@ class VisitorPasswordDialog extends StatelessWidget {
),
Row(
children: <Widget>[
SizedBox(
width: size.width * 0.15,
child: RadioListTile<String>(
@ -90,6 +90,7 @@ class VisitorPasswordDialog extends StatelessWidget {
: visitorBloc.accessTypeSelected,
onChanged: (String? value) {
if (value != null) {
print(value);
context.read<VisitorPasswordBloc>().add(SelectPasswordType(value));
}
},
@ -106,6 +107,8 @@ class VisitorPasswordDialog extends StatelessWidget {
: visitorBloc.accessTypeSelected,
onChanged: (String? value) {
if (value != null) {
print(value);
context.read<VisitorPasswordBloc>().add(SelectPasswordType(value));
}
},
@ -123,6 +126,7 @@ class VisitorPasswordDialog extends StatelessWidget {
onChanged: (String? value) {
if (value != null) {
context.read<VisitorPasswordBloc>().add(SelectPasswordType(value));
visitorBloc.usageFrequencySelected='';
}
},
),
@ -130,7 +134,7 @@ class VisitorPasswordDialog extends StatelessWidget {
],
),
const Text('Only currently online devices can be selected. It is recommended to use when the device network is stable, and the system randomly generates a digital password'),
SizedBox(height: 20,)
const SizedBox(height: 20,)
],
),
visitorBloc.accessTypeSelected=='Dynamic Password' ?
@ -162,6 +166,8 @@ class VisitorPasswordDialog extends StatelessWidget {
: visitorBloc.usageFrequencySelected,
onChanged: (String? value) {
if (value != null) {
print(value);
context.read<VisitorPasswordBloc>().add(SelectUsageFrequency(value));
}
},
@ -185,27 +191,28 @@ class VisitorPasswordDialog extends StatelessWidget {
],
),
Text('Within the validity period, each device can be unlocked only once.')
const Text('Within the validity period, each device can be unlocked only once.')
],
),
const SizedBox(height: 20,),
visitorBloc.accessTypeSelected=='Dynamic Password' ?
SizedBox():
if((visitorBloc.usageFrequencySelected!='One-Time'||visitorBloc.accessTypeSelected!='Offline Password')&&(visitorBloc.usageFrequencySelected!=''))
DateTimeWebWidget(
isRequired: true,
title: 'Access Period',
size: size,
endTime: () {
visitorBloc.add(SelectTimeVisitorPassword(context: context, isStart: false));
visitorBloc.add(SelectTimeVisitorPassword(
context: context, isStart: false,isRepeat:false));
},
startTime: () {
visitorBloc.add(SelectTimeVisitorPassword(context: context, isStart: true));
visitorBloc.add(SelectTimeVisitorPassword(
context: context, isStart: true,isRepeat:false));
},
firstString: visitorBloc.startTime,
secondString: visitorBloc.endTime,
),
const SizedBox(height: 20,),
Column(
@ -243,7 +250,8 @@ class VisitorPasswordDialog extends StatelessWidget {
),
),
),
isRepeat ? const RepeatWidget() : const SizedBox(),
if(visitorBloc.usageFrequencySelected=='Periodic'&&visitorBloc.accessTypeSelected=='Online Password')
isRepeat ? const RepeatWidget() : const SizedBox(),
Container(
decoration: containerDecoration,
width: size.width * 0.1,
@ -254,7 +262,6 @@ class VisitorPasswordDialog extends StatelessWidget {
barrierDismissible: false,
builder: (BuildContext context) {
return const AddDeviceDialog();
},
);
},
@ -293,39 +300,79 @@ class VisitorPasswordDialog extends StatelessWidget {
child: DefaultButton(
onPressed: () {
if(visitorBloc.forgetFormKey.currentState!.validate()){
if(visitorBloc.usageFrequencySelected=='One-Time'&&visitorBloc.accessTypeSelected=='Online Password'){
visitorBloc.add(OnlineOneTimePasswordEvent(
passwordName:visitorBloc.userNameController.text ,
email: visitorBloc.emailController.text
)
);
}else if(visitorBloc.usageFrequencySelected=='Periodic'&&visitorBloc.accessTypeSelected=='Online Password') {
visitorBloc.add(OnlineMultipleTimePasswordEvent(
passwordName:visitorBloc.userNameController.text ,
email: visitorBloc.emailController.text,
effectiveTime:visitorBloc.effectiveTimeTimeStamp.toString() ,
invalidTime:visitorBloc.expirationTimeTimeStamp.toString()
)
);
}
else if(visitorBloc.usageFrequencySelected=='One-Time'&&visitorBloc.accessTypeSelected=='Offline Password') {
visitorBloc.add(OfflineOneTimePasswordEvent(
passwordName:visitorBloc.userNameController.text ,
email: visitorBloc.emailController.text,
)
);
}
else if(visitorBloc.usageFrequencySelected=='Periodic'&&visitorBloc.accessTypeSelected=='Offline Password') {
visitorBloc.add(OfflineMultipleTimePasswordEvent(
passwordName:visitorBloc.userNameController.text ,
email: visitorBloc.emailController.text,
effectiveTime:visitorBloc.effectiveTimeTimeStamp.toString() ,
invalidTime:visitorBloc.expirationTimeTimeStamp.toString()
)
);
}
}
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return InfoDialog(
size: size,
title: 'Set Password',
content: 'This action will update all of the selected\n door locks passwords in the property.\n\nAre you sure you want to continue?',
actions: [
Container(
decoration: containerDecoration,
width: size.width * 0.1,
child: DefaultButton(
borderRadius: 8,
onPressed: () {
Navigator.of(context).pop(); // Close the dialog
},
backgroundColor: Colors.white,
child: Text(
'Cancel',
style: Theme.of(context).textTheme.bodyMedium!,
),
),
),
Container(
decoration: containerDecoration,
width: size.width * 0.1,
child: DefaultButton(
borderRadius: 8,
onPressed: () {
if(visitorBloc.usageFrequencySelected=='One-Time'&&visitorBloc.accessTypeSelected=='Online Password'){
visitorBloc.add(OnlineOneTimePasswordEvent(
passwordName:visitorBloc.userNameController.text ,
email: visitorBloc.emailController.text
)
);
}
else if(visitorBloc.usageFrequencySelected=='Periodic'&&visitorBloc.accessTypeSelected=='Online Password') {
visitorBloc.add(OnlineMultipleTimePasswordEvent(
passwordName:visitorBloc.userNameController.text ,
email: visitorBloc.emailController.text,
effectiveTime:visitorBloc.effectiveTimeTimeStamp.toString() ,
invalidTime:visitorBloc.expirationTimeTimeStamp.toString()
)
);
}
else if(visitorBloc.usageFrequencySelected=='One-Time'&&visitorBloc.accessTypeSelected=='Offline Password') {
visitorBloc.add(OfflineOneTimePasswordEvent(
passwordName:visitorBloc.userNameController.text ,
email: visitorBloc.emailController.text,
)
);
}
else if(visitorBloc.usageFrequencySelected=='Periodic'&&visitorBloc.accessTypeSelected=='Offline Password') {
visitorBloc.add(OfflineMultipleTimePasswordEvent(
passwordName:visitorBloc.userNameController.text ,
email: visitorBloc.emailController.text,
effectiveTime:visitorBloc.effectiveTimeTimeStamp.toString() ,
invalidTime:visitorBloc.expirationTimeTimeStamp.toString()
)
);
}
},
child: const Text(
'Ok',
),
),
),
],);
},
);
}
},
borderRadius: 8,
child: Text('Ok'),

View File

@ -42,3 +42,38 @@ extension AccessTypeExtension on AccessType {
enum DeviseStatus {
online,
offline,
}
extension OnlineTypeExtension on DeviseStatus {
String get value {
switch (this) {
case DeviseStatus.online:
return "Online";
case DeviseStatus.offline:
return "Offline";
}
}
static DeviseStatus fromString(bool value) {
switch (value) {
case false:
return DeviseStatus.offline;
case true:
return DeviseStatus.online;
default:
throw ArgumentError("Invalid access type: $value");
}
}
}