mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-09 06:37:20 +00:00
merged with dev and access_bugs and solved conflicts
This commit is contained in:
18
assets/images/grid.svg
Normal file
18
assets/images/grid.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1423_2976)">
|
||||
<path d="M4.5 17.5004H2C1.46957 17.5004 0.960859 17.7111 0.585786 18.0862C0.210714 18.4612 0 18.9699 0 19.5004L0 22.0004C0 22.5308 0.210714 23.0395 0.585786 23.4146C0.960859 23.7896 1.46957 24.0004 2 24.0004H4.5C5.03043 24.0004 5.53914 23.7896 5.91421 23.4146C6.28929 23.0395 6.5 22.5308 6.5 22.0004V19.5004C6.5 18.9699 6.28929 18.4612 5.91421 18.0862C5.53914 17.7111 5.03043 17.5004 4.5 17.5004ZM4.5 22.0004H2V19.5004H4.5V22.0004Z" fill="white"/>
|
||||
<path d="M22 17.5004H19.5C18.9696 17.5004 18.4609 17.7111 18.0858 18.0862C17.7107 18.4612 17.5 18.9699 17.5 19.5004V22.0004C17.5 22.5308 17.7107 23.0395 18.0858 23.4146C18.4609 23.7896 18.9696 24.0004 19.5 24.0004H22C22.5304 24.0004 23.0391 23.7896 23.4142 23.4146C23.7893 23.0395 24 22.5308 24 22.0004V19.5004C24 18.9699 23.7893 18.4612 23.4142 18.0862C23.0391 17.7111 22.5304 17.5004 22 17.5004ZM22 22.0004H19.5V19.5004H22V22.0004Z" fill="white"/>
|
||||
<path d="M4.5 8.74976H2C1.46957 8.74976 0.960859 8.96047 0.585786 9.33554C0.210714 9.71061 0 10.2193 0 10.7498L0 13.2497C0 13.7802 0.210714 14.2889 0.585786 14.664C0.960859 15.039 1.46957 15.2497 2 15.2497H4.5C5.03043 15.2497 5.53914 15.039 5.91421 14.664C6.28929 14.2889 6.5 13.7802 6.5 13.2497V10.7498C6.5 10.2193 6.28929 9.71061 5.91421 9.33554C5.53914 8.96047 5.03043 8.74976 4.5 8.74976ZM4.5 13.2497H2V10.7498H4.5V13.2497Z" fill="white"/>
|
||||
<path d="M22 8.74976H19.5C18.9696 8.74976 18.4609 8.96047 18.0858 9.33554C17.7107 9.71061 17.5 10.2193 17.5 10.7498V13.2497C17.5 13.7802 17.7107 14.2889 18.0858 14.664C18.4609 15.039 18.9696 15.2497 19.5 15.2497H22C22.5304 15.2497 23.0391 15.039 23.4142 14.664C23.7893 14.2889 24 13.7802 24 13.2497V10.7498C24 10.2193 23.7893 9.71061 23.4142 9.33554C23.0391 8.96047 22.5304 8.74976 22 8.74976ZM22 13.2497H19.5V10.7498H22V13.2497Z" fill="white"/>
|
||||
<path d="M4.5 0H2C1.46957 0 0.960859 0.210714 0.585786 0.585786C0.210714 0.960859 0 1.46957 0 2L0 4.5C0 5.03043 0.210714 5.53914 0.585786 5.91421C0.960859 6.28929 1.46957 6.5 2 6.5H4.5C5.03043 6.5 5.53914 6.28929 5.91421 5.91421C6.28929 5.53914 6.5 5.03043 6.5 4.5V2C6.5 1.46957 6.28929 0.960859 5.91421 0.585786C5.53914 0.210714 5.03043 0 4.5 0V0ZM4.5 4.5H2V2H4.5V4.5Z" fill="white"/>
|
||||
<path d="M13.25 17.5004H10.75C10.2196 17.5004 9.71086 17.7111 9.33579 18.0862C8.96071 18.4612 8.75 18.9699 8.75 19.5004V22.0004C8.75 22.5308 8.96071 23.0395 9.33579 23.4146C9.71086 23.7896 10.2196 24.0004 10.75 24.0004H13.25C13.7804 24.0004 14.2891 23.7896 14.6642 23.4146C15.0393 23.0395 15.25 22.5308 15.25 22.0004V19.5004C15.25 18.9699 15.0393 18.4612 14.6642 18.0862C14.2891 17.7111 13.7804 17.5004 13.25 17.5004ZM13.25 22.0004H10.75V19.5004H13.25V22.0004Z" fill="white"/>
|
||||
<path d="M13.25 8.74976H10.75C10.2196 8.74976 9.71086 8.96047 9.33579 9.33554C8.96071 9.71061 8.75 10.2193 8.75 10.7498V13.2497C8.75 13.7802 8.96071 14.2889 9.33579 14.664C9.71086 15.039 10.2196 15.2497 10.75 15.2497H13.25C13.7804 15.2497 14.2891 15.039 14.6642 14.664C15.0393 14.2889 15.25 13.7802 15.25 13.2497V10.7498C15.25 10.2193 15.0393 9.71061 14.6642 9.33554C14.2891 8.96047 13.7804 8.74976 13.25 8.74976ZM13.25 13.2497H10.75V10.7498H13.25V13.2497Z" fill="white"/>
|
||||
<path d="M13.25 0H10.75C10.2196 0 9.71086 0.210714 9.33579 0.585786C8.96071 0.960859 8.75 1.46957 8.75 2V4.5C8.75 5.03043 8.96071 5.53914 9.33579 5.91421C9.71086 6.28929 10.2196 6.5 10.75 6.5H13.25C13.7804 6.5 14.2891 6.28929 14.6642 5.91421C15.0393 5.53914 15.25 5.03043 15.25 4.5V2C15.25 1.46957 15.0393 0.960859 14.6642 0.585786C14.2891 0.210714 13.7804 0 13.25 0V0ZM13.25 4.5H10.75V2H13.25V4.5Z" fill="white"/>
|
||||
<path d="M22 0H19.5C18.9696 0 18.4609 0.210714 18.0858 0.585786C17.7107 0.960859 17.5 1.46957 17.5 2V4.5C17.5 5.03043 17.7107 5.53914 18.0858 5.91421C18.4609 6.28929 18.9696 6.5 19.5 6.5H22C22.5304 6.5 23.0391 6.28929 23.4142 5.91421C23.7893 5.53914 24 5.03043 24 4.5V2C24 1.46957 23.7893 0.960859 23.4142 0.585786C23.0391 0.210714 22.5304 0 22 0V0ZM22 4.5H19.5V2H22V4.5Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1423_2976">
|
||||
<rect width="24" height="24" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 4.1 KiB |
@ -1,3 +1,4 @@
|
||||
description: This file stores settings for Dart & Flutter DevTools.
|
||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||
extensions:
|
||||
- provider: true
|
||||
|
@ -2,28 +2,34 @@ import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||
import 'package:syncrow_web/pages/auth/view/login_page.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||
import 'package:syncrow_web/pages/home/view/home_page.dart';
|
||||
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:syncrow_web/services/locator.dart';
|
||||
import 'package:syncrow_web/utils/app_routes.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
initialSetup(); // Perform initial setup, e.g., dependency injection
|
||||
initialSetup();
|
||||
String checkToken = await AuthBloc.getTokenAndValidate();
|
||||
GoRouter router = GoRouter(
|
||||
initialLocation: checkToken == 'Success' ? RoutesConst.home : RoutesConst.auth,
|
||||
routes: AppRoutes.getRoutes(),
|
||||
);
|
||||
runApp(MyApp(
|
||||
isLoggedIn: checkToken,
|
||||
router: router,
|
||||
));
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
final dynamic isLoggedIn;
|
||||
final GoRouter router;
|
||||
const MyApp({
|
||||
super.key,
|
||||
required this.isLoggedIn,
|
||||
required this.router,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MultiBlocProvider(
|
||||
@ -33,7 +39,7 @@ class MyApp extends StatelessWidget {
|
||||
create: (context) => VisitorPasswordBloc(),
|
||||
)
|
||||
],
|
||||
child: MaterialApp(
|
||||
child: MaterialApp.router(
|
||||
debugShowCheckedModeBanner: false, // Hide debug banner
|
||||
scrollBehavior: const MaterialScrollBehavior().copyWith(
|
||||
dragDevices: {
|
||||
@ -48,9 +54,7 @@ class MyApp extends StatelessWidget {
|
||||
fontFamily: 'Aftika',
|
||||
textTheme: const TextTheme(
|
||||
bodySmall: TextStyle(
|
||||
fontSize: 13,
|
||||
color: ColorsManager.whiteColors,
|
||||
fontWeight: FontWeight.bold),
|
||||
fontSize: 13, color: ColorsManager.whiteColors, fontWeight: FontWeight.bold),
|
||||
bodyMedium: TextStyle(color: Colors.black87, fontSize: 14),
|
||||
bodyLarge: TextStyle(fontSize: 16, color: Colors.white),
|
||||
headlineSmall: TextStyle(color: Colors.black87, fontSize: 18),
|
||||
@ -61,47 +65,10 @@ class MyApp extends StatelessWidget {
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: ColorsManager.blueColor,
|
||||
primary: ColorsManager.blueColor, // Checked state color
|
||||
onSurface: Colors.grey.shade400, // Unchecked state color
|
||||
),
|
||||
switchTheme: SwitchThemeData(
|
||||
thumbColor: MaterialStateProperty.resolveWith((states) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return ColorsManager
|
||||
.blueColor; // Color of the switch knob when selected
|
||||
}
|
||||
return ColorsManager
|
||||
.whiteColors; // Color of the switch knob when not selected
|
||||
}),
|
||||
trackColor: MaterialStateProperty.resolveWith((states) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return ColorsManager.blueColor
|
||||
.withOpacity(0.5); // Track color when selected
|
||||
}
|
||||
return ColorsManager
|
||||
.whiteColors; // Track color when not selected
|
||||
}),
|
||||
),
|
||||
checkboxTheme: CheckboxThemeData(
|
||||
fillColor: MaterialStateProperty.resolveWith((states) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return ColorsManager.blueColor; // Checked state color
|
||||
}
|
||||
return Colors.grey.shade200; // Unchecked state color
|
||||
}),
|
||||
checkColor: MaterialStateProperty.all(
|
||||
Colors.white), // The color of the checkmark
|
||||
side:
|
||||
BorderSide(color: ColorsManager.whiteColors), // Border color
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(4), // Border radius
|
||||
),
|
||||
),
|
||||
useMaterial3: true, // Enable Material 3
|
||||
),
|
||||
home: isLoggedIn == 'Success' ? const HomePage() : const LoginPage(),
|
||||
routeInformationProvider: router.routeInformationProvider,
|
||||
routerDelegate: router.routerDelegate,
|
||||
routeInformationParser: router.routeInformationParser,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
);
|
||||
})));
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.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/bloc/auth_event.dart';
|
||||
import 'package:syncrow_web/pages/auth/bloc/auth_state.dart';
|
||||
@ -13,7 +12,7 @@ import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/pages/common/first_layer.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/pages/home/view/home_page.dart';
|
||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class LoginWebPage extends StatefulWidget {
|
||||
@ -32,13 +31,8 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
child: BlocConsumer<AuthBloc, AuthState>(
|
||||
listener: (context, state) {
|
||||
if (state is LoginSuccess) {
|
||||
// Navigate to home screen after successful login
|
||||
Navigator.pushReplacement(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => HomePage()),
|
||||
);
|
||||
context.go(RoutesConst.home);
|
||||
} else if (state is LoginFailure) {
|
||||
// Show error message
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(state.error),
|
||||
@ -60,8 +54,7 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
late ScrollController _scrollController;
|
||||
_scrollController = ScrollController();
|
||||
void _scrollToCenter() {
|
||||
final double middlePosition =
|
||||
_scrollController.position.maxScrollExtent / 2;
|
||||
final double middlePosition = _scrollController.position.maxScrollExtent / 2;
|
||||
_scrollController.animateTo(
|
||||
middlePosition,
|
||||
duration: const Duration(seconds: 1),
|
||||
@ -105,11 +98,9 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.1),
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(30)),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(30)),
|
||||
border: Border.all(
|
||||
color: ColorsManager.graysColor
|
||||
.withOpacity(0.2))),
|
||||
color: ColorsManager.graysColor.withOpacity(0.2))),
|
||||
child: Form(
|
||||
key: loginBloc.loginFormKey,
|
||||
child: Padding(
|
||||
@ -117,22 +108,16 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
horizontal: size.width * 0.02,
|
||||
vertical: size.width * 0.003),
|
||||
child: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
const SizedBox(height: 40),
|
||||
Text('Login',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineLarge),
|
||||
style: Theme.of(context).textTheme.headlineLarge),
|
||||
SizedBox(height: size.height * 0.03),
|
||||
Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Country/Region",
|
||||
@ -140,81 +125,57 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
fontSize: 14,
|
||||
fontWeight:
|
||||
FontWeight.w400),
|
||||
fontSize: 14, fontWeight: FontWeight.w400),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
SizedBox(
|
||||
child: DropdownButtonFormField<
|
||||
String>(
|
||||
child: DropdownButtonFormField<String>(
|
||||
padding: EdgeInsets.zero,
|
||||
value: loginBloc.regionList!
|
||||
.any((region) =>
|
||||
region.id ==
|
||||
loginBloc
|
||||
.regionUuid)
|
||||
value: loginBloc.regionList!.any((region) =>
|
||||
region.id == loginBloc.regionUuid)
|
||||
? loginBloc.regionUuid
|
||||
: null,
|
||||
validator:
|
||||
loginBloc.validateRegion,
|
||||
validator: loginBloc.validateRegion,
|
||||
icon: const Icon(
|
||||
Icons
|
||||
.keyboard_arrow_down_outlined,
|
||||
Icons.keyboard_arrow_down_outlined,
|
||||
),
|
||||
decoration: textBoxDecoration()!
|
||||
.copyWith(
|
||||
errorStyle: const TextStyle(
|
||||
height: 0),
|
||||
decoration: textBoxDecoration()!.copyWith(
|
||||
errorStyle: const TextStyle(height: 0),
|
||||
hintText: null,
|
||||
),
|
||||
hint: SizedBox(
|
||||
width: size.width * 0.12,
|
||||
child: Align(
|
||||
alignment:
|
||||
Alignment.centerLeft,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
'Select your region/country',
|
||||
textAlign:
|
||||
TextAlign.center,
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
color:
|
||||
ColorsManager
|
||||
.grayColor,
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w400),
|
||||
overflow:
|
||||
TextOverflow.ellipsis,
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.w400),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
isDense: true,
|
||||
style: const TextStyle(
|
||||
color: Colors.black),
|
||||
items: loginBloc.regionList!
|
||||
.map((RegionModel region) {
|
||||
return DropdownMenuItem<
|
||||
String>(
|
||||
style: const TextStyle(color: Colors.black),
|
||||
items:
|
||||
loginBloc.regionList!.map((RegionModel region) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: region.id,
|
||||
child: SizedBox(
|
||||
width:
|
||||
size.width * 0.08,
|
||||
child:
|
||||
Text(region.name)),
|
||||
width: size.width * 0.08,
|
||||
child: Text(region.name)),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (String? value) {
|
||||
loginBloc
|
||||
.add(CheckEnableEvent());
|
||||
loginBloc.add(
|
||||
SelectRegionEvent(
|
||||
val: value!));
|
||||
loginBloc.add(CheckEnableEvent());
|
||||
loginBloc.add(SelectRegionEvent(val: value!));
|
||||
},
|
||||
),
|
||||
)
|
||||
@ -222,10 +183,8 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
),
|
||||
const SizedBox(height: 20.0),
|
||||
Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Email",
|
||||
@ -233,9 +192,7 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
fontSize: 14,
|
||||
fontWeight:
|
||||
FontWeight.w400),
|
||||
fontSize: 14, fontWeight: FontWeight.w400),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
@ -243,43 +200,30 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
SizedBox(
|
||||
child: TextFormField(
|
||||
onChanged: (value) {
|
||||
loginBloc
|
||||
.add(CheckEnableEvent());
|
||||
loginBloc.add(CheckEnableEvent());
|
||||
// print(loginBloc.checkEnable());
|
||||
},
|
||||
validator: loginBloc
|
||||
.loginValidateEmail,
|
||||
controller: loginBloc
|
||||
.loginEmailController,
|
||||
decoration: textBoxDecoration()!
|
||||
.copyWith(
|
||||
errorStyle: const TextStyle(
|
||||
height:
|
||||
0), // Hide the error text space
|
||||
hintText:
|
||||
'Enter your email address',
|
||||
hintStyle: Theme.of(
|
||||
context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
color: ColorsManager
|
||||
.grayColor,
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w400)),
|
||||
style: const TextStyle(
|
||||
color: Colors.black),
|
||||
validator: loginBloc.loginValidateEmail,
|
||||
controller: loginBloc.loginEmailController,
|
||||
decoration: textBoxDecoration()!.copyWith(
|
||||
errorStyle: const TextStyle(
|
||||
height: 0), // Hide the error text space
|
||||
hintText: 'Enter your email address',
|
||||
hintStyle: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.w400)),
|
||||
style: const TextStyle(color: Colors.black),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20.0),
|
||||
Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Password",
|
||||
@ -287,9 +231,7 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
fontSize: 14,
|
||||
fontWeight:
|
||||
FontWeight.w400),
|
||||
fontSize: 14, fontWeight: FontWeight.w400),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
@ -297,54 +239,39 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
SizedBox(
|
||||
child: TextFormField(
|
||||
onChanged: (value) {
|
||||
loginBloc
|
||||
.add(CheckEnableEvent());
|
||||
loginBloc.add(CheckEnableEvent());
|
||||
},
|
||||
validator:
|
||||
loginBloc.validatePassword,
|
||||
obscureText:
|
||||
loginBloc.obscureText,
|
||||
keyboardType: TextInputType
|
||||
.visiblePassword,
|
||||
controller: loginBloc
|
||||
.loginPasswordController,
|
||||
decoration: textBoxDecoration()!
|
||||
.copyWith(
|
||||
hintText:
|
||||
'At least 8 characters',
|
||||
validator: loginBloc.validatePassword,
|
||||
obscureText: loginBloc.obscureText,
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
controller: loginBloc.loginPasswordController,
|
||||
decoration: textBoxDecoration()!.copyWith(
|
||||
hintText: 'At least 8 characters',
|
||||
hintStyle: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
color: ColorsManager
|
||||
.grayColor,
|
||||
fontWeight:
|
||||
FontWeight.w400),
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.w400),
|
||||
suffixIcon: IconButton(
|
||||
onPressed: () {
|
||||
loginBloc.add(
|
||||
PasswordVisibleEvent(
|
||||
newValue: loginBloc
|
||||
.obscureText));
|
||||
loginBloc.add(PasswordVisibleEvent(
|
||||
newValue: loginBloc.obscureText));
|
||||
},
|
||||
icon: SizedBox(
|
||||
child: SvgPicture.asset(
|
||||
loginBloc.obscureText
|
||||
? Assets
|
||||
.visiblePassword
|
||||
: Assets
|
||||
.invisiblePassword,
|
||||
? Assets.visiblePassword
|
||||
: Assets.invisiblePassword,
|
||||
height: 15,
|
||||
width: 15,
|
||||
),
|
||||
),
|
||||
),
|
||||
errorStyle: const TextStyle(
|
||||
height:
|
||||
0), // Hide the error text space
|
||||
height: 0), // Hide the error text space
|
||||
),
|
||||
style: const TextStyle(
|
||||
color: Colors.black),
|
||||
style: const TextStyle(color: Colors.black),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -354,13 +281,11 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
),
|
||||
SizedBox(
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context)
|
||||
.push(MaterialPageRoute(
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
const ForgetPasswordPage(),
|
||||
));
|
||||
@ -373,8 +298,7 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
.copyWith(
|
||||
color: Colors.black,
|
||||
fontSize: 14,
|
||||
fontWeight:
|
||||
FontWeight.w400),
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -386,18 +310,16 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
Row(
|
||||
children: [
|
||||
Transform.scale(
|
||||
scale:
|
||||
1.2, // Adjust the scale as needed
|
||||
scale: 1.2, // Adjust the scale as needed
|
||||
child: Checkbox(
|
||||
fillColor: MaterialStateProperty
|
||||
.all<Color>(Colors.white),
|
||||
fillColor:
|
||||
MaterialStateProperty.all<Color>(Colors.white),
|
||||
activeColor: Colors.white,
|
||||
value: loginBloc.isChecked,
|
||||
checkColor: Colors.black,
|
||||
shape: const CircleBorder(),
|
||||
onChanged: (bool? newValue) {
|
||||
loginBloc.add(CheckBoxEvent(
|
||||
newValue: newValue));
|
||||
loginBloc.add(CheckBoxEvent(newValue: newValue));
|
||||
},
|
||||
),
|
||||
),
|
||||
@ -406,45 +328,36 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
text: 'Agree to ',
|
||||
style: const TextStyle(
|
||||
color: Colors.white),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
children: [
|
||||
TextSpan(
|
||||
text:
|
||||
'(Terms of Service)',
|
||||
text: '(Terms of Service)',
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
),
|
||||
recognizer:
|
||||
TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
loginBloc.launchURL(
|
||||
'https://example.com/terms');
|
||||
},
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
loginBloc.launchURL(
|
||||
'https://example.com/terms');
|
||||
},
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
' (Legal Statement)',
|
||||
style: const TextStyle(
|
||||
color: Colors.black),
|
||||
recognizer:
|
||||
TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
loginBloc.launchURL(
|
||||
'https://example.com/legal');
|
||||
},
|
||||
text: ' (Legal Statement)',
|
||||
style: const TextStyle(color: Colors.black),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
loginBloc.launchURL(
|
||||
'https://example.com/legal');
|
||||
},
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
' (Privacy Statement)',
|
||||
style: const TextStyle(
|
||||
color: Colors.black),
|
||||
recognizer:
|
||||
TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
loginBloc.launchURL(
|
||||
'https://example.com/privacy');
|
||||
},
|
||||
text: ' (Privacy Statement)',
|
||||
style: const TextStyle(color: Colors.black),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
loginBloc.launchURL(
|
||||
'https://example.com/privacy');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -454,49 +367,35 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
),
|
||||
const SizedBox(height: 20.0),
|
||||
Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: size.width * 0.2,
|
||||
child: DefaultButton(
|
||||
enabled:
|
||||
loginBloc.checkValidate,
|
||||
enabled: loginBloc.checkValidate,
|
||||
child: Text('Sign in',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.labelLarge!
|
||||
.copyWith(
|
||||
fontSize: 14,
|
||||
color: loginBloc
|
||||
.checkValidate
|
||||
? ColorsManager
|
||||
.whiteColors
|
||||
: ColorsManager
|
||||
.whiteColors
|
||||
.withOpacity(
|
||||
0.2),
|
||||
color: loginBloc.checkValidate
|
||||
? ColorsManager.whiteColors
|
||||
: ColorsManager.whiteColors
|
||||
.withOpacity(0.2),
|
||||
)),
|
||||
onPressed: () {
|
||||
if (loginBloc.loginFormKey
|
||||
.currentState!
|
||||
if (loginBloc.loginFormKey.currentState!
|
||||
.validate()) {
|
||||
loginBloc
|
||||
.add(LoginButtonPressed(
|
||||
regionUuid:
|
||||
loginBloc.regionUuid,
|
||||
username: loginBloc
|
||||
.loginEmailController
|
||||
.text,
|
||||
password: loginBloc
|
||||
.loginPasswordController
|
||||
.text,
|
||||
loginBloc.add(LoginButtonPressed(
|
||||
regionUuid: loginBloc.regionUuid,
|
||||
username: loginBloc.loginEmailController.text,
|
||||
password:
|
||||
loginBloc.loginPasswordController.text,
|
||||
));
|
||||
} else {
|
||||
loginBloc.add(
|
||||
ChangeValidateEvent());
|
||||
loginBloc.add(ChangeValidateEvent());
|
||||
}
|
||||
},
|
||||
),
|
||||
@ -505,10 +404,8 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
child: Text(
|
||||
@ -533,8 +430,7 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (state is AuthLoading)
|
||||
const Center(child: CircularProgressIndicator())
|
||||
if (state is AuthLoading) const Center(child: CircularProgressIndicator())
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ Future<void> showCustomDialog({
|
||||
required String message,
|
||||
String? title,
|
||||
String? iconPath,
|
||||
Widget? widget,
|
||||
double? dialogHeight,
|
||||
double? iconHeight,
|
||||
double? iconWidth,
|
||||
@ -54,6 +55,8 @@ Future<void> showCustomDialog({
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
if(widget!=null)
|
||||
Expanded(child:widget)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -14,7 +14,6 @@ class DynamicTable extends StatefulWidget {
|
||||
final void Function(bool?)? selectAll;
|
||||
final void Function(int, bool, dynamic)? onRowSelected;
|
||||
final List<String>? initialSelectedIds;
|
||||
|
||||
const DynamicTable({
|
||||
super.key,
|
||||
required this.headers,
|
||||
@ -66,14 +65,11 @@ class _DynamicTableState extends State<DynamicTable> {
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: widget.headerDecoration ??
|
||||
BoxDecoration(color: Colors.grey[200]),
|
||||
decoration: widget.headerDecoration ?? BoxDecoration(color: Colors.grey[200]),
|
||||
child: Row(
|
||||
children: [
|
||||
if (widget.withCheckBox) _buildSelectAllCheckbox(),
|
||||
...widget.headers
|
||||
.map((header) => _buildTableHeaderCell(header))
|
||||
.toList(),
|
||||
...widget.headers.map((header) => _buildTableHeaderCell(header)).toList(),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -97,8 +93,7 @@ class _DynamicTableState extends State<DynamicTable> {
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
color: ColorsManager.grayColor),
|
||||
.copyWith(color: ColorsManager.grayColor),
|
||||
)
|
||||
],
|
||||
),
|
||||
@ -118,12 +113,10 @@ class _DynamicTableState extends State<DynamicTable> {
|
||||
return Row(
|
||||
children: [
|
||||
if (widget.withCheckBox)
|
||||
_buildRowCheckbox(
|
||||
index, widget.size.height * 0.10),
|
||||
_buildRowCheckbox(index, widget.size.height * 0.10),
|
||||
...row
|
||||
.map((cell) => _buildTableCell(
|
||||
cell.toString(),
|
||||
widget.size.height * 0.10))
|
||||
.map((cell) =>
|
||||
_buildTableCell(cell.toString(), widget.size.height * 0.10))
|
||||
.toList(),
|
||||
],
|
||||
);
|
||||
@ -211,6 +204,27 @@ class _DynamicTableState extends State<DynamicTable> {
|
||||
batteryLevel = double.tryParse(content.replaceAll('%', '').trim());
|
||||
}
|
||||
|
||||
Color? statusColor;
|
||||
switch (content) {
|
||||
case 'Effective':
|
||||
statusColor = ColorsManager.textGreen;
|
||||
break;
|
||||
case 'Expired':
|
||||
statusColor = ColorsManager.red;
|
||||
break;
|
||||
case 'To be effective':
|
||||
statusColor = ColorsManager.yaGreen;
|
||||
break;
|
||||
case 'Online':
|
||||
statusColor = ColorsManager.green;
|
||||
break;
|
||||
case 'Offline':
|
||||
statusColor = ColorsManager.red;
|
||||
break;
|
||||
default:
|
||||
statusColor = Colors.black; // Default color
|
||||
}
|
||||
|
||||
return Expanded(
|
||||
child: Container(
|
||||
height: size,
|
||||
@ -227,16 +241,11 @@ class _DynamicTableState extends State<DynamicTable> {
|
||||
child: Text(
|
||||
content,
|
||||
style: TextStyle(
|
||||
color: batteryLevel != null && batteryLevel < 20
|
||||
? ColorsManager.red // Red color for low battery
|
||||
: content == 'Online'
|
||||
? ColorsManager.green // Green color for Online
|
||||
: content == 'Offline'
|
||||
? ColorsManager.red // Red color for Offline
|
||||
: Colors.black,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
color: batteryLevel != null && batteryLevel < 20
|
||||
? ColorsManager.red
|
||||
: statusColor, // Use the passed color or default to black
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -36,10 +36,7 @@ class DateTimeWebWidget extends StatelessWidget {
|
||||
if (isRequired)
|
||||
Text(
|
||||
'* ',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(color: Colors.red),
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: Colors.red),
|
||||
),
|
||||
Text(
|
||||
title,
|
||||
@ -55,8 +52,7 @@ class DateTimeWebWidget extends StatelessWidget {
|
||||
),
|
||||
Container(
|
||||
height: size.height * 0.055,
|
||||
padding:
|
||||
const EdgeInsets.only(top: 10, bottom: 10, right: 30, left: 10),
|
||||
padding: const EdgeInsets.only(top: 10, bottom: 10, right: 30, left: 10),
|
||||
decoration: containerDecoration,
|
||||
child: FittedBox(
|
||||
child: Column(
|
||||
@ -69,13 +65,10 @@ class DateTimeWebWidget extends StatelessWidget {
|
||||
child: FittedBox(
|
||||
child: Text(
|
||||
firstString,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400),
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
)),
|
||||
const SizedBox(
|
||||
@ -90,13 +83,10 @@ class DateTimeWebWidget extends StatelessWidget {
|
||||
child: FittedBox(
|
||||
child: Text(
|
||||
secondString,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400),
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
)),
|
||||
const SizedBox(
|
||||
|
@ -1,17 +1,15 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:graphview/GraphView.dart';
|
||||
import 'package:syncrow_web/pages/access_management/view/access_management.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/view/device_managment_page.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||
import 'package:syncrow_web/pages/home/home_model/home_item_model.dart';
|
||||
import 'package:syncrow_web/services/home_api.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';
|
||||
|
||||
class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
final Graph graph = Graph()..isTree = true;
|
||||
@ -43,8 +41,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
|
||||
Future fetchUserInfo() async {
|
||||
try {
|
||||
var uuid =
|
||||
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
user = await HomeApi().fetchUserInfo(uuid);
|
||||
emit(HomeUserInfoLoaded(user!)); // Emit state after fetching user info
|
||||
} catch (e) {
|
||||
@ -58,9 +55,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
icon: Assets.accessIcon,
|
||||
active: true,
|
||||
onPress: (context) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (context) => AccessManagementPage()),
|
||||
);
|
||||
context.go(RoutesConst.accessManagementPage);
|
||||
},
|
||||
color: null,
|
||||
),
|
||||
@ -76,9 +71,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
icon: Assets.devicesIcon,
|
||||
active: true,
|
||||
onPress: (context) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (context) => const DeviceManagementPage()),
|
||||
);
|
||||
context.go(RoutesConst.deviceManagementPage);
|
||||
},
|
||||
color: ColorsManager.primaryColor,
|
||||
),
|
||||
|
@ -24,13 +24,19 @@ class HomeCard extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(left: 10, right: 10, bottom: 10),
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
// evenNumbers && active
|
||||
// ? ColorsManager.blueColor.withOpacity(0.8)
|
||||
// :
|
||||
(active
|
||||
? ColorsManager.blueColor
|
||||
: ColorsManager.blueColor.withOpacity(0.2)),
|
||||
color: index == 0 && active
|
||||
? ColorsManager.blue1.withOpacity(0.9)
|
||||
: index == 1 && active
|
||||
? ColorsManager.blue2.withOpacity(0.9)
|
||||
: index == 2 && active
|
||||
? ColorsManager.blue3
|
||||
: index == 4 && active == false
|
||||
? ColorsManager.blue4.withOpacity(0.2)
|
||||
: index == 7 && active == false
|
||||
? ColorsManager.blue4.withOpacity(0.2)
|
||||
: ColorsManager.blueColor.withOpacity(0.2),
|
||||
// (active ?ColorsManager.blueColor
|
||||
// : ColorsManager.blueColor.withOpacity(0.2)),
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
child: Column(
|
||||
|
@ -8,7 +8,6 @@ class HomePage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ResponsiveLayout(
|
||||
desktopBody: HomeWebPage(), mobileBody: HomeMobilePage());
|
||||
return ResponsiveLayout(desktopBody: HomeWebPage(), mobileBody: HomeMobilePage());
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,11 @@ class HomeWebPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Size size = MediaQuery.of(context).size;
|
||||
return WebScaffold(
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvoked: (didPop) => false,
|
||||
child:
|
||||
WebScaffold(
|
||||
enableMenuSideba: false,
|
||||
appBarTitle: Row(
|
||||
children: [
|
||||
@ -76,6 +80,6 @@ class HomeWebPage extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
));
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
16
lib/pages/space_management/spaseManagementIcon.dart
Normal file
16
lib/pages/space_management/spaseManagementIcon.dart
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SpaseManagementicon extends StatelessWidget {
|
||||
const SpaseManagementicon({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Container(),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import 'dart:math';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
@ -7,14 +8,14 @@ import 'package:syncrow_web/pages/common/hour_picker_dialog.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';
|
||||
import 'package:syncrow_web/pages/visitor_password/model/device_model.dart';
|
||||
import 'package:syncrow_web/pages/visitor_password/model/failed_operation.dart';
|
||||
import 'package:syncrow_web/pages/visitor_password/model/schedule_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/assets.dart';
|
||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||
|
||||
class VisitorPasswordBloc
|
||||
extends Bloc<VisitorPasswordEvent, VisitorPasswordState> {
|
||||
class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordState> {
|
||||
VisitorPasswordBloc() : super(VisitorPasswordInitial()) {
|
||||
on<SelectUsageFrequency>(selectUsageFrequency);
|
||||
on<FetchDevice>(_onFetchDevice);
|
||||
@ -37,8 +38,7 @@ class VisitorPasswordBloc
|
||||
final TextEditingController deviceNameController = TextEditingController();
|
||||
final TextEditingController deviceIdController = TextEditingController();
|
||||
final TextEditingController unitNameController = TextEditingController();
|
||||
final TextEditingController virtualAddressController =
|
||||
TextEditingController();
|
||||
final TextEditingController virtualAddressController = TextEditingController();
|
||||
List<String> selectedDevices = [];
|
||||
|
||||
List<DeviceModel> data = [];
|
||||
@ -62,15 +62,13 @@ class VisitorPasswordBloc
|
||||
|
||||
String startTimeAccess = 'Start Time';
|
||||
String endTimeAccess = 'End Time';
|
||||
|
||||
selectAccessType(
|
||||
SelectPasswordType event, Emitter<VisitorPasswordState> emit) {
|
||||
PasswordStatus? passwordStatus;
|
||||
selectAccessType(SelectPasswordType event, Emitter<VisitorPasswordState> emit) {
|
||||
accessTypeSelected = event.type;
|
||||
emit(PasswordTypeSelected(event.type));
|
||||
}
|
||||
|
||||
selectUsageFrequency(
|
||||
SelectUsageFrequency event, Emitter<VisitorPasswordState> emit) {
|
||||
selectUsageFrequency(SelectUsageFrequency event, Emitter<VisitorPasswordState> emit) {
|
||||
usageFrequencySelected = event.usageType;
|
||||
emit(UsageFrequencySelected(event.usageType));
|
||||
}
|
||||
@ -117,12 +115,10 @@ class VisitorPasswordBloc
|
||||
timePicked.minute,
|
||||
);
|
||||
|
||||
final selectedTimestamp =
|
||||
selectedDateTime.millisecondsSinceEpoch ~/ 1000;
|
||||
final selectedTimestamp = selectedDateTime.millisecondsSinceEpoch ~/ 1000;
|
||||
|
||||
if (event.isStart) {
|
||||
if (expirationTimeTimeStamp != null &&
|
||||
selectedTimestamp > expirationTimeTimeStamp!) {
|
||||
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
|
||||
CustomSnackBar.displaySnackBar(
|
||||
'Effective Time cannot be later than Expiration Time.',
|
||||
);
|
||||
@ -131,8 +127,7 @@ class VisitorPasswordBloc
|
||||
effectiveTimeTimeStamp = selectedTimestamp;
|
||||
startTimeAccess = selectedDateTime.toString().split('.').first;
|
||||
} else {
|
||||
if (effectiveTimeTimeStamp != null &&
|
||||
selectedTimestamp < effectiveTimeTimeStamp!) {
|
||||
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
|
||||
CustomSnackBar.displaySnackBar(
|
||||
'Expiration Time cannot be earlier than Effective Time.',
|
||||
);
|
||||
@ -147,8 +142,7 @@ class VisitorPasswordBloc
|
||||
}
|
||||
}
|
||||
|
||||
bool toggleRepeat(
|
||||
ToggleRepeatEvent event, Emitter<VisitorPasswordState> emit) {
|
||||
bool toggleRepeat(ToggleRepeatEvent event, Emitter<VisitorPasswordState> emit) {
|
||||
emit(LoadingInitialState());
|
||||
repeat = !repeat;
|
||||
emit(IsRepeatState(repeat: repeat));
|
||||
@ -180,8 +174,7 @@ class VisitorPasswordBloc
|
||||
emit(ChangeTimeState());
|
||||
}
|
||||
|
||||
Future<void> _onFetchDevice(
|
||||
FetchDevice event, Emitter<VisitorPasswordState> emit) async {
|
||||
Future<void> _onFetchDevice(FetchDevice event, Emitter<VisitorPasswordState> emit) async {
|
||||
try {
|
||||
emit(DeviceLoaded());
|
||||
data = await AccessMangApi().fetchDevices();
|
||||
@ -192,48 +185,43 @@ class VisitorPasswordBloc
|
||||
}
|
||||
|
||||
//online password
|
||||
Future<void> postOnlineOneTimePassword(OnlineOneTimePasswordEvent event,
|
||||
Emitter<VisitorPasswordState> emit) async {
|
||||
Future<void> postOnlineOneTimePassword(
|
||||
OnlineOneTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
|
||||
try {
|
||||
emit(LoadingInitialState());
|
||||
generate7DigitNumber();
|
||||
bool res = await AccessMangApi().postOnlineOneTime(
|
||||
var res = await AccessMangApi().postOnlineOneTime(
|
||||
email: event.email,
|
||||
password: passwordController,
|
||||
devicesUuid: selectedDevices,
|
||||
passwordName: event.passwordName,
|
||||
effectiveTime: effectiveTimeTimeStamp.toString(),
|
||||
invalidTime: expirationTimeTimeStamp.toString());
|
||||
if (res == true) {
|
||||
if (res['statusCode'] == 201) {
|
||||
passwordStatus = PasswordStatus.fromJson(res['data']);
|
||||
emit(SuccessState());
|
||||
} else {
|
||||
throw Exception('Failed to create password');
|
||||
}
|
||||
emit(TableLoaded(data));
|
||||
} catch (e) {
|
||||
emit(FailedState(e.toString()));
|
||||
Navigator.pop(event.context!);
|
||||
stateDialog(
|
||||
context: event.context!,
|
||||
message: e.toString(),
|
||||
title: 'Something Wrong');
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
String errorMessage = errorData['message'];
|
||||
print('errorMessage==$errorData');
|
||||
emit(FailedState(errorMessage.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> postOnlineMultipleTimePassword(
|
||||
OnlineMultipleTimePasswordEvent event,
|
||||
Emitter<VisitorPasswordState> emit) async {
|
||||
OnlineMultipleTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
|
||||
try {
|
||||
emit(LoadingInitialState());
|
||||
|
||||
await generate7DigitNumber();
|
||||
bool res = await AccessMangApi().postOnlineMultipleTime(
|
||||
var res = await AccessMangApi().postOnlineMultipleTime(
|
||||
scheduleList: [
|
||||
if (repeat)
|
||||
Schedule(
|
||||
effectiveTime: getTimeFromDateTimeString(expirationTime),
|
||||
invalidTime:
|
||||
getTimeFromDateTimeString(effectiveTime).toString(),
|
||||
invalidTime: getTimeFromDateTimeString(effectiveTime).toString(),
|
||||
workingDay: selectedDays,
|
||||
),
|
||||
],
|
||||
@ -243,79 +231,66 @@ class VisitorPasswordBloc
|
||||
email: event.email,
|
||||
devicesUuid: selectedDevices,
|
||||
passwordName: event.passwordName);
|
||||
if (res == true) {
|
||||
if (res['statusCode'] == 201) {
|
||||
passwordStatus = PasswordStatus.fromJson(res['data']);
|
||||
emit(SuccessState());
|
||||
} else {
|
||||
throw Exception('Failed to create password');
|
||||
}
|
||||
emit(TableLoaded(data));
|
||||
} catch (e) {
|
||||
emit(FailedState(e.toString()));
|
||||
Navigator.pop(event.context!);
|
||||
stateDialog(
|
||||
context: event.context!,
|
||||
message: e.toString(),
|
||||
title: 'Something Wrong');
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
String errorMessage = errorData['message'];
|
||||
print('errorMessage==$errorData');
|
||||
emit(FailedState(errorMessage.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
//offline password
|
||||
Future<void> postOfflineOneTimePassword(OfflineOneTimePasswordEvent event,
|
||||
Emitter<VisitorPasswordState> emit) async {
|
||||
Future<void> postOfflineOneTimePassword(
|
||||
OfflineOneTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
|
||||
try {
|
||||
emit(LoadingInitialState());
|
||||
await generate7DigitNumber();
|
||||
bool res = await AccessMangApi().postOffLineOneTime(
|
||||
email: event.email,
|
||||
devicesUuid: selectedDevices,
|
||||
passwordName: event.passwordName);
|
||||
if (res == true) {
|
||||
var res = await AccessMangApi().postOffLineOneTime(
|
||||
email: event.email, devicesUuid: selectedDevices, passwordName: event.passwordName);
|
||||
if (res['statusCode'] == 201) {
|
||||
passwordStatus = PasswordStatus.fromJson(res['data']);
|
||||
emit(SuccessState());
|
||||
} else {
|
||||
throw Exception('Failed to create password');
|
||||
}
|
||||
emit(TableLoaded(data));
|
||||
} catch (e) {
|
||||
emit(FailedState(e.toString()));
|
||||
Navigator.pop(event.context!);
|
||||
stateDialog(
|
||||
context: event.context!,
|
||||
message: e.toString(),
|
||||
title: 'Something Wrong');
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
String errorMessage = errorData['message'];
|
||||
print('errorMessage==$errorData');
|
||||
emit(FailedState(errorMessage.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> postOfflineMultipleTimePassword(
|
||||
OfflineMultipleTimePasswordEvent event,
|
||||
Emitter<VisitorPasswordState> emit) async {
|
||||
OfflineMultipleTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
|
||||
try {
|
||||
emit(LoadingInitialState());
|
||||
await generate7DigitNumber();
|
||||
bool res = await AccessMangApi().postOffLineMultipleTime(
|
||||
var res = await AccessMangApi().postOffLineMultipleTime(
|
||||
email: event.email,
|
||||
devicesUuid: selectedDevices,
|
||||
passwordName: event.passwordName,
|
||||
invalidTime: expirationTimeTimeStamp.toString(),
|
||||
effectiveTime: effectiveTimeTimeStamp.toString(),
|
||||
);
|
||||
if (res == true) {
|
||||
if (res['statusCode'] == 201) {
|
||||
passwordStatus = PasswordStatus.fromJson(res['data']);
|
||||
emit(SuccessState());
|
||||
} else {
|
||||
throw Exception('Failed to create password');
|
||||
}
|
||||
emit(TableLoaded(data));
|
||||
} catch (e) {
|
||||
emit(FailedState(e.toString()));
|
||||
Navigator.pop(event.context!);
|
||||
stateDialog(
|
||||
context: event.context!,
|
||||
message: e.toString(),
|
||||
title: 'Something Wrong');
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
String errorMessage = errorData['message'];
|
||||
print('errorMessage==$errorData');
|
||||
emit(FailedState(errorMessage.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void selectDevice(
|
||||
SelectDeviceEvent event, Emitter<VisitorPasswordState> emit) {
|
||||
void selectDevice(SelectDeviceEvent event, Emitter<VisitorPasswordState> emit) {
|
||||
if (selectedDeviceIds.contains(event.deviceId)) {
|
||||
selectedDeviceIds.remove(event.deviceId);
|
||||
} else {
|
||||
@ -358,8 +333,7 @@ class VisitorPasswordBloc
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<VisitorPasswordState> mapEventToState(
|
||||
VisitorPasswordEvent event) async* {
|
||||
Stream<VisitorPasswordState> mapEventToState(VisitorPasswordEvent event) async* {
|
||||
if (event is FetchDevice) {
|
||||
} else if (event is UpdateFilteredDevicesEvent) {
|
||||
yield TableLoaded(event.filteredData);
|
||||
@ -407,27 +381,20 @@ class VisitorPasswordBloc
|
||||
).millisecondsSinceEpoch ~/
|
||||
1000; // Divide by 1000 to remove milliseconds
|
||||
if (event.isEffective) {
|
||||
if (expirationTimeTimeStamp != null &&
|
||||
selectedTimestamp > expirationTimeTimeStamp!) {
|
||||
CustomSnackBar.displaySnackBar(
|
||||
'Effective Time cannot be later than Expiration Time.');
|
||||
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
|
||||
CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.');
|
||||
} else {
|
||||
effectiveTime = selectedDateTime
|
||||
.toString()
|
||||
.split('.')
|
||||
.first; // Remove seconds and milliseconds
|
||||
effectiveTime =
|
||||
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
|
||||
effectiveTimeTimeStamp = selectedTimestamp;
|
||||
}
|
||||
} else {
|
||||
if (effectiveTimeTimeStamp != null &&
|
||||
selectedTimestamp < effectiveTimeTimeStamp!) {
|
||||
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
|
||||
CustomSnackBar.displaySnackBar(
|
||||
'Expiration Time cannot be earlier than Effective Time.');
|
||||
} else {
|
||||
expirationTime = selectedDateTime
|
||||
.toString()
|
||||
.split('.')
|
||||
.first; // Remove seconds and milliseconds
|
||||
expirationTime =
|
||||
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
|
||||
expirationTimeTimeStamp = selectedTimestamp;
|
||||
}
|
||||
}
|
||||
@ -468,23 +435,26 @@ class VisitorPasswordBloc
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<void> stateDialog({
|
||||
Future stateDialog({
|
||||
BuildContext? context,
|
||||
String? message,
|
||||
String? title,
|
||||
dynamic actions,
|
||||
Widget? widgeta,
|
||||
}) {
|
||||
return showCustomDialog(
|
||||
barrierDismissible: false,
|
||||
context: context!,
|
||||
message: message!,
|
||||
iconPath: Assets.deviceNoteIcon,
|
||||
title: title,
|
||||
dialogHeight: 150,
|
||||
widget: widgeta,
|
||||
dialogHeight: MediaQuery.of(context).size.height * 0.3,
|
||||
actions: actions ??
|
||||
<Widget>[
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
child: const Text('OK'),
|
||||
),
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/constants/const.dart';
|
||||
import 'package:syncrow_web/utils/enum/device_types.dart';
|
||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||
|
||||
class DeviceModel {
|
||||
dynamic productUuid;
|
||||
@ -54,8 +54,7 @@ class DeviceModel {
|
||||
|
||||
if (type == DeviceType.LightBulb) {
|
||||
tempIcon = Assets.lightBulb;
|
||||
} else if (type == DeviceType.CeilingSensor ||
|
||||
type == DeviceType.WallSensor) {
|
||||
} else if (type == DeviceType.CeilingSensor || type == DeviceType.WallSensor) {
|
||||
tempIcon = Assets.sensors;
|
||||
} else if (type == DeviceType.AC) {
|
||||
tempIcon = Assets.ac;
|
||||
|
124
lib/pages/visitor_password/model/failed_operation.dart
Normal file
124
lib/pages/visitor_password/model/failed_operation.dart
Normal file
@ -0,0 +1,124 @@
|
||||
class FailedOperation {
|
||||
final bool success;
|
||||
final dynamic deviceUuid;
|
||||
final dynamic error;
|
||||
|
||||
FailedOperation({
|
||||
required this.success,
|
||||
required this.deviceUuid,
|
||||
required this.error,
|
||||
});
|
||||
|
||||
factory FailedOperation.fromJson(Map<String, dynamic> json) {
|
||||
return FailedOperation(
|
||||
success: json['success'],
|
||||
deviceUuid: json['deviceUuid'],
|
||||
error: json['error'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'success': success,
|
||||
'deviceUuid': deviceUuid,
|
||||
'error': error,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class SuccessOperation {
|
||||
final bool success;
|
||||
// final Result result;
|
||||
final String deviceUuid;
|
||||
|
||||
SuccessOperation({
|
||||
required this.success,
|
||||
// required this.result,
|
||||
required this.deviceUuid,
|
||||
});
|
||||
|
||||
factory SuccessOperation.fromJson(Map<String, dynamic> json) {
|
||||
return SuccessOperation(
|
||||
success: json['success'],
|
||||
// result: Result.fromJson(json['result']),
|
||||
deviceUuid: json['deviceUuid'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'success': success,
|
||||
// 'result': result.toJson(),
|
||||
'deviceUuid': deviceUuid,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// class Result {
|
||||
// final dynamic effectiveTime;
|
||||
// final dynamic invalidTime;
|
||||
// final dynamic offlineTempPassword;
|
||||
// final dynamic offlineTempPasswordId;
|
||||
// final dynamic offlineTempPasswordName;
|
||||
//
|
||||
// Result({
|
||||
// required this.effectiveTime,
|
||||
// required this.invalidTime,
|
||||
// required this.offlineTempPassword,
|
||||
// required this.offlineTempPasswordId,
|
||||
// required this.offlineTempPasswordName,
|
||||
// });
|
||||
//
|
||||
// factory Result.fromJson(Map<String, dynamic> json) {
|
||||
// return Result(
|
||||
// effectiveTime: json['effective_time'],
|
||||
// invalidTime: json['invalid_time'],
|
||||
// offlineTempPassword: json['offline_temp_password'].toString(),
|
||||
// offlineTempPasswordId: json['offline_temp_password_id'],
|
||||
// offlineTempPasswordName: json['offline_temp_password_name'],
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// Map<String, dynamic> toJson() {
|
||||
// return {
|
||||
// 'effective_time': effectiveTime,
|
||||
// 'invalid_time': invalidTime,
|
||||
// 'offline_temp_password': offlineTempPassword,
|
||||
// 'offline_temp_password_id': offlineTempPasswordId,
|
||||
// 'offline_temp_password_name': offlineTempPasswordName,
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
class PasswordStatus {
|
||||
final List<SuccessOperation> successOperations;
|
||||
final List<FailedOperation> failedOperations;
|
||||
|
||||
PasswordStatus({
|
||||
required this.successOperations,
|
||||
required this.failedOperations,
|
||||
});
|
||||
|
||||
factory PasswordStatus.fromJson(Map<String, dynamic> json) {
|
||||
return PasswordStatus(
|
||||
successOperations: (json['successOperations'] as List)
|
||||
.map((i) => SuccessOperation.fromJson(i))
|
||||
.toList(),
|
||||
failedOperations: (json['failedOperations'] as List)
|
||||
.map((i) => FailedOperation.fromJson(i))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'successOperations': successOperations.map((e) => e.toJson()).toList(),
|
||||
'failedOperations': failedOperations.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +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/constants/app_enum.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class AddDeviceDialog extends StatelessWidget {
|
||||
|
@ -20,21 +20,75 @@ class VisitorPasswordDialog extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Size size = MediaQuery.of(context).size;
|
||||
var text = Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(color: Colors.black, fontSize: 13);
|
||||
var text = Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.black, fontSize: 13);
|
||||
return BlocProvider(
|
||||
create: (context) => VisitorPasswordBloc(),
|
||||
child: BlocListener<VisitorPasswordBloc, VisitorPasswordState>(
|
||||
listener: (context, state) {
|
||||
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
|
||||
if (state is SuccessState) {
|
||||
visitorBloc.stateDialog(
|
||||
context: context,
|
||||
message: 'Password Created Successfully',
|
||||
title: 'Send Success',
|
||||
);
|
||||
visitorBloc
|
||||
.stateDialog(
|
||||
context: context,
|
||||
message: 'Password Created Successfully',
|
||||
title: 'Send Success',
|
||||
widgeta: Column(
|
||||
children: [
|
||||
if (visitorBloc.passwordStatus!.failedOperations.isNotEmpty)
|
||||
Column(
|
||||
children: [
|
||||
const Text('Failed Devises'),
|
||||
SizedBox(
|
||||
width: 200,
|
||||
height: 50,
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
shrinkWrap: true,
|
||||
itemCount: visitorBloc.passwordStatus!.failedOperations.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Container(
|
||||
margin: EdgeInsets.all(5),
|
||||
decoration: containerDecoration,
|
||||
height: 45,
|
||||
child: Center(
|
||||
child: Text(visitorBloc
|
||||
.passwordStatus!.failedOperations[index].deviceUuid)),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (visitorBloc.passwordStatus!.successOperations.isNotEmpty)
|
||||
Column(
|
||||
children: [
|
||||
const Text('Success Devises'),
|
||||
SizedBox(
|
||||
width: 200,
|
||||
height: 50,
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
shrinkWrap: true,
|
||||
itemCount: visitorBloc.passwordStatus!.successOperations.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Container(
|
||||
margin: EdgeInsets.all(5),
|
||||
decoration: containerDecoration,
|
||||
height: 45,
|
||||
child: Center(
|
||||
child: Text(visitorBloc.passwordStatus!
|
||||
.successOperations[index].deviceUuid)),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
))
|
||||
.then((v) {
|
||||
Navigator.of(context).pop();
|
||||
});
|
||||
} else if (state is FailedState) {
|
||||
visitorBloc.stateDialog(
|
||||
context: context,
|
||||
@ -46,16 +100,15 @@ class VisitorPasswordDialog extends StatelessWidget {
|
||||
child: BlocBuilder<VisitorPasswordBloc, VisitorPasswordState>(
|
||||
builder: (BuildContext context, VisitorPasswordState state) {
|
||||
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
|
||||
bool isRepeat =
|
||||
state is IsRepeatState ? state.repeat : visitorBloc.repeat;
|
||||
bool isRepeat = state is IsRepeatState ? state.repeat : visitorBloc.repeat;
|
||||
return AlertDialog(
|
||||
backgroundColor: Colors.white,
|
||||
title: Text(
|
||||
'Create visitor password',
|
||||
style: Theme.of(context).textTheme.headlineLarge!.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 24,
|
||||
color: Colors.black),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineLarge!
|
||||
.copyWith(fontWeight: FontWeight.w400, fontSize: 24, color: Colors.black),
|
||||
),
|
||||
content: state is LoadingInitialState
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
@ -73,8 +126,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
||||
flex: 2,
|
||||
child: CustomWebTextField(
|
||||
validator: visitorBloc.validate,
|
||||
controller:
|
||||
visitorBloc.userNameController,
|
||||
controller: visitorBloc.userNameController,
|
||||
isRequired: true,
|
||||
textFieldName: 'Name',
|
||||
description: '',
|
||||
@ -116,95 +168,111 @@ class VisitorPasswordDialog extends StatelessWidget {
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(
|
||||
'Online Password',
|
||||
style: text,
|
||||
),
|
||||
value: 'Online Password',
|
||||
groupValue: (state
|
||||
is PasswordTypeSelected)
|
||||
? state.selectedType
|
||||
: visitorBloc.accessTypeSelected,
|
||||
onChanged: (String? value) {
|
||||
if (value != null) {
|
||||
context
|
||||
.read<VisitorPasswordBloc>()
|
||||
.add(SelectPasswordType(
|
||||
value));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text('Offline Password',
|
||||
style: text),
|
||||
value: 'Offline Password',
|
||||
groupValue: (state
|
||||
is PasswordTypeSelected)
|
||||
? state.selectedType
|
||||
: visitorBloc.accessTypeSelected,
|
||||
onChanged: (String? value) {
|
||||
if (value != null) {
|
||||
context
|
||||
.read<VisitorPasswordBloc>()
|
||||
.add(SelectPasswordType(
|
||||
value));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(
|
||||
'Dynamic Password',
|
||||
style: text,
|
||||
),
|
||||
value: 'Dynamic Password',
|
||||
groupValue: (state
|
||||
is PasswordTypeSelected)
|
||||
? state.selectedType
|
||||
: visitorBloc.accessTypeSelected,
|
||||
onChanged: (String? value) {
|
||||
if (value != null) {
|
||||
context
|
||||
.read<VisitorPasswordBloc>()
|
||||
.add(SelectPasswordType(
|
||||
value));
|
||||
visitorBloc
|
||||
.usageFrequencySelected = '';
|
||||
}
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: size.width * 0.12,
|
||||
child: RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(
|
||||
'Online Password',
|
||||
style: text,
|
||||
),
|
||||
value: 'Online Password',
|
||||
groupValue: (state is PasswordTypeSelected)
|
||||
? state.selectedType
|
||||
: visitorBloc.accessTypeSelected,
|
||||
onChanged: (String? value) {
|
||||
if (value != null) {
|
||||
context
|
||||
.read<VisitorPasswordBloc>()
|
||||
.add(SelectPasswordType(value));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: size.width * 0.12,
|
||||
child: RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text('Offline Password', style: text),
|
||||
value: 'Offline Password',
|
||||
groupValue: (state is PasswordTypeSelected)
|
||||
? state.selectedType
|
||||
: visitorBloc.accessTypeSelected,
|
||||
onChanged: (String? value) {
|
||||
if (value != null) {
|
||||
context
|
||||
.read<VisitorPasswordBloc>()
|
||||
.add(SelectPasswordType(value));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: size.width * 0.12,
|
||||
child: RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(
|
||||
'Dynamic Password',
|
||||
style: text,
|
||||
),
|
||||
value: 'Dynamic Password',
|
||||
groupValue: (state is PasswordTypeSelected)
|
||||
? state.selectedType
|
||||
: visitorBloc.accessTypeSelected,
|
||||
onChanged: (String? value) {
|
||||
if (value != null) {
|
||||
context
|
||||
.read<VisitorPasswordBloc>()
|
||||
.add(SelectPasswordType(value));
|
||||
visitorBloc.usageFrequencySelected = '';
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
const Spacer(
|
||||
flex: 2,
|
||||
),
|
||||
],
|
||||
),
|
||||
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',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager.grayColor,
|
||||
fontSize: 9),
|
||||
),
|
||||
if (visitorBloc.accessTypeSelected == 'Online Password')
|
||||
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',
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager.grayColor,
|
||||
fontSize: 9),
|
||||
),
|
||||
if (visitorBloc.accessTypeSelected == 'Offline Password')
|
||||
Text(
|
||||
'Unaffected by the online status of the device, you can select online or offline device, and the system randomly generates a digital password',
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager.grayColor,
|
||||
fontSize: 9),
|
||||
),
|
||||
if (visitorBloc.accessTypeSelected == 'Dynamic Password')
|
||||
Text(
|
||||
'Quick and short-acting password, only valid within 5 minutes after creation, the system randomly generates a digital password.',
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager.grayColor,
|
||||
fontSize: 9),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
)
|
||||
],
|
||||
),
|
||||
visitorBloc.accessTypeSelected ==
|
||||
'Dynamic Password'
|
||||
visitorBloc.accessTypeSelected == 'Dynamic Password'
|
||||
? const SizedBox()
|
||||
: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
@ -223,7 +291,8 @@ class VisitorPasswordDialog extends StatelessWidget {
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
SizedBox(
|
||||
width: size.width * 0.12,
|
||||
child: RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(
|
||||
@ -231,88 +300,113 @@ class VisitorPasswordDialog extends StatelessWidget {
|
||||
style: text,
|
||||
),
|
||||
value: 'One-Time',
|
||||
groupValue: (state
|
||||
is UsageFrequencySelected)
|
||||
groupValue: (state is UsageFrequencySelected)
|
||||
? state.selectedFrequency
|
||||
: visitorBloc
|
||||
.usageFrequencySelected,
|
||||
: visitorBloc.usageFrequencySelected,
|
||||
onChanged: (String? value) {
|
||||
if (value != null) {
|
||||
context
|
||||
.read<
|
||||
VisitorPasswordBloc>()
|
||||
.add(
|
||||
SelectUsageFrequency(
|
||||
value));
|
||||
.read<VisitorPasswordBloc>()
|
||||
.add(SelectUsageFrequency(value));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
SizedBox(
|
||||
width: size.width * 0.12,
|
||||
child: RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text('Periodic',
|
||||
style: text),
|
||||
title: Text('Periodic', style: text),
|
||||
value: 'Periodic',
|
||||
groupValue: (state
|
||||
is UsageFrequencySelected)
|
||||
groupValue: (state is UsageFrequencySelected)
|
||||
? state.selectedFrequency
|
||||
: visitorBloc
|
||||
.usageFrequencySelected,
|
||||
: visitorBloc.usageFrequencySelected,
|
||||
onChanged: (String? value) {
|
||||
if (value != null) {
|
||||
context
|
||||
.read<
|
||||
VisitorPasswordBloc>()
|
||||
.add(
|
||||
SelectUsageFrequency(
|
||||
value));
|
||||
.read<VisitorPasswordBloc>()
|
||||
.add(SelectUsageFrequency(value));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'Within the validity period, each device can be unlocked only once.',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
color:
|
||||
ColorsManager.grayColor,
|
||||
fontSize: 9),
|
||||
)
|
||||
|
||||
//One-Time
|
||||
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
|
||||
visitorBloc.accessTypeSelected == 'Online Password')
|
||||
Text(
|
||||
'Within the validity period, each device can be unlocked only once.',
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: ColorsManager.grayColor, fontSize: 9),
|
||||
),
|
||||
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
|
||||
visitorBloc.accessTypeSelected == 'Offline Password')
|
||||
Text(
|
||||
'Within the validity period, there is no limit to the number of times each device can be unlocked.',
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: ColorsManager.grayColor, fontSize: 9),
|
||||
),
|
||||
|
||||
// Periodic
|
||||
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
|
||||
visitorBloc.accessTypeSelected == 'Offline Password')
|
||||
Text(
|
||||
'Within the validity period, there is no limit to the number of times each device can be unlocked, and it should be used at least once within 24 hours after the entry into force.',
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: ColorsManager.grayColor, fontSize: 9),
|
||||
),
|
||||
|
||||
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
|
||||
visitorBloc.accessTypeSelected == 'Online Password')
|
||||
Text(
|
||||
'Within the validity period, there is no limit to the number of times each device can be unlocked.',
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: ColorsManager.grayColor, fontSize: 9),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
if ((visitorBloc.usageFrequencySelected !=
|
||||
'One-Time' ||
|
||||
visitorBloc.accessTypeSelected !=
|
||||
'Offline Password') &&
|
||||
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,
|
||||
isRepeat: false));
|
||||
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
|
||||
visitorBloc.accessTypeSelected == 'Offline Password') {
|
||||
visitorBloc.add(
|
||||
SelectTimeEvent(context: context, isEffective: false));
|
||||
} else {
|
||||
visitorBloc.add(SelectTimeVisitorPassword(
|
||||
context: context, isStart: false, isRepeat: false));
|
||||
}
|
||||
},
|
||||
startTime: () {
|
||||
visitorBloc.add(SelectTimeVisitorPassword(
|
||||
context: context,
|
||||
isStart: true,
|
||||
isRepeat: false));
|
||||
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
|
||||
visitorBloc.accessTypeSelected == 'Offline Password') {
|
||||
visitorBloc.add(
|
||||
SelectTimeEvent(context: context, isEffective: true));
|
||||
} else {
|
||||
visitorBloc.add(SelectTimeVisitorPassword(
|
||||
context: context, isStart: true, isRepeat: false));
|
||||
}
|
||||
},
|
||||
firstString:
|
||||
visitorBloc.startTimeAccess.toString(),
|
||||
secondString:
|
||||
visitorBloc.endTimeAccess.toString(),
|
||||
firstString: (visitorBloc.usageFrequencySelected ==
|
||||
'Periodic' &&
|
||||
visitorBloc.accessTypeSelected == 'Offline Password')
|
||||
? visitorBloc.effectiveTime
|
||||
: visitorBloc.startTimeAccess.toString(),
|
||||
secondString: (visitorBloc.usageFrequencySelected ==
|
||||
'Periodic' &&
|
||||
visitorBloc.accessTypeSelected == 'Offline Password')
|
||||
? visitorBloc.expirationTime
|
||||
: visitorBloc.endTimeAccess.toString(),
|
||||
icon: Assets.calendarIcon),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
@ -337,21 +431,16 @@ class VisitorPasswordDialog extends StatelessWidget {
|
||||
),
|
||||
Text(
|
||||
'Within the validity period, each device can be unlocked only once.',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager.grayColor,
|
||||
fontSize: 9),
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager.grayColor,
|
||||
fontSize: 9),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
if (visitorBloc.usageFrequencySelected ==
|
||||
'Periodic' &&
|
||||
visitorBloc.accessTypeSelected ==
|
||||
'Online Password')
|
||||
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
|
||||
visitorBloc.accessTypeSelected == 'Online Password')
|
||||
SizedBox(
|
||||
width: 100,
|
||||
child: Column(
|
||||
@ -362,8 +451,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
||||
child: CupertinoSwitch(
|
||||
value: visitorBloc.repeat,
|
||||
onChanged: (value) {
|
||||
visitorBloc
|
||||
.add(ToggleRepeatEvent());
|
||||
visitorBloc.add(ToggleRepeatEvent());
|
||||
},
|
||||
applyTheme: true,
|
||||
),
|
||||
@ -371,13 +459,9 @@ class VisitorPasswordDialog extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
if (visitorBloc.usageFrequencySelected ==
|
||||
'Periodic' &&
|
||||
visitorBloc.accessTypeSelected ==
|
||||
'Online Password')
|
||||
isRepeat
|
||||
? const RepeatWidget()
|
||||
: const SizedBox(),
|
||||
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
|
||||
visitorBloc.accessTypeSelected == 'Online Password')
|
||||
isRepeat ? const RepeatWidget() : const SizedBox(),
|
||||
Container(
|
||||
decoration: containerDecoration,
|
||||
width: size.width / 9,
|
||||
@ -388,28 +472,22 @@ class VisitorPasswordDialog extends StatelessWidget {
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return AddDeviceDialog(
|
||||
selectedDeviceIds:
|
||||
visitorBloc.selectedDevices,
|
||||
selectedDeviceIds: visitorBloc.selectedDevices,
|
||||
);
|
||||
},
|
||||
).then((listDevice) {
|
||||
if (listDevice != null) {
|
||||
visitorBloc.selectedDevices =
|
||||
listDevice;
|
||||
visitorBloc.selectedDevices = listDevice;
|
||||
}
|
||||
});
|
||||
},
|
||||
borderRadius: 8,
|
||||
child: Text(
|
||||
'+ Add Device',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
color:
|
||||
ColorsManager.whiteColors,
|
||||
fontSize: 12),
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager.whiteColors,
|
||||
fontSize: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -447,15 +525,36 @@ class VisitorPasswordDialog extends StatelessWidget {
|
||||
onPressed: () {
|
||||
if (visitorBloc.forgetFormKey.currentState!.validate()) {
|
||||
if (visitorBloc.selectedDevices.isNotEmpty) {
|
||||
if (visitorBloc.effectiveTimeTimeStamp != null &&
|
||||
visitorBloc.expirationTimeTimeStamp != null) {
|
||||
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
|
||||
visitorBloc.accessTypeSelected == 'Offline Password') {
|
||||
setPasswordFunction(context, size, visitorBloc);
|
||||
} else if (visitorBloc.accessTypeSelected == 'Dynamic Password') {
|
||||
print('objectobjectobjectobject');
|
||||
setPasswordFunction(context, size, visitorBloc);
|
||||
} else {
|
||||
visitorBloc.stateDialog(
|
||||
context: context,
|
||||
message:
|
||||
'Please select Access Period to continue',
|
||||
title: 'Access Period');
|
||||
if (visitorBloc.effectiveTimeTimeStamp != null &&
|
||||
visitorBloc.expirationTimeTimeStamp != null) {
|
||||
if (isRepeat == true) {
|
||||
if (visitorBloc.expirationTime != 'End Time' &&
|
||||
visitorBloc.effectiveTime != 'Start Time' &&
|
||||
visitorBloc.selectedDays.isNotEmpty) {
|
||||
setPasswordFunction(context, size, visitorBloc);
|
||||
} else {
|
||||
visitorBloc.stateDialog(
|
||||
context: context,
|
||||
message:
|
||||
'Please select days and fill start time and end time to continue',
|
||||
title: 'Access Period');
|
||||
}
|
||||
} else {
|
||||
setPasswordFunction(context, size, visitorBloc);
|
||||
}
|
||||
} else {
|
||||
visitorBloc.stateDialog(
|
||||
context: context,
|
||||
message: 'Please select Access Period to continue',
|
||||
title: 'Access Period');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
visitorBloc.stateDialog(
|
||||
@ -465,6 +564,57 @@ class VisitorPasswordDialog extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// onPressed: () {
|
||||
// if (visitorBloc.forgetFormKey.currentState!.validate()) {
|
||||
// if (visitorBloc.selectedDevices.isNotEmpty) {
|
||||
// switch (visitorBloc.usageFrequencySelected) {
|
||||
// case 'One-Time':
|
||||
// if (visitorBloc.accessTypeSelected == 'Offline Password') {
|
||||
// setPasswordFunction(context, size, visitorBloc);
|
||||
// } else {
|
||||
// visitorBloc.stateDialog(
|
||||
// context: context,
|
||||
// message: 'Invalid combination of Access Type and Usage Frequency.',
|
||||
// title: 'Error',
|
||||
// );
|
||||
// }
|
||||
// break;
|
||||
// default:
|
||||
// if (visitorBloc.effectiveTimeTimeStamp != null && visitorBloc.expirationTimeTimeStamp != null) {
|
||||
// if (isRepeat) {
|
||||
// if (visitorBloc.expirationTime != 'End Time' &&
|
||||
// visitorBloc.effectiveTime != 'Start Time' &&
|
||||
// visitorBloc.selectedDays.isNotEmpty) {
|
||||
// setPasswordFunction(context, size, visitorBloc);
|
||||
// } else {
|
||||
// visitorBloc.stateDialog(
|
||||
// context: context,
|
||||
// message: 'Please select days and fill start time and end time to continue',
|
||||
// title: 'Access Period',
|
||||
// );
|
||||
// }
|
||||
// } else {
|
||||
// setPasswordFunction(context, size, visitorBloc);
|
||||
// }
|
||||
// } else {
|
||||
// visitorBloc.stateDialog(
|
||||
// context: context,
|
||||
// message: 'Please select Access Period to continue',
|
||||
// title: 'Access Period',
|
||||
// );
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// } else {
|
||||
// visitorBloc.stateDialog(
|
||||
// context: context,
|
||||
// message: 'Please select devices to continue',
|
||||
// title: 'Select Devices',
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
borderRadius: 8,
|
||||
child: Text(
|
||||
'Ok',
|
||||
@ -501,8 +651,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
||||
content: SizedBox(
|
||||
height: size.height * 0.25,
|
||||
child: Center(
|
||||
child:
|
||||
CircularProgressIndicator(), // Display a loading spinner
|
||||
child: CircularProgressIndicator(), // Display a loading spinner
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -526,10 +675,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
||||
),
|
||||
Text(
|
||||
'Set Password',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineLarge!
|
||||
.copyWith(
|
||||
style: Theme.of(context).textTheme.headlineLarge!.copyWith(
|
||||
fontSize: 30,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.black,
|
||||
@ -578,47 +724,39 @@ class VisitorPasswordDialog extends StatelessWidget {
|
||||
borderRadius: 8,
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
|
||||
visitorBloc.accessTypeSelected ==
|
||||
'Online Password') {
|
||||
visitorBloc.add(OnlineOneTimePasswordEvent(
|
||||
context: context,
|
||||
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(
|
||||
context: context,
|
||||
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(),
|
||||
));
|
||||
if (visitorBloc.accessTypeSelected == 'Dynamic Password') {
|
||||
} else {
|
||||
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
|
||||
visitorBloc.accessTypeSelected == 'Online Password') {
|
||||
visitorBloc.add(OnlineOneTimePasswordEvent(
|
||||
context: context,
|
||||
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(
|
||||
context: context,
|
||||
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: Text(
|
||||
|
@ -1,5 +1,4 @@
|
||||
import 'dart:convert';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:syncrow_web/pages/access_management/model/password_model.dart';
|
||||
import 'package:syncrow_web/pages/visitor_password/model/device_model.dart';
|
||||
@ -48,39 +47,29 @@ class AccessMangApi {
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> postOnlineOneTime(
|
||||
Future postOnlineOneTime(
|
||||
{String? email,
|
||||
String? passwordName,
|
||||
String? password,
|
||||
String? effectiveTime,
|
||||
String? invalidTime,
|
||||
List<String>? devicesUuid}) async {
|
||||
try {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.sendOnlineOneTime,
|
||||
body: jsonEncode({
|
||||
"email": email,
|
||||
"passwordName": passwordName,
|
||||
"password": password,
|
||||
"devicesUuid": devicesUuid,
|
||||
"effectiveTime": effectiveTime,
|
||||
"invalidTime": invalidTime
|
||||
}),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
if (json['statusCode'].toString() == '201') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
);
|
||||
return response;
|
||||
} on DioException catch (e) {
|
||||
debugPrint('Error: ${e.message}');
|
||||
debugPrint('Error fetching ${e.response!.statusMessage}');
|
||||
return false;
|
||||
}
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.sendOnlineOneTime,
|
||||
body: jsonEncode({
|
||||
"email": email,
|
||||
"passwordName": passwordName,
|
||||
"password": password,
|
||||
"devicesUuid": devicesUuid,
|
||||
"effectiveTime": effectiveTime,
|
||||
"invalidTime": invalidTime
|
||||
}),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return json;
|
||||
},
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
Future postOnlineMultipleTime(
|
||||
@ -91,66 +80,41 @@ class AccessMangApi {
|
||||
String? passwordName,
|
||||
List<Schedule>? scheduleList,
|
||||
List<String>? devicesUuid}) async {
|
||||
try {
|
||||
Map<String, dynamic> body = {
|
||||
"email": email,
|
||||
"devicesUuid": devicesUuid,
|
||||
"passwordName": passwordName,
|
||||
"password": password,
|
||||
"effectiveTime": effectiveTime,
|
||||
"invalidTime": invalidTime,
|
||||
};
|
||||
if (scheduleList != null) {
|
||||
body["scheduleList"] =
|
||||
scheduleList.map((schedule) => schedule.toJson()).toList();
|
||||
}
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.sendOnlineMultipleTime,
|
||||
body: jsonEncode(body),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
if (json['data']['successOperations'][0]['success'].toString() ==
|
||||
'true') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
);
|
||||
return response;
|
||||
} on DioException catch (e) {
|
||||
debugPrint('Error fetching ${e.type.name}');
|
||||
debugPrint('Error fetching ${e.response!.statusMessage}');
|
||||
return false;
|
||||
Map<String, dynamic> body = {
|
||||
"email": email,
|
||||
"devicesUuid": devicesUuid,
|
||||
"passwordName": passwordName,
|
||||
"password": password,
|
||||
"effectiveTime": effectiveTime,
|
||||
"invalidTime": invalidTime,
|
||||
};
|
||||
if (scheduleList != null) {
|
||||
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList();
|
||||
}
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.sendOnlineMultipleTime,
|
||||
body: jsonEncode(body),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return json;
|
||||
},
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
// OffLine One Time Password
|
||||
|
||||
Future postOffLineOneTime(
|
||||
{String? email, String? passwordName, List<String>? devicesUuid}) async {
|
||||
try {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.sendOffLineOneTime,
|
||||
body: jsonEncode({
|
||||
"email": email,
|
||||
"passwordName": passwordName,
|
||||
"devicesUuid": devicesUuid
|
||||
}),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
if (json['data']['successOperations'][0]['success'].toString() ==
|
||||
'true') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return response;
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching $e');
|
||||
return [];
|
||||
}
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.sendOffLineOneTime,
|
||||
body: jsonEncode({"email": email, "passwordName": passwordName, "devicesUuid": devicesUuid}),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return json;
|
||||
},
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
Future postOffLineMultipleTime(
|
||||
@ -159,29 +123,27 @@ class AccessMangApi {
|
||||
String? effectiveTime,
|
||||
String? invalidTime,
|
||||
List<String>? devicesUuid}) async {
|
||||
try {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.sendOffLineOneTime,
|
||||
body: jsonEncode({
|
||||
"email": email,
|
||||
"devicesUuid": devicesUuid,
|
||||
"passwordName": passwordName,
|
||||
"effectiveTime": effectiveTime,
|
||||
"invalidTime": invalidTime
|
||||
}),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
if (json['data']['successOperations'][0]['success'].toString() ==
|
||||
'true') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return response;
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching $e');
|
||||
return [];
|
||||
}
|
||||
print(jsonEncode({
|
||||
"email": email,
|
||||
"devicesUuid": devicesUuid,
|
||||
"passwordName": passwordName,
|
||||
"effectiveTime": effectiveTime,
|
||||
"invalidTime": invalidTime,
|
||||
}));
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.sendOffLineMultipleTime,
|
||||
body: jsonEncode({
|
||||
"email": email,
|
||||
"devicesUuid": devicesUuid,
|
||||
"passwordName": passwordName,
|
||||
"effectiveTime": effectiveTime,
|
||||
"invalidTime": invalidTime,
|
||||
}),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return json;
|
||||
},
|
||||
);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
@ -29,17 +29,17 @@ class AuthenticationAPI {
|
||||
return response;
|
||||
}
|
||||
|
||||
static Future<int?> sendOtp(
|
||||
{required String email, required String regionUuid}) async {
|
||||
static Future<int?> sendOtp({required String email, required String regionUuid}) async {
|
||||
try {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.sendOtp,
|
||||
body: {"email": email, "type": "PASSWORD", "regionUuid": regionUuid},
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return 30;
|
||||
return json['data']['cooldown'];
|
||||
});
|
||||
return 30;
|
||||
|
||||
return response;
|
||||
} on DioException catch (e) {
|
||||
if (e.response != null) {
|
||||
if (e.response!.statusCode == 400) {
|
||||
@ -52,8 +52,7 @@ class AuthenticationAPI {
|
||||
return cooldown;
|
||||
}
|
||||
} else {
|
||||
debugPrint(
|
||||
'Error: ${e.response!.statusCode} - ${e.response!.statusMessage}');
|
||||
debugPrint('Error: ${e.response!.statusCode} - ${e.response!.statusMessage}');
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
@ -66,8 +65,7 @@ class AuthenticationAPI {
|
||||
}
|
||||
}
|
||||
|
||||
static Future verifyOtp(
|
||||
{required String email, required String otpCode}) async {
|
||||
static Future verifyOtp({required String email, required String otpCode}) async {
|
||||
try {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.verifyOtp,
|
||||
@ -99,9 +97,7 @@ class AuthenticationAPI {
|
||||
path: ApiEndpoints.getRegion,
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return (json as List)
|
||||
.map((zone) => RegionModel.fromJson(zone))
|
||||
.toList();
|
||||
return (json as List).map((zone) => RegionModel.fromJson(zone)).toList();
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
34
lib/utils/app_routes.dart
Normal file
34
lib/utils/app_routes.dart
Normal file
@ -0,0 +1,34 @@
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:syncrow_web/pages/access_management/view/access_management.dart';
|
||||
import 'package:syncrow_web/pages/auth/view/login_page.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/view/device_managment_page.dart';
|
||||
import 'package:syncrow_web/pages/home/view/home_page.dart';
|
||||
import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart';
|
||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||
|
||||
class AppRoutes {
|
||||
static List<GoRoute> getRoutes() {
|
||||
return [
|
||||
GoRoute(
|
||||
path: RoutesConst.auth,
|
||||
builder: (context, state) => const LoginPage(),
|
||||
),
|
||||
GoRoute(
|
||||
path: RoutesConst.home,
|
||||
builder: (context, state) => const HomePage(),
|
||||
),
|
||||
GoRoute(
|
||||
path: RoutesConst.visitorPassword,
|
||||
builder: (context, state) => const VisitorPasswordDialog(),
|
||||
),
|
||||
GoRoute(
|
||||
path: RoutesConst.accessManagementPage,
|
||||
builder: (context, state) => const AccessManagementPage(),
|
||||
),
|
||||
GoRoute(
|
||||
path: RoutesConst.deviceManagementPage,
|
||||
builder: (context, state) => const DeviceManagementPage(),
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
@ -36,4 +36,11 @@ abstract class ColorsManager {
|
||||
static const Color blueColor = Color(0xFF0036E6);
|
||||
static const Color boxColor = Color(0xFFF5F6F7);
|
||||
static const Color boxDivider = Color(0xFFE0E0E0);
|
||||
static const Color blue1 = Color(0xFF0036E6);
|
||||
static const Color blue2 = Color(0xFF0026A2);
|
||||
static const Color blue3 = Color(0xFF00165E);
|
||||
static const Color blue4 = Color(0xFF001E7E);
|
||||
static const Color textGreen = Color(0xFF008905);
|
||||
static const Color yaGreen = Color(0xFFFFBF44);
|
||||
}
|
||||
//0036E6
|
@ -13,12 +13,10 @@ class Assets {
|
||||
static const String rightLine = "assets/images/right_line.png";
|
||||
static const String google = "assets/images/google.svg";
|
||||
static const String facebook = "assets/images/facebook.svg";
|
||||
static const String invisiblePassword =
|
||||
"assets/images/Password_invisible.svg";
|
||||
static const String invisiblePassword = "assets/images/Password_invisible.svg";
|
||||
static const String visiblePassword = "assets/images/Password_visible.svg";
|
||||
static const String accessIcon = "assets/images/access_icon.svg";
|
||||
static const String spaseManagementIcon =
|
||||
"assets/images/spase_management_icon.svg";
|
||||
static const String spaseManagementIcon = "assets/images/spase_management_icon.svg";
|
||||
static const String devicesIcon = "assets/images/devices_icon.svg";
|
||||
static const String moveinIcon = "assets/images/movein_icon.svg";
|
||||
static const String constructionIcon = "assets/images/construction_icon.svg";
|
||||
@ -31,15 +29,13 @@ class Assets {
|
||||
static const String emptyTable = "assets/images/empty_table.svg";
|
||||
|
||||
// General assets
|
||||
static const String motionlessDetection =
|
||||
"assets/icons/motionless_detection.svg";
|
||||
static const String motionlessDetection = "assets/icons/motionless_detection.svg";
|
||||
static const String acHeating = "assets/icons/ac_heating.svg";
|
||||
static const String acPowerOff = "assets/icons/ac_power_off.svg";
|
||||
static const String acFanMiddle = "assets/icons/ac_fan_middle.svg";
|
||||
static const String switchAlarmSound = "assets/icons/switch_alarm_sound.svg";
|
||||
static const String resetOff = "assets/icons/reset_off.svg";
|
||||
static const String sensitivityOperationIcon =
|
||||
"assets/icons/sesitivity_operation_icon.svg";
|
||||
static const String sensitivityOperationIcon = "assets/icons/sesitivity_operation_icon.svg";
|
||||
static const String motionDetection = "assets/icons/motion_detection.svg";
|
||||
static const String freezing = "assets/icons/freezing.svg";
|
||||
static const String indicator = "assets/icons/indicator.svg";
|
||||
@ -60,8 +56,7 @@ class Assets {
|
||||
static const String celsiusDegrees = "assets/icons/celsius_degrees.svg";
|
||||
static const String masterState = "assets/icons/master_state.svg";
|
||||
static const String acPower = "assets/icons/ac_power.svg";
|
||||
static const String farDetectionFunction =
|
||||
"assets/icons/far_detection_function.svg";
|
||||
static const String farDetectionFunction = "assets/icons/far_detection_function.svg";
|
||||
static const String nobodyTime = "assets/icons/nobody_time.svg";
|
||||
|
||||
// Automation functions
|
||||
@ -69,47 +64,33 @@ class Assets {
|
||||
"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 doorbell = "assets/icons/automation_functions/doorbell.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 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 hijackAlarm =
|
||||
"assets/icons/automation_functions/hijack_alarm.svg";
|
||||
static const String passwordUnlock =
|
||||
"assets/icons/automation_functions/password_unlock.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 cardUnlock =
|
||||
"assets/icons/automation_functions/card_unlock.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";
|
||||
|
||||
// Presence Sensor Assets
|
||||
static const String sensorMotionIcon = "assets/icons/sensor_motion_ic.svg";
|
||||
static const String sensorPresenceIcon =
|
||||
"assets/icons/sensor_presence_ic.svg";
|
||||
static const String sensorPresenceIcon = "assets/icons/sensor_presence_ic.svg";
|
||||
static const String sensorVacantIcon = "assets/icons/sensor_vacant_ic.svg";
|
||||
static const String illuminanceRecordIcon =
|
||||
"assets/icons/illuminance_record_ic.svg";
|
||||
static const String presenceRecordIcon =
|
||||
"assets/icons/presence_record_ic.svg";
|
||||
static const String helpDescriptionIcon =
|
||||
"assets/icons/help_description_ic.svg";
|
||||
static const String illuminanceRecordIcon = "assets/icons/illuminance_record_ic.svg";
|
||||
static const String presenceRecordIcon = "assets/icons/presence_record_ic.svg";
|
||||
static const String helpDescriptionIcon = "assets/icons/help_description_ic.svg";
|
||||
|
||||
static const String lightPulp = "assets/icons/light_pulb.svg";
|
||||
static const String acDevice = "assets/icons/ac_device.svg";
|
||||
@ -142,4 +123,5 @@ class Assets {
|
||||
static const String dyi = 'assets/icons/dyi.svg';
|
||||
static const String office = 'assets/icons/office.svg';
|
||||
static const String parlour = 'assets/icons/parlour.svg';
|
||||
static const String grid = "assets/images/grid.svg";
|
||||
}
|
||||
|
7
lib/utils/constants/routes_const.dart
Normal file
7
lib/utils/constants/routes_const.dart
Normal file
@ -0,0 +1,7 @@
|
||||
class RoutesConst {
|
||||
static const String auth = '/login';
|
||||
static const String home = '/';
|
||||
static const String visitorPassword = '/visitor-password';
|
||||
static const String accessManagementPage = '/access-management-page';
|
||||
static const String deviceManagementPage = '/device-management-page';
|
||||
}
|
@ -5,3 +5,6 @@ class NavigationService {
|
||||
static GlobalKey<ScaffoldMessengerState>? snackbarKey =
|
||||
GlobalKey<ScaffoldMessengerState>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
40
pubspec.lock
40
pubspec.lock
@ -216,6 +216,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.7.0"
|
||||
go_router:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: go_router
|
||||
sha256: "2ddb88e9ad56ae15ee144ed10e33886777eb5ca2509a914850a5faa7b52ff459"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.7"
|
||||
graphview:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -260,18 +268,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
||||
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.5"
|
||||
version: "10.0.4"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
||||
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.5"
|
||||
version: "3.0.3"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -288,6 +296,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -300,18 +316,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
||||
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.11.1"
|
||||
version: "0.8.0"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
||||
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
version: "1.12.0"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -521,10 +537,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
|
||||
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.2"
|
||||
version: "0.7.0"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -569,10 +585,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
||||
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.5"
|
||||
version: "14.2.1"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -44,7 +44,9 @@ dependencies:
|
||||
flutter_secure_storage: ^9.2.2
|
||||
shared_preferences: ^2.3.0
|
||||
data_table_2: ^2.5.15
|
||||
go_router:
|
||||
intl: ^0.19.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
Reference in New Issue
Block a user