merged with dev and access_bugs and solved conflicts

This commit is contained in:
Abdullah Alassaf
2024-08-28 14:50:47 +03:00
30 changed files with 1326 additions and 1207 deletions

View File

@ -5,7 +5,7 @@ import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
import 'package:syncrow_web/pages/access_management/model/password_model.dart';
import 'package:syncrow_web/services/access_mang_api.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/const.dart';
import 'package:syncrow_web/utils/constants/app_enum.dart';
import 'package:syncrow_web/utils/snack_bar.dart';
class AccessBloc extends Bloc<AccessEvent, AccessState> {
@ -26,8 +26,7 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
List<PasswordModel> filteredData = [];
List<PasswordModel> data = [];
Future<void> _onFetchTableData(
FetchTableData event, Emitter<AccessState> emit) async {
Future<void> _onFetchTableData(FetchTableData event, Emitter<AccessState> emit) async {
try {
emit(AccessLoaded());
data = await AccessMangApi().fetchVisitorPassword();
@ -40,28 +39,19 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
}
void updateTabsCount() {
int toBeEffectiveCount = data
.where((item) => item.passwordStatus.value == 'To Be Effective')
.length;
int effectiveCount =
data.where((item) => item.passwordStatus.value == 'Effective').length;
int expiredCount =
data.where((item) => item.passwordStatus.value == 'Expired').length;
int toBeEffectiveCount =
data.where((item) => item.passwordStatus.value == 'To be effective').length;
int effectiveCount = data.where((item) => item.passwordStatus.value == 'Effective').length;
int expiredCount = data.where((item) => item.passwordStatus.value == 'Expired').length;
tabs[1] = 'To Be Effective ($toBeEffectiveCount)';
tabs[2] = 'Effective ($effectiveCount)';
tabs[3] = 'Expired ($expiredCount)';
}
int selectedIndex = 0;
final List<String> tabs = [
'All',
'To Be Effective (0)',
'Effective (0)',
'Expired'
];
final List<String> tabs = ['All', 'To Be Effective (0)', 'Effective (0)', 'Expired'];
Future selectFilterTap(
TabChangedEvent event, Emitter<AccessState> emit) async {
Future selectFilterTap(TabChangedEvent event, Emitter<AccessState> emit) async {
try {
emit(AccessLoaded());
selectedIndex = event.selectedIndex;
@ -75,7 +65,6 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
Future<void> selectTime(SelectTime event, Emitter<AccessState> emit) async {
emit(AccessLoaded());
final DateTime? picked = await showDatePicker(
context: event.context,
initialDate: DateTime.now(),
@ -83,111 +72,112 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
lastDate: DateTime(2101),
);
if (picked != null) {
final TimeOfDay? timePicked = await showTimePicker(
context: event.context,
initialTime: TimeOfDay.now(),
builder: (context, child) {
return Theme(
data: ThemeData.light().copyWith(
colorScheme: const ColorScheme.light(
primary: ColorsManager.primaryColor,
onSurface: Colors.black,
),
buttonTheme: const ButtonThemeData(
colorScheme: ColorScheme.light(
primary: Colors.green,
),
),
),
child: child!,
);
},
final selectedDateTime = DateTime(
picked.year,
picked.month,
picked.day,
);
if (timePicked != null) {
final selectedDateTime = DateTime(
picked.year,
picked.month,
picked.day,
timePicked.hour,
timePicked.minute,
);
final selectedTimestamp = DateTime(
selectedDateTime.year,
selectedDateTime.month,
selectedDateTime.day,
selectedDateTime.hour,
selectedDateTime.minute,
).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.');
} else {
startTime = selectedDateTime
.toString()
.split('.')
.first; // Remove seconds and milliseconds
effectiveTimeTimeStamp = selectedTimestamp;
}
final selectedTimestamp = DateTime(
selectedDateTime.year,
selectedDateTime.month,
selectedDateTime.day,
selectedDateTime.hour,
selectedDateTime.minute,
).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.');
} else {
if (effectiveTimeTimeStamp != null &&
selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Expiration Time cannot be earlier than Effective Time.');
} else {
endTime = selectedDateTime
.toString()
.split('.')
.first; // Remove seconds and milliseconds
expirationTimeTimeStamp = selectedTimestamp;
}
startTime =
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 {
endTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
expirationTimeTimeStamp = selectedTimestamp;
}
}
}
emit(ChangeTimeState());
}
Future<void> _filterData(
FilterDataEvent event, Emitter<AccessState> emit) async {
Future<void> _filterData(FilterDataEvent event, Emitter<AccessState> emit) async {
emit(AccessLoaded());
try {
filteredData = data.where((item) {
bool matchesCriteria = true;
// Convert timestamp to DateTime and extract date component
DateTime effectiveDate =
DateTime.fromMillisecondsSinceEpoch(int.parse(item.effectiveTime.toString()) * 1000)
.toUtc()
.toLocal();
DateTime invalidDate =
DateTime.fromMillisecondsSinceEpoch(int.parse(item.invalidTime.toString()) * 1000)
.toUtc()
.toLocal();
DateTime effectiveDateOnly =
DateTime(effectiveDate.year, effectiveDate.month, effectiveDate.day);
DateTime invalidDateOnly = DateTime(invalidDate.year, invalidDate.month, invalidDate.day);
// Filter by password name
if (event.passwordName != null && event.passwordName!.isNotEmpty) {
final bool matchesName = item.passwordName != null &&
item.passwordName.contains(event.passwordName);
final bool matchesName =
item.passwordName != null && item.passwordName.contains(event.passwordName);
if (!matchesName) {
matchesCriteria = false;
}
}
if (event.startTime != null && event.endTime != null) {
final int? effectiveTime =
int.tryParse(item.effectiveTime.toString());
final int? invalidTime = int.tryParse(item.invalidTime.toString());
if (effectiveTime == null || invalidTime == null) {
// Filter by start date only
if (event.startTime != null && event.endTime == null) {
DateTime startDateOnly =
DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal();
startDateOnly = DateTime(startDateOnly.year, startDateOnly.month, startDateOnly.day);
if (effectiveDateOnly.isBefore(startDateOnly)) {
matchesCriteria = false;
} else {
final bool matchesStartTime = effectiveTime >= event.startTime!;
final bool matchesEndTime = invalidTime <= event.endTime!;
if (!matchesStartTime || !matchesEndTime) {
matchesCriteria = false;
}
}
}
if (event.selectedTabIndex == 1 &&
item.passwordStatus.value != 'To Be Effective') {
// Filter by end date only
if (event.endTime != null && event.startTime == null) {
DateTime endDateOnly =
DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal();
endDateOnly = DateTime(endDateOnly.year, endDateOnly.month, endDateOnly.day);
if (invalidDateOnly.isAfter(endDateOnly)) {
matchesCriteria = false;
}
}
// Filter by both start date and end date
if (event.startTime != null && event.endTime != null) {
DateTime startDateOnly =
DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal();
DateTime endDateOnly =
DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal();
startDateOnly = DateTime(startDateOnly.year, startDateOnly.month, startDateOnly.day);
endDateOnly = DateTime(endDateOnly.year, endDateOnly.month, endDateOnly.day);
if (effectiveDateOnly.isBefore(startDateOnly) || invalidDateOnly.isAfter(endDateOnly)) {
matchesCriteria = false;
}
}
// Filter by selected tab index
if (event.selectedTabIndex == 1 && item.passwordStatus.value != 'To be effective') {
matchesCriteria = false;
} else if (event.selectedTabIndex == 2 &&
item.passwordStatus.value != 'Effective') {
} else if (event.selectedTabIndex == 2 && item.passwordStatus.value != 'Effective') {
matchesCriteria = false;
} else if (event.selectedTabIndex == 3 &&
item.passwordStatus.value != 'Expired') {
} else if (event.selectedTabIndex == 3 && item.passwordStatus.value != 'Expired') {
matchesCriteria = false;
}
return matchesCriteria;
}).toList();
emit(TableLoaded(filteredData));
} catch (e) {
emit(FailedState(e.toString()));
@ -206,13 +196,11 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
}
String timestampToDate(dynamic timestamp) {
DateTime dateTime =
DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000);
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000);
return "${dateTime.year}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.day.toString().padLeft(2, '0')}";
}
Future<void> onTabChanged(
TabChangedEvent event, Emitter<AccessState> emit) async {
Future<void> onTabChanged(TabChangedEvent event, Emitter<AccessState> emit) async {
try {
emit(AccessLoaded());
selectedIndex = event.selectedIndex;
@ -221,19 +209,14 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
filteredData = data;
break;
case 1: // To Be Effective
filteredData = data
.where((item) => item.passwordStatus.value == "To Be Effective")
.toList();
filteredData =
data.where((item) => item.passwordStatus.value == "To Be Effective").toList();
break;
case 2: // Effective
filteredData = data
.where((item) => item.passwordStatus.value == "Effective")
.toList();
filteredData = data.where((item) => item.passwordStatus.value == "Effective").toList();
break;
case 3: // Expired
filteredData = data
.where((item) => item.passwordStatus.value == "Expired")
.toList();
filteredData = data.where((item) => item.passwordStatus.value == "Expired").toList();
break;
default:
filteredData = data;

View File

@ -1,4 +1,4 @@
import 'package:syncrow_web/utils/constants/const.dart';
import 'package:syncrow_web/utils/constants/app_enum.dart';
class PasswordModel {
final dynamic passwordId;

View File

@ -1,293 +1,287 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:go_router/go_router.dart';
import 'package:syncrow_web/pages/access_management/bloc/access_bloc.dart';
import 'package:syncrow_web/pages/access_management/bloc/access_event.dart';
import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/common/custom_table.dart';
import 'package:syncrow_web/pages/common/date_time_widget.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/common/text_field/custom_web_textfield.dart';
import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.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/constants/app_enum.dart';
import 'package:syncrow_web/utils/constants/routes_const.dart';
import 'package:syncrow_web/utils/style.dart';
import 'package:syncrow_web/web_layout/web_scaffold.dart';
class AccessManagementPage extends StatelessWidget {
const AccessManagementPage({super.key});
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return WebScaffold(
enableMenuSideba: false,
appBarTitle: Row(
children: [
Text(
'Access Management',
style: Theme.of(context).textTheme.headlineLarge,
)
],
),
appBarBody: [
Text(
'Physical Access',
style: Theme.of(context)
.textTheme
.headlineMedium!
.copyWith(color: Colors.white),
enableMenuSideba: false,
appBarTitle: Row(
children: [
Text(
'Access Management',
style: Theme.of(context).textTheme.headlineLarge,
)
],
),
],
scaffoldBody: BlocProvider(
create: (BuildContext context) => AccessBloc()..add(FetchTableData()),
child: BlocConsumer<AccessBloc, AccessState>(
listener: (context, state) {},
builder: (context, state) {
final accessBloc = BlocProvider.of<AccessBloc>(context);
final filteredData = accessBloc.filteredData;
return state is AccessLoaded
? const Center(child: CircularProgressIndicator())
: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(30),
appBarBody: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Physical Access',
style: Theme.of(context).textTheme.headlineMedium!.copyWith(color: Colors.white),
),
Row(
children: [
InkWell(
onTap: () {
context.go(RoutesConst.home);
},
child: SvgPicture.asset(
height: 20,
width: 20,
Assets.grid,
),
),
const SizedBox(
width: 10,
)
],
),
],
),
],
scaffoldBody: BlocProvider(
create: (BuildContext context) => AccessBloc()..add(FetchTableData()),
child: BlocConsumer<AccessBloc, AccessState>(
listener: (context, state) {},
builder: (context, state) {
final accessBloc = BlocProvider.of<AccessBloc>(context);
final filteredData = accessBloc.filteredData;
return state is AccessLoaded
? const Center(child: CircularProgressIndicator())
: Container(
padding: EdgeInsets.all(30),
height: size.height,
width: size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildTabSelector(context, accessBloc, size),
const SizedBox(height: 20),
_buildSearchFilters(context, accessBloc, size),
const SizedBox(height: 20),
_buildActionButtons(context, accessBloc, size),
const SizedBox(height: 20),
Container(
decoration: containerDecoration,
height: size.height * 0.05,
child: Flexible(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: BlocProvider.of<AccessBloc>(context).tabs.length,
shrinkWrap: true,
itemBuilder: (context, index) {
final isSelected = index ==
BlocProvider.of<AccessBloc>(context).selectedIndex;
return InkWell(
onTap: () {
BlocProvider.of<AccessBloc>(context)
.add(TabChangedEvent(index));
},
child: Container(
decoration: BoxDecoration(
color: ColorsManager.boxColor,
border: Border.all(
color: isSelected ? Colors.blue : Colors.transparent,
width: 2.0,
),
borderRadius: index == 0
? const BorderRadius.only(
topLeft: Radius.circular(10),
bottomLeft: Radius.circular(10))
: index == 3
? const BorderRadius.only(
topRight: Radius.circular(10),
bottomRight: Radius.circular(10))
: null,
),
padding: const EdgeInsets.only(left: 10, right: 10),
child: Center(
child: Text(
BlocProvider.of<AccessBloc>(context).tabs[index],
style: TextStyle(
color: isSelected ? Colors.blue : Colors.black,
),
),
),
),
);
},
),
),
),
const SizedBox(
height: 20,
),
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
textBaseline: TextBaseline.ideographic,
children: [
Container(
width: size.width * 0.15,
child: CustomWebTextField(
controller: accessBloc.passwordName,
isRequired: true,
textFieldName: 'Name',
description: '',
),
),
const SizedBox(
width: 15,
),
DateTimeWebWidget(
icon: Assets.calendarIcon,
isRequired: false,
title: 'Access Time',
size: size,
endTime: () {
accessBloc.add(SelectTime(context: context, isStart: false));
},
startTime: () {
accessBloc.add(SelectTime(context: context, isStart: true));
},
firstString: BlocProvider.of<AccessBloc>(context).startTime,
secondString: BlocProvider.of<AccessBloc>(context).endTime,
),
const SizedBox(
width: 15,
),
SizedBox(
width: size.width * 0.06,
child: Container(
decoration: containerDecoration,
child: DefaultButton(
onPressed: () {
accessBloc.add(FilterDataEvent(
selectedTabIndex: BlocProvider.of<AccessBloc>(
context)
.selectedIndex, // Pass the selected tab index
passwordName:
accessBloc.passwordName.text.toLowerCase(),
startTime: accessBloc.effectiveTimeTimeStamp,
endTime: accessBloc.expirationTimeTimeStamp));
},
borderRadius: 9,
child: const Text('Search'))),
),
const SizedBox(
width: 10,
),
SizedBox(
width: size.width * 0.06,
child: Container(
decoration: containerDecoration,
child: DefaultButton(
onPressed: () {
accessBloc.add(ResetSearch());
},
backgroundColor: ColorsManager.whiteColors,
borderRadius: 9,
child: Text(
'Reset',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.black),
),
),
),
),
],
),
const SizedBox(
height: 20,
),
Wrap(
children: [
Container(
width: size.width * 0.15,
decoration: containerDecoration,
child: DefaultButton(
onPressed: () {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return const VisitorPasswordDialog();
},
).then((v) {
if (v != null) {
accessBloc.add(FetchTableData());
}
});
},
borderRadius: 8,
child: const Text('+ Create Visitor Password ')),
),
const SizedBox(
width: 10,
),
Container(
width: size.width * 0.12,
decoration: containerDecoration,
child: DefaultButton(
borderRadius: 8,
backgroundColor: ColorsManager.whiteColors,
child: Text(
'Admin Password',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.black),
)))
],
),
const SizedBox(
height: 20,
),
Expanded(
child: DynamicTable(
isEmpty: filteredData.isEmpty,
withCheckBox: false,
size: size,
cellDecoration: containerDecoration,
headers: const [
'Name',
'Access Type',
'Access Period',
'Accessible Device',
'Authorizer',
'Authorization Date & Time',
'Access Status'
],
data: filteredData.map((item) {
return [
item.passwordName.toString(),
item.passwordType.value,
('${accessBloc.timestampToDate(item.effectiveTime)} - ${accessBloc.timestampToDate(item.invalidTime)}'),
item.deviceUuid.toString(),
'',
'',
item.passwordStatus.value,
];
}).toList(),
)
// : const Center(child: CircularProgressIndicator()),
)
],
),
),
),
SliverFillRemaining(
child: DynamicTable(
isEmpty: filteredData.isEmpty,
withCheckBox: false,
size: size,
cellDecoration: containerDecoration,
headers: const [
'Name',
'Access Type',
'Access Period',
'Accessible Device',
'Authorizer',
'Authorization Date & Time',
'Access Status'
],
data: filteredData.map((item) {
return [
item.passwordName.toString(),
item.passwordType.value,
('${accessBloc.timestampToDate(item.effectiveTime)} - ${accessBloc.timestampToDate(item.invalidTime)}'),
item.deviceUuid.toString(),
'',
'',
item.passwordStatus.value
];
}).toList(),
),
),
],
);
},
),
),
);
}
Widget _buildTabSelector(
BuildContext context, AccessBloc accessBloc, Size size) {
return Container(
decoration: containerDecoration,
height: size.height * 0.05,
child: Flexible(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: accessBloc.tabs.length,
shrinkWrap: true,
itemBuilder: (context, index) {
final isSelected = index == accessBloc.selectedIndex;
return InkWell(
onTap: () {
accessBloc.add(TabChangedEvent(index));
},
child: Container(
decoration: BoxDecoration(
color: ColorsManager.boxColor,
border: Border.all(
color: isSelected ? Colors.blue : Colors.transparent,
width: 2.0,
),
borderRadius: index == 0
? const BorderRadius.only(
topLeft: Radius.circular(10),
bottomLeft: Radius.circular(10))
: index == accessBloc.tabs.length - 1
? const BorderRadius.only(
topRight: Radius.circular(10),
bottomRight: Radius.circular(10))
: null,
),
padding: const EdgeInsets.only(left: 10, right: 10),
child: Center(
child: Text(
accessBloc.tabs[index],
style: TextStyle(
color: isSelected ? Colors.blue : Colors.black,
),
),
),
),
);
},
),
),
);
}
Widget _buildSearchFilters(
BuildContext context, AccessBloc accessBloc, Size size) {
return Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
textBaseline: TextBaseline.ideographic,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Name',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.black, fontSize: 13),
),
const SizedBox(height: 5),
Container(
height: 43,
width: size.width * 0.15,
decoration: containerDecoration,
child: TextFormField(
controller: accessBloc.passwordName,
style: const TextStyle(color: Colors.black),
decoration:
textBoxDecoration()!.copyWith(hintText: 'Please enter'),
),
),
],
),
const SizedBox(width: 15),
DateTimeWebWidget(
icon: Assets.calendarIcon,
isRequired: false,
title: 'Access Time',
size: size,
endTime: () {
accessBloc.add(SelectTime(context: context, isStart: false));
},
startTime: () {
accessBloc.add(SelectTime(context: context, isStart: true));
},
firstString: accessBloc.startTime,
secondString: accessBloc.endTime,
),
const SizedBox(width: 15),
SizedBox(
height: 45,
width: size.width * 0.06,
child: Container(
decoration: containerDecoration,
child: DefaultButton(
onPressed: () {
accessBloc.add(FilterDataEvent(
selectedTabIndex:
accessBloc.selectedIndex, // Pass the selected tab index
passwordName: accessBloc.passwordName.text.toLowerCase(),
startTime: accessBloc.effectiveTimeTimeStamp,
endTime: accessBloc.expirationTimeTimeStamp,
));
},
borderRadius: 9,
child: const Text('Search'),
),
),
),
const SizedBox(width: 10),
SizedBox(
height: 45,
width: size.width * 0.06,
child: Container(
decoration: containerDecoration,
child: DefaultButton(
onPressed: () {
accessBloc.add(ResetSearch());
},
backgroundColor: ColorsManager.whiteColors,
borderRadius: 9,
child: Text(
'Reset',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.black),
),
),
),
),
],
);
}
Widget _buildActionButtons(
BuildContext context, AccessBloc accessBloc, Size size) {
return Wrap(
children: [
Container(
width: size.width * 0.15,
decoration: containerDecoration,
child: DefaultButton(
onPressed: () {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return const VisitorPasswordDialog();
},
).then((v) {
if (v != null) {
accessBloc.add(FetchTableData());
}
});
},
borderRadius: 8,
child: const Text('+ Create Visitor Password '),
),
),
const SizedBox(width: 10),
Container(
width: size.width * 0.12,
decoration: containerDecoration,
child: DefaultButton(
borderRadius: 8,
backgroundColor: ColorsManager.whiteColors,
child: Text(
'Admin Password',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.black),
),
),
)
],
);
);
})));
}
}