mirror of
https://github.com/SyncrowIOT/web.git
synced 2026-10-24 22:37:56 +00:00
Merge branch 'power_clamp' of https://github.com/SyncrowIOT/web into power_clamp
This commit is contained in:
@@ -5,6 +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/pages/common/hour_picker_dialog.dart';
|
||||
import 'package:syncrow_web/services/access_mang_api.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||
|
||||
@@ -26,7 +27,8 @@ 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();
|
||||
@@ -39,19 +41,28 @@ 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;
|
||||
@@ -73,6 +84,23 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
initialDate: DateTime.now(),
|
||||
firstDate: DateTime.now().add(const Duration(days: -5095)),
|
||||
lastDate: DateTime.now().add(const Duration(days: 2095)),
|
||||
builder: (BuildContext context, Widget? child) {
|
||||
return Theme(
|
||||
data: ThemeData.light().copyWith(
|
||||
colorScheme: ColorScheme.light(
|
||||
primary: ColorsManager.blackColor,
|
||||
onPrimary: Colors.white,
|
||||
onSurface: ColorsManager.grayColor,
|
||||
),
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Colors.blue,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: child!,
|
||||
);
|
||||
},
|
||||
);
|
||||
if (picked != null) {
|
||||
final TimeOfDay? timePicked = await showHourPicker(
|
||||
@@ -88,16 +116,20 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
timePicked.hour,
|
||||
timePicked.minute,
|
||||
);
|
||||
final int selectedTimestamp = selectedDateTime.millisecondsSinceEpoch ~/ 1000;
|
||||
final int selectedTimestamp =
|
||||
selectedDateTime.millisecondsSinceEpoch ~/ 1000;
|
||||
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;
|
||||
effectiveTimeTimeStamp = selectedTimestamp;
|
||||
}
|
||||
} else {
|
||||
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
|
||||
if (effectiveTimeTimeStamp != null &&
|
||||
selectedTimestamp < effectiveTimeTimeStamp!) {
|
||||
CustomSnackBar.displaySnackBar(
|
||||
'Expiration Time cannot be earlier than Effective Time.');
|
||||
} else {
|
||||
@@ -110,7 +142,8 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
emit(ChangeTimeState());
|
||||
}
|
||||
|
||||
Future<void> _filterData(FilterDataEvent event, Emitter<AccessState> emit) async {
|
||||
Future<void> _filterData(
|
||||
FilterDataEvent event, Emitter<AccessState> emit) async {
|
||||
emit(AccessLoaded());
|
||||
try {
|
||||
// Convert search text to lower case for case-insensitive search
|
||||
@@ -119,29 +152,40 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
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 effectiveDateAndTime = DateTime(effectiveDate.year, effectiveDate.month,
|
||||
effectiveDate.day, effectiveDate.hour, effectiveDate.minute);
|
||||
DateTime invalidDateAndTime = DateTime(invalidDate.year, invalidDate.month, invalidDate.day,
|
||||
invalidDate.hour, invalidDate.minute);
|
||||
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 effectiveDateAndTime = DateTime(
|
||||
effectiveDate.year,
|
||||
effectiveDate.month,
|
||||
effectiveDate.day,
|
||||
effectiveDate.hour,
|
||||
effectiveDate.minute);
|
||||
DateTime invalidDateAndTime = DateTime(
|
||||
invalidDate.year,
|
||||
invalidDate.month,
|
||||
invalidDate.day,
|
||||
invalidDate.hour,
|
||||
invalidDate.minute);
|
||||
|
||||
// Filter by password name, making the search case-insensitive
|
||||
if (searchText.isNotEmpty) {
|
||||
final bool matchesName = item.passwordName.toString().toLowerCase().contains(searchText);
|
||||
final bool matchesName =
|
||||
item.passwordName.toString().toLowerCase().contains(searchText);
|
||||
if (!matchesName) {
|
||||
matchesCriteria = false;
|
||||
}
|
||||
}
|
||||
if (searchEmailText.isNotEmpty) {
|
||||
final bool matchesName =
|
||||
item.authorizerEmail.toString().toLowerCase().contains(searchEmailText);
|
||||
final bool matchesName = item.authorizerEmail
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.contains(searchEmailText);
|
||||
if (!matchesName) {
|
||||
matchesCriteria = false;
|
||||
}
|
||||
@@ -149,9 +193,11 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
// Filter by start date only
|
||||
if (event.startTime != null && event.endTime == null) {
|
||||
DateTime startDateTime =
|
||||
DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal();
|
||||
startDateTime = DateTime(startDateTime.year, startDateTime.month, startDateTime.day,
|
||||
startDateTime.hour, startDateTime.minute);
|
||||
DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000)
|
||||
.toUtc()
|
||||
.toLocal();
|
||||
startDateTime = DateTime(startDateTime.year, startDateTime.month,
|
||||
startDateTime.day, startDateTime.hour, startDateTime.minute);
|
||||
if (effectiveDateAndTime.isBefore(startDateTime)) {
|
||||
matchesCriteria = false;
|
||||
}
|
||||
@@ -159,9 +205,11 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
// Filter by end date only
|
||||
if (event.endTime != null && event.startTime == null) {
|
||||
DateTime startDateTime =
|
||||
DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal();
|
||||
startDateTime = DateTime(startDateTime.year, startDateTime.month, startDateTime.day,
|
||||
startDateTime.hour, startDateTime.minute);
|
||||
DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000)
|
||||
.toUtc()
|
||||
.toLocal();
|
||||
startDateTime = DateTime(startDateTime.year, startDateTime.month,
|
||||
startDateTime.day, startDateTime.hour, startDateTime.minute);
|
||||
if (invalidDateAndTime.isAfter(startDateTime)) {
|
||||
matchesCriteria = false;
|
||||
}
|
||||
@@ -170,13 +218,17 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
// Filter by both start date and end date
|
||||
if (event.startTime != null && event.endTime != null) {
|
||||
DateTime startDateTime =
|
||||
DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal();
|
||||
DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000)
|
||||
.toUtc()
|
||||
.toLocal();
|
||||
DateTime endDateTime =
|
||||
DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal();
|
||||
startDateTime = DateTime(startDateTime.year, startDateTime.month, startDateTime.day,
|
||||
startDateTime.hour, startDateTime.minute);
|
||||
endDateTime = DateTime(endDateTime.year, endDateTime.month, endDateTime.day,
|
||||
endDateTime.hour, endDateTime.minute);
|
||||
DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000)
|
||||
.toUtc()
|
||||
.toLocal();
|
||||
startDateTime = DateTime(startDateTime.year, startDateTime.month,
|
||||
startDateTime.day, startDateTime.hour, startDateTime.minute);
|
||||
endDateTime = DateTime(endDateTime.year, endDateTime.month,
|
||||
endDateTime.day, endDateTime.hour, endDateTime.minute);
|
||||
if (effectiveDateAndTime.isBefore(startDateTime) ||
|
||||
invalidDateAndTime.isAfter(endDateTime)) {
|
||||
matchesCriteria = false;
|
||||
@@ -184,11 +236,14 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
}
|
||||
|
||||
// Filter by selected tab index
|
||||
if (event.selectedTabIndex == 1 && item.passwordStatus.value != 'To be effective') {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -214,12 +269,14 @@ 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')} "
|
||||
" ${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.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;
|
||||
@@ -228,14 +285,19 @@ 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;
|
||||
|
||||
@@ -15,8 +15,8 @@ import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||
|
||||
class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
@@ -27,7 +27,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
final isLargeScreen = isLargeScreenSize(context);
|
||||
final isSmallScreen = isSmallScreenSize(context);
|
||||
final isHalfMediumScreen = isHafMediumScreenSize(context);
|
||||
final padding = isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
|
||||
final padding =
|
||||
isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
|
||||
|
||||
return WebScaffold(
|
||||
enableMenuSidebar: false,
|
||||
@@ -37,23 +38,10 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
style: Theme.of(context).textTheme.headlineLarge,
|
||||
),
|
||||
),
|
||||
centerBody: Wrap(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: MediaQuery.of(context).size.width * 0.09),
|
||||
child: Align(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Text(
|
||||
'Physical Access',
|
||||
style: Theme.of(context).textTheme.headlineMedium!.copyWith(color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
rightBody: const NavigateHomeGridView(),
|
||||
scaffoldBody: BlocProvider(
|
||||
create: (BuildContext context) => AccessBloc()..add(FetchTableData()),
|
||||
create: (BuildContext context) =>
|
||||
AccessBloc()..add(FetchTableData()),
|
||||
child: BlocConsumer<AccessBloc, AccessState>(
|
||||
listener: (context, state) {},
|
||||
builder: (context, state) {
|
||||
@@ -107,11 +95,14 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
return [
|
||||
item.passwordName,
|
||||
item.passwordType.value,
|
||||
accessBloc.timestampToDate(item.effectiveTime),
|
||||
accessBloc.timestampToDate(item.invalidTime),
|
||||
accessBloc
|
||||
.timestampToDate(item.effectiveTime),
|
||||
accessBloc
|
||||
.timestampToDate(item.invalidTime),
|
||||
item.deviceName.toString(),
|
||||
item.authorizerEmail.toString(),
|
||||
accessBloc.timestampToDate(item.invalidTime),
|
||||
accessBloc
|
||||
.timestampToDate(item.invalidTime),
|
||||
item.passwordStatus.value,
|
||||
];
|
||||
}).toList(),
|
||||
@@ -122,7 +113,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
})));
|
||||
}
|
||||
|
||||
Wrap _buildVisitorAdminPasswords(BuildContext context, AccessBloc accessBloc) {
|
||||
Wrap _buildVisitorAdminPasswords(
|
||||
BuildContext context, AccessBloc accessBloc) {
|
||||
return Wrap(
|
||||
spacing: 10,
|
||||
runSpacing: 10,
|
||||
@@ -147,8 +139,9 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
},
|
||||
borderRadius: 8,
|
||||
child: Text(
|
||||
'+ Create Visitor Password ',
|
||||
style: context.textTheme.titleSmall!.copyWith(color: Colors.white, fontSize: 12),
|
||||
'Create Visitor Password ',
|
||||
style: context.textTheme.titleSmall!
|
||||
.copyWith(color: Colors.white, fontSize: 12),
|
||||
)),
|
||||
),
|
||||
Container(
|
||||
@@ -160,7 +153,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
backgroundColor: ColorsManager.whiteColors,
|
||||
child: Text(
|
||||
'Admin Password',
|
||||
style: context.textTheme.titleSmall!.copyWith(color: Colors.black, fontSize: 12),
|
||||
style: context.textTheme.titleSmall!
|
||||
.copyWith(color: Colors.black, fontSize: 12),
|
||||
)),
|
||||
),
|
||||
],
|
||||
@@ -183,6 +177,16 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
isRequired: false,
|
||||
textFieldName: 'Name',
|
||||
description: '',
|
||||
onSubmitted: (value) {
|
||||
accessBloc.add(FilterDataEvent(
|
||||
emailAuthorizer:
|
||||
accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||
selectedTabIndex:
|
||||
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||
endTime: accessBloc.expirationTimeTimeStamp));
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 15),
|
||||
@@ -194,6 +198,16 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
isRequired: false,
|
||||
textFieldName: 'Authorizer',
|
||||
description: '',
|
||||
onSubmitted: (value) {
|
||||
accessBloc.add(FilterDataEvent(
|
||||
emailAuthorizer:
|
||||
accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||
selectedTabIndex:
|
||||
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||
endTime: accessBloc.expirationTimeTimeStamp));
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 15),
|
||||
@@ -218,7 +232,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
onSearch: () {
|
||||
accessBloc.add(FilterDataEvent(
|
||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
selectedTabIndex:
|
||||
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||
endTime: accessBloc.expirationTimeTimeStamp));
|
||||
@@ -239,12 +254,21 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
SizedBox(
|
||||
width: 300,
|
||||
child: CustomWebTextField(
|
||||
controller: accessBloc.passwordName,
|
||||
isRequired: true,
|
||||
height: 40,
|
||||
textFieldName: 'Name',
|
||||
description: '',
|
||||
),
|
||||
controller: accessBloc.passwordName,
|
||||
isRequired: true,
|
||||
height: 40,
|
||||
textFieldName: 'Name',
|
||||
description: '',
|
||||
onSubmitted: (value) {
|
||||
accessBloc.add(FilterDataEvent(
|
||||
emailAuthorizer:
|
||||
accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||
selectedTabIndex:
|
||||
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||
endTime: accessBloc.expirationTimeTimeStamp));
|
||||
}),
|
||||
),
|
||||
DateTimeWebWidget(
|
||||
icon: Assets.calendarIcon,
|
||||
@@ -264,7 +288,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
onSearch: () {
|
||||
accessBloc.add(FilterDataEvent(
|
||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
selectedTabIndex:
|
||||
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||
endTime: accessBloc.expirationTimeTimeStamp));
|
||||
|
||||
@@ -26,9 +26,12 @@ class CurtainToggle extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ClipOval(
|
||||
child: Container(
|
||||
@@ -41,6 +44,9 @@ class CurtainToggle extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
width: 35,
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_managment_bloc.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 DynamicTable extends StatefulWidget {
|
||||
final List<String> headers;
|
||||
@@ -45,6 +46,8 @@ class DynamicTable extends StatefulWidget {
|
||||
class _DynamicTableState extends State<DynamicTable> {
|
||||
late List<bool> _selectedRows;
|
||||
bool _selectAll = false;
|
||||
final ScrollController _verticalScrollController = ScrollController();
|
||||
final ScrollController _horizontalScrollController = ScrollController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -102,68 +105,78 @@ class _DynamicTableState extends State<DynamicTable> {
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: widget.cellDecoration,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SizedBox(
|
||||
width: widget.size.width,
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: widget.headerDecoration ?? BoxDecoration(color: Colors.grey[200]),
|
||||
child: Row(
|
||||
child: Scrollbar(
|
||||
controller: _verticalScrollController,
|
||||
thumbVisibility: true,
|
||||
trackVisibility: true,
|
||||
child: Scrollbar(
|
||||
controller: _horizontalScrollController,
|
||||
thumbVisibility: false,
|
||||
trackVisibility: false,
|
||||
notificationPredicate: (notif) => notif.depth == 1,
|
||||
child: SingleChildScrollView(
|
||||
controller: _verticalScrollController,
|
||||
child: SingleChildScrollView(
|
||||
controller: _horizontalScrollController,
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SizedBox(
|
||||
width: widget.size.width,
|
||||
child: Column(
|
||||
children: [
|
||||
if (widget.withCheckBox) _buildSelectAllCheckbox(),
|
||||
...widget.headers.map((header) => _buildTableHeaderCell(header)),
|
||||
],
|
||||
),
|
||||
),
|
||||
widget.isEmpty
|
||||
? Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
Container(
|
||||
decoration: widget.headerDecoration ??
|
||||
const BoxDecoration(
|
||||
color: ColorsManager.boxColor,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
if (widget.withCheckBox) _buildSelectAllCheckbox(),
|
||||
...widget.headers.map((header) => _buildTableHeaderCell(header)),
|
||||
],
|
||||
),
|
||||
),
|
||||
widget.isEmpty
|
||||
? Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(Assets.emptyTable),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
Column(
|
||||
children: [
|
||||
SvgPicture.asset(Assets.emptyTable),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
Text(
|
||||
widget.tableName == 'AccessManagement' ? 'No Password ' : 'No Devices',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(color: ColorsManager.grayColor),
|
||||
)
|
||||
],
|
||||
),
|
||||
Text(
|
||||
// no password
|
||||
widget.tableName == 'AccessManagement' ? 'No Password ' : 'No Devices',
|
||||
style:
|
||||
Theme.of(context).textTheme.bodySmall!.copyWith(color: ColorsManager.grayColor),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
children: List.generate(widget.data.length, (index) {
|
||||
final row = widget.data[index];
|
||||
return Row(
|
||||
children: [
|
||||
if (widget.withCheckBox) _buildRowCheckbox(index, widget.size.height * 0.08),
|
||||
...row.map((cell) => _buildTableCell(cell.toString(), widget.size.height * 0.08)),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: Expanded(
|
||||
child: Container(
|
||||
color: Colors.white,
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: widget.data.length,
|
||||
itemBuilder: (context, index) {
|
||||
final row = widget.data[index];
|
||||
return Row(
|
||||
children: [
|
||||
if (widget.withCheckBox) _buildRowCheckbox(index, widget.size.height * 0.10),
|
||||
...row.map((cell) => _buildTableCell(cell.toString(), widget.size.height * 0.10)),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -173,7 +186,6 @@ class _DynamicTableState extends State<DynamicTable> {
|
||||
Widget _buildSelectAllCheckbox() {
|
||||
return Container(
|
||||
width: 50,
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
decoration: const BoxDecoration(
|
||||
border: Border.symmetric(
|
||||
vertical: BorderSide(color: ColorsManager.boxDivider),
|
||||
@@ -198,6 +210,7 @@ class _DynamicTableState extends State<DynamicTable> {
|
||||
width: 1.0,
|
||||
),
|
||||
),
|
||||
color: ColorsManager.whiteColors,
|
||||
),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Center(
|
||||
@@ -219,15 +232,16 @@ class _DynamicTableState extends State<DynamicTable> {
|
||||
vertical: BorderSide(color: ColorsManager.boxDivider),
|
||||
),
|
||||
),
|
||||
constraints: const BoxConstraints.expand(height: 40),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4),
|
||||
child: Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
style: context.textTheme.titleSmall!.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 13,
|
||||
color: Color(0xFF999999),
|
||||
),
|
||||
maxLines: 2,
|
||||
),
|
||||
@@ -276,6 +290,7 @@ class _DynamicTableState extends State<DynamicTable> {
|
||||
width: 1.0,
|
||||
),
|
||||
),
|
||||
color: Colors.white,
|
||||
),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
@@ -286,7 +301,7 @@ class _DynamicTableState extends State<DynamicTable> {
|
||||
: (batteryLevel != null && batteryLevel > 20)
|
||||
? ColorsManager.green
|
||||
: statusColor,
|
||||
fontSize: 10,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w400),
|
||||
maxLines: 2,
|
||||
),
|
||||
|
||||
@@ -81,7 +81,10 @@ class DateTimeWebWidget extends StatelessWidget {
|
||||
const SizedBox(
|
||||
width: 30,
|
||||
),
|
||||
const Icon(Icons.arrow_right_alt),
|
||||
const Icon(
|
||||
Icons.arrow_right_alt,
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 30,
|
||||
),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class StatefulTextField extends StatefulWidget {
|
||||
const StatefulTextField(
|
||||
@@ -25,13 +26,15 @@ class StatefulTextField extends StatefulWidget {
|
||||
class _StatefulTextFieldState extends State<StatefulTextField> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomTextField(
|
||||
title: widget.title,
|
||||
controller: widget.controller,
|
||||
hintText: widget.hintText,
|
||||
width: widget.width,
|
||||
elevation: widget.elevation,
|
||||
onSubmittedFun: widget.onSubmitted);
|
||||
return Container(
|
||||
child: CustomTextField(
|
||||
title: widget.title,
|
||||
controller: widget.controller,
|
||||
hintText: widget.hintText,
|
||||
width: widget.width,
|
||||
elevation: widget.elevation,
|
||||
onSubmittedFun: widget.onSubmitted),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,17 +76,20 @@ class CustomTextField extends StatelessWidget {
|
||||
child: Container(
|
||||
width: width,
|
||||
height: 45,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
decoration: containerDecoration,
|
||||
|
||||
// decoration: BoxDecoration(
|
||||
// color: Colors.white,
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
// ),
|
||||
child: TextFormField(
|
||||
controller: controller,
|
||||
style: const TextStyle(color: Colors.black),
|
||||
decoration: InputDecoration(
|
||||
hintText: hintText,
|
||||
hintStyle: const TextStyle(fontSize: 12),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
border: InputBorder.none,
|
||||
),
|
||||
onFieldSubmitted: (_) {
|
||||
|
||||
@@ -13,6 +13,7 @@ class CustomWebTextField extends StatelessWidget {
|
||||
this.validator,
|
||||
this.hintText,
|
||||
this.height,
|
||||
this.onSubmitted,
|
||||
});
|
||||
|
||||
final bool isRequired;
|
||||
@@ -22,6 +23,7 @@ class CustomWebTextField extends StatelessWidget {
|
||||
final String? Function(String?)? validator;
|
||||
final String? hintText;
|
||||
final double? height;
|
||||
final ValueChanged<String>? onSubmitted;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -32,23 +34,25 @@ class CustomWebTextField extends StatelessWidget {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
|
||||
Row(
|
||||
children: [
|
||||
if (isRequired)
|
||||
Text('* ',
|
||||
Row(
|
||||
children: [
|
||||
if (isRequired)
|
||||
Text(
|
||||
'* ',
|
||||
style: Theme.of(context)
|
||||
.textTheme.bodyMedium!
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(color: Colors.red),
|
||||
),
|
||||
Text(
|
||||
textFieldName,
|
||||
style: Theme.of(context)
|
||||
.textTheme.bodySmall!
|
||||
.copyWith(color: Colors.black, fontSize: 13),
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
textFieldName,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(color: Colors.black, fontSize: 13),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
@@ -68,17 +72,7 @@ class CustomWebTextField extends StatelessWidget {
|
||||
),
|
||||
Container(
|
||||
height: height ?? 35,
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: const Color(0xFFF5F6F7),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.3),
|
||||
spreadRadius: 2,
|
||||
blurRadius: 3,
|
||||
offset: const Offset(1, 1), // changes position of shadow
|
||||
),
|
||||
]
|
||||
),
|
||||
decoration: containerDecoration,
|
||||
child: TextFormField(
|
||||
validator: validator,
|
||||
controller: controller,
|
||||
@@ -88,6 +82,7 @@ class CustomWebTextField extends StatelessWidget {
|
||||
hintStyle: context.textTheme.titleSmall!
|
||||
.copyWith(color: Colors.grey, fontSize: 12),
|
||||
hintText: hintText ?? 'Please enter'),
|
||||
onFieldSubmitted: onSubmitted,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -40,7 +40,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
: 1,
|
||||
mainAxisExtent: 140,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 12,
|
||||
mainAxisSpacing: 16,
|
||||
),
|
||||
children: [
|
||||
ToggleWidget(
|
||||
@@ -81,6 +81,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
IconButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
Icons.remove,
|
||||
@@ -108,6 +109,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
),
|
||||
Text('m', style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor)),
|
||||
IconButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
Icons.add,
|
||||
@@ -127,7 +129,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
deviceId: device.uuid!,
|
||||
code: 'child_lock',
|
||||
value: state.status.childLock,
|
||||
label: 'Child Lock',
|
||||
label: 'Lock',
|
||||
icon: state.status.childLock ? Assets.acLock : Assets.unlock,
|
||||
onChange: (value) {
|
||||
context.read<AcBloc>().add(
|
||||
|
||||
@@ -8,7 +8,6 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_search_filters.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/device_batch_control_dialog.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/device_control_dialog.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/format_date_time.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
@@ -58,12 +57,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: [
|
||||
@@ -72,7 +74,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),
|
||||
@@ -94,11 +98,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,
|
||||
),
|
||||
);
|
||||
@@ -112,7 +119,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,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -123,16 +132,20 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
|
||||
padding: isLargeScreenSize(context)
|
||||
? const EdgeInsets.all(30)
|
||||
: const EdgeInsets.all(15),
|
||||
child: DynamicTable(
|
||||
withSelectAll: true,
|
||||
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,
|
||||
size: MediaQuery.of(context).size,
|
||||
uuidIndex: 2,
|
||||
headers: const [
|
||||
'Device Name',
|
||||
@@ -152,17 +165,26 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
||||
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>().selectedDevices.map((device) => device.uuid!).toList(),
|
||||
initialSelectedIds: context
|
||||
.read<DeviceManagementBloc>()
|
||||
.selectedDevices
|
||||
.map((device) => device.uuid!)
|
||||
.toList(),
|
||||
isEmpty: devicesToShow.isEmpty,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:syncrow_web/pages/common/text_field/custom_text_field.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_managment_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/search_reset_buttons.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class DeviceSearchFilters extends StatefulWidget {
|
||||
const DeviceSearchFilters({super.key});
|
||||
@@ -12,7 +13,8 @@ class DeviceSearchFilters extends StatefulWidget {
|
||||
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
|
||||
}
|
||||
|
||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperResponsiveLayout {
|
||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
||||
with HelperResponsiveLayout {
|
||||
final TextEditingController communityController = TextEditingController();
|
||||
final TextEditingController unitNameController = TextEditingController();
|
||||
final TextEditingController productNameController = TextEditingController();
|
||||
@@ -34,7 +36,8 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperRe
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchField("Unit Name", unitNameController, 200),
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchField("Device Name / Product Name", productNameController, 300),
|
||||
_buildSearchField(
|
||||
"Device Name / Product Name", productNameController, 300),
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchResetButtons(),
|
||||
],
|
||||
@@ -59,19 +62,22 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperRe
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSearchField(String title, TextEditingController controller, double width) {
|
||||
return StatefulTextField(
|
||||
title: title,
|
||||
width: width,
|
||||
elevation: 2,
|
||||
controller: controller,
|
||||
onSubmitted: () {
|
||||
context.read<DeviceManagementBloc>().add(SearchDevices(
|
||||
productName: productNameController.text,
|
||||
unitName: unitNameController.text,
|
||||
community: communityController.text,
|
||||
searchField: true));
|
||||
},
|
||||
Widget _buildSearchField(
|
||||
String title, TextEditingController controller, double width) {
|
||||
return Container(
|
||||
child: StatefulTextField(
|
||||
title: title,
|
||||
width: width,
|
||||
elevation: 2,
|
||||
controller: controller,
|
||||
onSubmitted: () {
|
||||
context.read<DeviceManagementBloc>().add(SearchDevices(
|
||||
productName: productNameController.text,
|
||||
unitName: unitNameController.text,
|
||||
community: communityController.text,
|
||||
searchField: true));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/device_managment/gateway/bloc/gate_way_bloc.da
|
||||
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
|
||||
import 'package:syncrow_web/pages/visitor_password/model/device_model.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
|
||||
class GateWayControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
@@ -25,25 +26,61 @@ class GateWayControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
if (state is GatewayLoadingState) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (state is UpdateGatewayState) {
|
||||
return GridView.builder(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 50),
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: isLarge || isExtraLarge
|
||||
? 3
|
||||
: isMedium
|
||||
? 2
|
||||
: 1,
|
||||
mainAxisExtent: 140,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 12,
|
||||
),
|
||||
itemCount: state.list.length,
|
||||
itemBuilder: (context, index) {
|
||||
final device = state.list[index];
|
||||
return _DeviceItem(device: device);
|
||||
},
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 50),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"Bluetooth Devices:",
|
||||
style: context.textTheme.bodyMedium!.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
"No devices found",
|
||||
style: context.textTheme.bodySmall!.copyWith(
|
||||
color: ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
Text(
|
||||
"ZigBee Devices:",
|
||||
style: context.textTheme.bodyMedium!.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
GridView.builder(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 50),
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: isLarge || isExtraLarge
|
||||
? 3
|
||||
: isMedium
|
||||
? 2
|
||||
: 1,
|
||||
mainAxisExtent: 140,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 12,
|
||||
),
|
||||
itemCount: state.list.length,
|
||||
itemBuilder: (context, index) {
|
||||
final device = state.list[index];
|
||||
return _DeviceItem(device: device);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return const Center(child: Text('Error fetching status'));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/helper/route_controls_based_code.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/device_batch_control_dialog.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/format_date_time.dart';
|
||||
|
||||
@@ -31,7 +32,7 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
||||
children: [
|
||||
const SizedBox(),
|
||||
Text(
|
||||
device.productName ?? 'Device Control',
|
||||
getBatchDialogName(device),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 22,
|
||||
@@ -64,7 +65,7 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_buildDeviceInfoSection(),
|
||||
const SizedBox(height: 20),
|
||||
//const SizedBox(height: 20),
|
||||
//// BUILD DEVICE CONTROLS
|
||||
///
|
||||
//// ROUTE TO SPECIFIC CONTROL VIEW BASED ON DEVICE CATEGORY
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class DeviceControlsContainer extends StatelessWidget {
|
||||
const DeviceControlsContainer({required this.child, this.padding, super.key});
|
||||
@@ -8,21 +7,21 @@ class DeviceControlsContainer extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
return Card(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: ColorsManager.greyColor.withOpacity(0.2),
|
||||
|
||||
// boxShadow: <BoxShadow>[
|
||||
// BoxShadow(
|
||||
// color: ColorsManager.blackColor.withOpacity(0.05),
|
||||
// blurRadius: 6.0,
|
||||
// offset: const Offset(0, 5),
|
||||
// spreadRadius: 0)
|
||||
// ],
|
||||
),
|
||||
padding: EdgeInsets.all(padding ?? 12),
|
||||
child: child,
|
||||
elevation: 3,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade100,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
padding:
|
||||
EdgeInsets.symmetric(vertical: padding ?? 10, horizontal: padding ?? 16), //EdgeInsets.all(padding ?? 12),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,4 +42,4 @@ abstract class ColorsManager {
|
||||
static const Color textGreen = Color(0xFF008905);
|
||||
static const Color yaGreen = Color(0xFFFFBF44);
|
||||
}
|
||||
//0036E6
|
||||
//background: #999999;
|
||||
|
||||
@@ -60,23 +60,29 @@ class Assets {
|
||||
static const String nobodyTime = "assets/icons/nobody_time.svg";
|
||||
|
||||
// Automation functions
|
||||
static const String tempPasswordUnlock = "assets/icons/automation_functions/temp_password_unlock.svg";
|
||||
static const String doorlockNormalOpen = "assets/icons/automation_functions/doorlock_normal_open.svg";
|
||||
static const String tempPasswordUnlock =
|
||||
"assets/icons/automation_functions/temp_password_unlock.svg";
|
||||
static const String doorlockNormalOpen =
|
||||
"assets/icons/automation_functions/doorlock_normal_open.svg";
|
||||
static const String doorbell = "assets/icons/automation_functions/doorbell.svg";
|
||||
static const String remoteUnlockViaApp = "assets/icons/automation_functions/remote_unlock_via_app.svg";
|
||||
static const String remoteUnlockViaApp =
|
||||
"assets/icons/automation_functions/remote_unlock_via_app.svg";
|
||||
static const String doubleLock = "assets/icons/automation_functions/double_lock.svg";
|
||||
static const String selfTestResult = "assets/icons/automation_functions/self_test_result.svg";
|
||||
static const String lockAlarm = "assets/icons/automation_functions/lock_alarm.svg";
|
||||
static const String presenceState = "assets/icons/automation_functions/presence_state.svg";
|
||||
static const String currentTemp = "assets/icons/automation_functions/current_temp.svg";
|
||||
static const String presence = "assets/icons/automation_functions/presence.svg";
|
||||
static const String residualElectricity = "assets/icons/automation_functions/residual_electricity.svg";
|
||||
static const String residualElectricity =
|
||||
"assets/icons/automation_functions/residual_electricity.svg";
|
||||
static const String hijackAlarm = "assets/icons/automation_functions/hijack_alarm.svg";
|
||||
static const String passwordUnlock = "assets/icons/automation_functions/password_unlock.svg";
|
||||
static const String remoteUnlockRequest = "assets/icons/automation_functions/remote_unlock_req.svg";
|
||||
static const String remoteUnlockRequest =
|
||||
"assets/icons/automation_functions/remote_unlock_req.svg";
|
||||
static const String cardUnlock = "assets/icons/automation_functions/card_unlock.svg";
|
||||
static const String motion = "assets/icons/automation_functions/motion.svg";
|
||||
static const String fingerprintUnlock = "assets/icons/automation_functions/fingerprint_unlock.svg";
|
||||
static const String fingerprintUnlock =
|
||||
"assets/icons/automation_functions/fingerprint_unlock.svg";
|
||||
|
||||
// Presence Sensor Assets
|
||||
static const String sensorMotionIcon = "assets/icons/sensor_motion_ic.svg";
|
||||
@@ -169,12 +175,21 @@ class Assets {
|
||||
//assets/icons/2gang.svg
|
||||
static const String twoGang = 'assets/icons/2gang.svg';
|
||||
|
||||
|
||||
|
||||
static const String frequencyIcon = "assets/icons/frequency_icon.svg";
|
||||
static const String voltMeterIcon = "assets/icons/volt_meter_icon.svg";
|
||||
static const String powerActiveIcon = "assets/icons/power_active_icon.svg";
|
||||
static const String searchIcon = "assets/icons/search_icon.svg";
|
||||
static const String voltageIcon = "assets/icons/voltage_icon.svg";
|
||||
static const String speedoMeter = "assets/icons/speedo_meter.svg";
|
||||
//assets/icons/account_setting.svg
|
||||
static const String accountSetting = 'assets/icons/account_setting.svg';
|
||||
|
||||
//assets/icons/settings.svg
|
||||
static const String settings = 'assets/icons/settings.svg';
|
||||
|
||||
//assets/icons/sign_out.svg
|
||||
static const String signOut = 'assets/icons/sign_out.svg';
|
||||
|
||||
//assets/icons/logo_grey.svg
|
||||
static const String logoGrey = 'assets/icons/logo-grey.svg';
|
||||
}
|
||||
|
||||
@@ -33,12 +33,11 @@ InputDecoration? textBoxDecoration({bool suffixIcon = false}) =>
|
||||
BoxDecoration containerDecoration = BoxDecoration(
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.5),
|
||||
spreadRadius: 5,
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 3), // changes position of shadow
|
||||
color: Colors.grey.withOpacity(0.3),
|
||||
spreadRadius: 2,
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 5), // changes position of shadow
|
||||
),
|
||||
],
|
||||
color: ColorsManager.boxColor,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(10)));
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
final myTheme = ThemeData(
|
||||
fontFamily: 'Aftika',
|
||||
useMaterial3: true,
|
||||
textTheme: const TextTheme(
|
||||
bodySmall: TextStyle(
|
||||
fontSize: 13,
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
|
||||
class UserDropdownMenu extends StatefulWidget {
|
||||
const UserDropdownMenu({super.key, required this.user});
|
||||
final UserModel? user;
|
||||
|
||||
@override
|
||||
_UserDropdownMenuState createState() => _UserDropdownMenuState();
|
||||
}
|
||||
|
||||
class _UserDropdownMenuState extends State<UserDropdownMenu> {
|
||||
bool _isDropdownOpen = false;
|
||||
|
||||
void _toggleDropdown() {
|
||||
setState(() {
|
||||
_isDropdownOpen = !_isDropdownOpen;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
_toggleDropdown();
|
||||
await _showPopupMenu(context);
|
||||
setState(() {
|
||||
_isDropdownOpen = false;
|
||||
});
|
||||
},
|
||||
child: Transform.rotate(
|
||||
angle: _isDropdownOpen ? -1.5708 : 1.5708,
|
||||
child: const Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
color: Colors.white,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _showPopupMenu(BuildContext context) async {
|
||||
final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
final RelativeRect position = RelativeRect.fromRect(
|
||||
Rect.fromLTRB(
|
||||
overlay.size.width,
|
||||
75,
|
||||
0,
|
||||
overlay.size.height,
|
||||
),
|
||||
Offset.zero & overlay.size,
|
||||
);
|
||||
|
||||
await showMenu(
|
||||
context: context,
|
||||
position: position,
|
||||
color: ColorsManager.whiteColors,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomRight: Radius.circular(10),
|
||||
bottomLeft: Radius.circular(10),
|
||||
),
|
||||
),
|
||||
items: <PopupMenuEntry>[
|
||||
PopupMenuItem(
|
||||
onTap: () {},
|
||||
child: ListTile(
|
||||
leading: SvgPicture.asset(Assets.accountSetting),
|
||||
title: Text(
|
||||
"Account Settings",
|
||||
style: context.textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: () {},
|
||||
child: ListTile(
|
||||
leading: SvgPicture.asset(Assets.settings),
|
||||
title: Text(
|
||||
"Settings",
|
||||
style: context.textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
final size = MediaQuery.of(context).size;
|
||||
return AlertDialog(
|
||||
alignment: Alignment.center,
|
||||
content: SizedBox(
|
||||
height: 200,
|
||||
width: 400,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 24, left: 24, right: 24),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Image.asset(
|
||||
Assets.blackLogo,
|
||||
height: 40,
|
||||
width: 200,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: Text(
|
||||
'Log out of your Syncrow account',
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
SizedBox.square(
|
||||
dimension: 80,
|
||||
child: CircleAvatar(
|
||||
backgroundColor: ColorsManager.whiteColors,
|
||||
child: SizedBox.square(
|
||||
dimension: 78,
|
||||
child: SvgPicture.asset(
|
||||
Assets.logoGrey,
|
||||
fit: BoxFit.fitHeight,
|
||||
height: 80,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'${widget.user?.firstName ?? ''} ${widget.user?.lastName}',
|
||||
style: Theme.of(context).textTheme.titleMedium!.copyWith(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
' ${widget.user?.email}',
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actionsAlignment: MainAxisAlignment.center,
|
||||
actions: [
|
||||
SizedBox(
|
||||
width: 200,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
context.pop();
|
||||
},
|
||||
child: DefaultButton(
|
||||
backgroundColor: ColorsManager.boxColor,
|
||||
elevation: 1,
|
||||
child: Text(
|
||||
'Cancel',
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
AuthBloc.logout();
|
||||
context.go(RoutesConst.auth);
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 200,
|
||||
child: DefaultButton(
|
||||
elevation: 1,
|
||||
child: Text(
|
||||
'Logout',
|
||||
style:
|
||||
Theme.of(context).textTheme.bodyMedium!.copyWith(fontSize: 12, color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
]);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: ListTile(
|
||||
leading: SvgPicture.asset(Assets.signOut),
|
||||
title: Text(
|
||||
"Log Out",
|
||||
style: context.textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
).then((value) {
|
||||
setState(() {
|
||||
_isDropdownOpen = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/pages/common/custom_dialog.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
import 'package:syncrow_web/utils/user_drop_down_menu.dart';
|
||||
|
||||
class WebAppBar extends StatefulWidget {
|
||||
final Widget? title;
|
||||
@@ -58,15 +56,15 @@ class _WebAppBarState extends State<WebAppBar> with HelperResponsiveLayout {
|
||||
if (widget.rightBody != null) widget.rightBody!,
|
||||
Row(
|
||||
children: [
|
||||
const SizedBox.square(
|
||||
SizedBox.square(
|
||||
dimension: 40,
|
||||
child: CircleAvatar(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: ColorsManager.whiteColors,
|
||||
child: SizedBox.square(
|
||||
dimension: 35,
|
||||
child: CircleAvatar(
|
||||
backgroundColor: Colors.grey,
|
||||
child: FlutterLogo(),
|
||||
child: SvgPicture.asset(
|
||||
Assets.logoGrey,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -112,15 +110,15 @@ class _WebAppBarState extends State<WebAppBar> with HelperResponsiveLayout {
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
const SizedBox.square(
|
||||
SizedBox.square(
|
||||
dimension: 40,
|
||||
child: CircleAvatar(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: ColorsManager.whiteColors,
|
||||
child: SizedBox.square(
|
||||
dimension: 35,
|
||||
child: CircleAvatar(
|
||||
backgroundColor: Colors.grey,
|
||||
child: FlutterLogo(),
|
||||
child: SvgPicture.asset(
|
||||
Assets.logoGrey,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -136,54 +134,55 @@ class _WebAppBarState extends State<WebAppBar> with HelperResponsiveLayout {
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
showCustomDialog(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
title: 'Logout',
|
||||
message: 'Are you sure you want to logout?',
|
||||
actions: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
AuthBloc.logout();
|
||||
context.go(RoutesConst.auth);
|
||||
},
|
||||
child: DefaultButton(
|
||||
child: Text(
|
||||
'Ok',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(fontSize: 12, color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.pop();
|
||||
},
|
||||
child: DefaultButton(
|
||||
child: Text(
|
||||
'Cancel',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(fontSize: 12, color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
child: const Icon(
|
||||
Icons.logout,
|
||||
color: ColorsManager.whiteColors,
|
||||
),
|
||||
)
|
||||
UserDropdownMenu(user: user),
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// showCustomDialog(
|
||||
// context: context,
|
||||
// barrierDismissible: true,
|
||||
// title: 'Logout',
|
||||
// message: 'Are you sure you want to logout?',
|
||||
// actions: [
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// AuthBloc.logout();
|
||||
// context.go(RoutesConst.auth);
|
||||
// },
|
||||
// child: DefaultButton(
|
||||
// child: Text(
|
||||
// 'Ok',
|
||||
// style: Theme.of(context)
|
||||
// .textTheme
|
||||
// .bodyMedium!
|
||||
// .copyWith(fontSize: 12, color: Colors.white),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(
|
||||
// height: 10,
|
||||
// ),
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// context.pop();
|
||||
// },
|
||||
// child: DefaultButton(
|
||||
// child: Text(
|
||||
// 'Cancel',
|
||||
// style: Theme.of(context)
|
||||
// .textTheme
|
||||
// .bodyMedium!
|
||||
// .copyWith(fontSize: 12, color: Colors.white),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// },
|
||||
// child: const Icon(
|
||||
// Icons.logout,
|
||||
// color: ColorsManager.whiteColors,
|
||||
// ),
|
||||
// )
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user