mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-09 14:47:23 +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.
|
description: This file stores settings for Dart & Flutter DevTools.
|
||||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||||
extensions:
|
extensions:
|
||||||
|
- provider: true
|
||||||
|
@ -2,28 +2,34 @@ import 'package:flutter/gestures.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/auth/bloc/auth_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/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: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/services/locator.dart';
|
||||||
|
import 'package:syncrow_web/utils/app_routes.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
initialSetup(); // Perform initial setup, e.g., dependency injection
|
initialSetup();
|
||||||
String checkToken = await AuthBloc.getTokenAndValidate();
|
String checkToken = await AuthBloc.getTokenAndValidate();
|
||||||
|
GoRouter router = GoRouter(
|
||||||
|
initialLocation: checkToken == 'Success' ? RoutesConst.home : RoutesConst.auth,
|
||||||
|
routes: AppRoutes.getRoutes(),
|
||||||
|
);
|
||||||
runApp(MyApp(
|
runApp(MyApp(
|
||||||
isLoggedIn: checkToken,
|
router: router,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
final dynamic isLoggedIn;
|
final GoRouter router;
|
||||||
const MyApp({
|
const MyApp({
|
||||||
super.key,
|
super.key,
|
||||||
required this.isLoggedIn,
|
required this.router,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
@ -33,7 +39,7 @@ class MyApp extends StatelessWidget {
|
|||||||
create: (context) => VisitorPasswordBloc(),
|
create: (context) => VisitorPasswordBloc(),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
child: MaterialApp(
|
child: MaterialApp.router(
|
||||||
debugShowCheckedModeBanner: false, // Hide debug banner
|
debugShowCheckedModeBanner: false, // Hide debug banner
|
||||||
scrollBehavior: const MaterialScrollBehavior().copyWith(
|
scrollBehavior: const MaterialScrollBehavior().copyWith(
|
||||||
dragDevices: {
|
dragDevices: {
|
||||||
@ -48,9 +54,7 @@ class MyApp extends StatelessWidget {
|
|||||||
fontFamily: 'Aftika',
|
fontFamily: 'Aftika',
|
||||||
textTheme: const TextTheme(
|
textTheme: const TextTheme(
|
||||||
bodySmall: TextStyle(
|
bodySmall: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13, color: ColorsManager.whiteColors, fontWeight: FontWeight.bold),
|
||||||
color: ColorsManager.whiteColors,
|
|
||||||
fontWeight: FontWeight.bold),
|
|
||||||
bodyMedium: TextStyle(color: Colors.black87, fontSize: 14),
|
bodyMedium: TextStyle(color: Colors.black87, fontSize: 14),
|
||||||
bodyLarge: TextStyle(fontSize: 16, color: Colors.white),
|
bodyLarge: TextStyle(fontSize: 16, color: Colors.white),
|
||||||
headlineSmall: TextStyle(color: Colors.black87, fontSize: 18),
|
headlineSmall: TextStyle(color: Colors.black87, fontSize: 18),
|
||||||
@ -61,47 +65,10 @@ class MyApp extends StatelessWidget {
|
|||||||
fontWeight: FontWeight.bold,
|
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/pages/access_management/model/password_model.dart';
|
||||||
import 'package:syncrow_web/services/access_mang_api.dart';
|
import 'package:syncrow_web/services/access_mang_api.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.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';
|
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||||
|
|
||||||
class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||||
@ -26,8 +26,7 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
|||||||
List<PasswordModel> filteredData = [];
|
List<PasswordModel> filteredData = [];
|
||||||
List<PasswordModel> data = [];
|
List<PasswordModel> data = [];
|
||||||
|
|
||||||
Future<void> _onFetchTableData(
|
Future<void> _onFetchTableData(FetchTableData event, Emitter<AccessState> emit) async {
|
||||||
FetchTableData event, Emitter<AccessState> emit) async {
|
|
||||||
try {
|
try {
|
||||||
emit(AccessLoaded());
|
emit(AccessLoaded());
|
||||||
data = await AccessMangApi().fetchVisitorPassword();
|
data = await AccessMangApi().fetchVisitorPassword();
|
||||||
@ -40,28 +39,19 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updateTabsCount() {
|
void updateTabsCount() {
|
||||||
int toBeEffectiveCount = data
|
int toBeEffectiveCount =
|
||||||
.where((item) => item.passwordStatus.value == 'To Be Effective')
|
data.where((item) => item.passwordStatus.value == 'To be effective').length;
|
||||||
.length;
|
int effectiveCount = data.where((item) => item.passwordStatus.value == 'Effective').length;
|
||||||
int effectiveCount =
|
int expiredCount = data.where((item) => item.passwordStatus.value == 'Expired').length;
|
||||||
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[1] = 'To Be Effective ($toBeEffectiveCount)';
|
||||||
tabs[2] = 'Effective ($effectiveCount)';
|
tabs[2] = 'Effective ($effectiveCount)';
|
||||||
tabs[3] = 'Expired ($expiredCount)';
|
tabs[3] = 'Expired ($expiredCount)';
|
||||||
}
|
}
|
||||||
|
|
||||||
int selectedIndex = 0;
|
int selectedIndex = 0;
|
||||||
final List<String> tabs = [
|
final List<String> tabs = ['All', 'To Be Effective (0)', 'Effective (0)', 'Expired'];
|
||||||
'All',
|
|
||||||
'To Be Effective (0)',
|
|
||||||
'Effective (0)',
|
|
||||||
'Expired'
|
|
||||||
];
|
|
||||||
|
|
||||||
Future selectFilterTap(
|
Future selectFilterTap(TabChangedEvent event, Emitter<AccessState> emit) async {
|
||||||
TabChangedEvent event, Emitter<AccessState> emit) async {
|
|
||||||
try {
|
try {
|
||||||
emit(AccessLoaded());
|
emit(AccessLoaded());
|
||||||
selectedIndex = event.selectedIndex;
|
selectedIndex = event.selectedIndex;
|
||||||
@ -75,7 +65,6 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
|||||||
|
|
||||||
Future<void> selectTime(SelectTime event, Emitter<AccessState> emit) async {
|
Future<void> selectTime(SelectTime event, Emitter<AccessState> emit) async {
|
||||||
emit(AccessLoaded());
|
emit(AccessLoaded());
|
||||||
|
|
||||||
final DateTime? picked = await showDatePicker(
|
final DateTime? picked = await showDatePicker(
|
||||||
context: event.context,
|
context: event.context,
|
||||||
initialDate: DateTime.now(),
|
initialDate: DateTime.now(),
|
||||||
@ -83,111 +72,112 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
|||||||
lastDate: DateTime(2101),
|
lastDate: DateTime(2101),
|
||||||
);
|
);
|
||||||
if (picked != null) {
|
if (picked != null) {
|
||||||
final TimeOfDay? timePicked = await showTimePicker(
|
final selectedDateTime = DateTime(
|
||||||
context: event.context,
|
picked.year,
|
||||||
initialTime: TimeOfDay.now(),
|
picked.month,
|
||||||
builder: (context, child) {
|
picked.day,
|
||||||
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!,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
if (timePicked != null) {
|
final selectedTimestamp = DateTime(
|
||||||
final selectedDateTime = DateTime(
|
selectedDateTime.year,
|
||||||
picked.year,
|
selectedDateTime.month,
|
||||||
picked.month,
|
selectedDateTime.day,
|
||||||
picked.day,
|
selectedDateTime.hour,
|
||||||
timePicked.hour,
|
selectedDateTime.minute,
|
||||||
timePicked.minute,
|
).millisecondsSinceEpoch ~/
|
||||||
);
|
1000; // Divide by 1000 to remove milliseconds
|
||||||
final selectedTimestamp = DateTime(
|
if (event.isStart) {
|
||||||
selectedDateTime.year,
|
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
|
||||||
selectedDateTime.month,
|
CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.');
|
||||||
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;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (effectiveTimeTimeStamp != null &&
|
startTime =
|
||||||
selectedTimestamp < effectiveTimeTimeStamp!) {
|
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
|
||||||
CustomSnackBar.displaySnackBar(
|
effectiveTimeTimeStamp = selectedTimestamp;
|
||||||
'Expiration Time cannot be earlier than Effective Time.');
|
}
|
||||||
} else {
|
} else {
|
||||||
endTime = selectedDateTime
|
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
|
||||||
.toString()
|
CustomSnackBar.displaySnackBar('Expiration Time cannot be earlier than Effective Time.');
|
||||||
.split('.')
|
} else {
|
||||||
.first; // Remove seconds and milliseconds
|
endTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
|
||||||
expirationTimeTimeStamp = selectedTimestamp;
|
expirationTimeTimeStamp = selectedTimestamp;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit(ChangeTimeState());
|
emit(ChangeTimeState());
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _filterData(
|
Future<void> _filterData(FilterDataEvent event, Emitter<AccessState> emit) async {
|
||||||
FilterDataEvent event, Emitter<AccessState> emit) async {
|
|
||||||
emit(AccessLoaded());
|
emit(AccessLoaded());
|
||||||
try {
|
try {
|
||||||
filteredData = data.where((item) {
|
filteredData = data.where((item) {
|
||||||
bool matchesCriteria = true;
|
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) {
|
if (event.passwordName != null && event.passwordName!.isNotEmpty) {
|
||||||
final bool matchesName = item.passwordName != null &&
|
final bool matchesName =
|
||||||
item.passwordName.contains(event.passwordName);
|
item.passwordName != null && item.passwordName.contains(event.passwordName);
|
||||||
if (!matchesName) {
|
if (!matchesName) {
|
||||||
matchesCriteria = false;
|
matchesCriteria = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (event.startTime != null && event.endTime != null) {
|
|
||||||
final int? effectiveTime =
|
// Filter by start date only
|
||||||
int.tryParse(item.effectiveTime.toString());
|
if (event.startTime != null && event.endTime == null) {
|
||||||
final int? invalidTime = int.tryParse(item.invalidTime.toString());
|
DateTime startDateOnly =
|
||||||
if (effectiveTime == null || invalidTime == null) {
|
DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal();
|
||||||
|
startDateOnly = DateTime(startDateOnly.year, startDateOnly.month, startDateOnly.day);
|
||||||
|
if (effectiveDateOnly.isBefore(startDateOnly)) {
|
||||||
matchesCriteria = false;
|
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;
|
matchesCriteria = false;
|
||||||
} else if (event.selectedTabIndex == 2 &&
|
} else if (event.selectedTabIndex == 2 && item.passwordStatus.value != 'Effective') {
|
||||||
item.passwordStatus.value != 'Effective') {
|
|
||||||
matchesCriteria = false;
|
matchesCriteria = false;
|
||||||
} else if (event.selectedTabIndex == 3 &&
|
} else if (event.selectedTabIndex == 3 && item.passwordStatus.value != 'Expired') {
|
||||||
item.passwordStatus.value != 'Expired') {
|
|
||||||
matchesCriteria = false;
|
matchesCriteria = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return matchesCriteria;
|
return matchesCriteria;
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
emit(TableLoaded(filteredData));
|
emit(TableLoaded(filteredData));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(FailedState(e.toString()));
|
emit(FailedState(e.toString()));
|
||||||
@ -206,13 +196,11 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String timestampToDate(dynamic timestamp) {
|
String timestampToDate(dynamic timestamp) {
|
||||||
DateTime dateTime =
|
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000);
|
||||||
DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000);
|
|
||||||
return "${dateTime.year}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.day.toString().padLeft(2, '0')}";
|
return "${dateTime.year}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.day.toString().padLeft(2, '0')}";
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> onTabChanged(
|
Future<void> onTabChanged(TabChangedEvent event, Emitter<AccessState> emit) async {
|
||||||
TabChangedEvent event, Emitter<AccessState> emit) async {
|
|
||||||
try {
|
try {
|
||||||
emit(AccessLoaded());
|
emit(AccessLoaded());
|
||||||
selectedIndex = event.selectedIndex;
|
selectedIndex = event.selectedIndex;
|
||||||
@ -221,19 +209,14 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
|||||||
filteredData = data;
|
filteredData = data;
|
||||||
break;
|
break;
|
||||||
case 1: // To Be Effective
|
case 1: // To Be Effective
|
||||||
filteredData = data
|
filteredData =
|
||||||
.where((item) => item.passwordStatus.value == "To Be Effective")
|
data.where((item) => item.passwordStatus.value == "To Be Effective").toList();
|
||||||
.toList();
|
|
||||||
break;
|
break;
|
||||||
case 2: // Effective
|
case 2: // Effective
|
||||||
filteredData = data
|
filteredData = data.where((item) => item.passwordStatus.value == "Effective").toList();
|
||||||
.where((item) => item.passwordStatus.value == "Effective")
|
|
||||||
.toList();
|
|
||||||
break;
|
break;
|
||||||
case 3: // Expired
|
case 3: // Expired
|
||||||
filteredData = data
|
filteredData = data.where((item) => item.passwordStatus.value == "Expired").toList();
|
||||||
.where((item) => item.passwordStatus.value == "Expired")
|
|
||||||
.toList();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
filteredData = data;
|
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 {
|
class PasswordModel {
|
||||||
final dynamic passwordId;
|
final dynamic passwordId;
|
||||||
|
@ -1,293 +1,287 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.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_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/bloc/access_event.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/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/custom_table.dart';
|
||||||
import 'package:syncrow_web/pages/common/date_time_widget.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/pages/visitor_password/view/visitor_password_dialog.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.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/utils/style.dart';
|
||||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||||
|
|
||||||
class AccessManagementPage extends StatelessWidget {
|
class AccessManagementPage extends StatelessWidget {
|
||||||
const AccessManagementPage({super.key});
|
const AccessManagementPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Size size = MediaQuery.of(context).size;
|
Size size = MediaQuery.of(context).size;
|
||||||
return WebScaffold(
|
return WebScaffold(
|
||||||
enableMenuSideba: false,
|
enableMenuSideba: false,
|
||||||
appBarTitle: Row(
|
appBarTitle: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Access Management',
|
'Access Management',
|
||||||
style: Theme.of(context).textTheme.headlineLarge,
|
style: Theme.of(context).textTheme.headlineLarge,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
|
||||||
appBarBody: [
|
|
||||||
Text(
|
|
||||||
'Physical Access',
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.headlineMedium!
|
|
||||||
.copyWith(color: Colors.white),
|
|
||||||
),
|
),
|
||||||
],
|
appBarBody: [
|
||||||
scaffoldBody: BlocProvider(
|
Row(
|
||||||
create: (BuildContext context) => AccessBloc()..add(FetchTableData()),
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
child: BlocConsumer<AccessBloc, AccessState>(
|
children: [
|
||||||
listener: (context, state) {},
|
Text(
|
||||||
builder: (context, state) {
|
'Physical Access',
|
||||||
final accessBloc = BlocProvider.of<AccessBloc>(context);
|
style: Theme.of(context).textTheme.headlineMedium!.copyWith(color: Colors.white),
|
||||||
final filteredData = accessBloc.filteredData;
|
),
|
||||||
|
Row(
|
||||||
return state is AccessLoaded
|
children: [
|
||||||
? const Center(child: CircularProgressIndicator())
|
InkWell(
|
||||||
: CustomScrollView(
|
onTap: () {
|
||||||
slivers: [
|
context.go(RoutesConst.home);
|
||||||
SliverToBoxAdapter(
|
},
|
||||||
child: Padding(
|
child: SvgPicture.asset(
|
||||||
padding: const EdgeInsets.all(30),
|
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(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildTabSelector(context, accessBloc, size),
|
Container(
|
||||||
const SizedBox(height: 20),
|
decoration: containerDecoration,
|
||||||
_buildSearchFilters(context, accessBloc, size),
|
height: size.height * 0.05,
|
||||||
const SizedBox(height: 20),
|
child: Flexible(
|
||||||
_buildActionButtons(context, accessBloc, size),
|
child: ListView.builder(
|
||||||
const SizedBox(height: 20),
|
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/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/svg.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_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/auth/bloc/auth_event.dart';
|
import 'package:syncrow_web/pages/auth/bloc/auth_event.dart';
|
||||||
import 'package:syncrow_web/pages/auth/bloc/auth_state.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/pages/common/first_layer.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.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';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class LoginWebPage extends StatefulWidget {
|
class LoginWebPage extends StatefulWidget {
|
||||||
@ -32,13 +31,8 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
child: BlocConsumer<AuthBloc, AuthState>(
|
child: BlocConsumer<AuthBloc, AuthState>(
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
if (state is LoginSuccess) {
|
if (state is LoginSuccess) {
|
||||||
// Navigate to home screen after successful login
|
context.go(RoutesConst.home);
|
||||||
Navigator.pushReplacement(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(builder: (context) => HomePage()),
|
|
||||||
);
|
|
||||||
} else if (state is LoginFailure) {
|
} else if (state is LoginFailure) {
|
||||||
// Show error message
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(state.error),
|
content: Text(state.error),
|
||||||
@ -60,8 +54,7 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
late ScrollController _scrollController;
|
late ScrollController _scrollController;
|
||||||
_scrollController = ScrollController();
|
_scrollController = ScrollController();
|
||||||
void _scrollToCenter() {
|
void _scrollToCenter() {
|
||||||
final double middlePosition =
|
final double middlePosition = _scrollController.position.maxScrollExtent / 2;
|
||||||
_scrollController.position.maxScrollExtent / 2;
|
|
||||||
_scrollController.animateTo(
|
_scrollController.animateTo(
|
||||||
middlePosition,
|
middlePosition,
|
||||||
duration: const Duration(seconds: 1),
|
duration: const Duration(seconds: 1),
|
||||||
@ -105,11 +98,9 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white.withOpacity(0.1),
|
color: Colors.white.withOpacity(0.1),
|
||||||
borderRadius: const BorderRadius.all(
|
borderRadius: const BorderRadius.all(Radius.circular(30)),
|
||||||
Radius.circular(30)),
|
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: ColorsManager.graysColor
|
color: ColorsManager.graysColor.withOpacity(0.2))),
|
||||||
.withOpacity(0.2))),
|
|
||||||
child: Form(
|
child: Form(
|
||||||
key: loginBloc.loginFormKey,
|
key: loginBloc.loginFormKey,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@ -117,22 +108,16 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
horizontal: size.width * 0.02,
|
horizontal: size.width * 0.02,
|
||||||
vertical: size.width * 0.003),
|
vertical: size.width * 0.003),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
MainAxisAlignment.spaceEvenly,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
crossAxisAlignment:
|
|
||||||
CrossAxisAlignment.start,
|
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
Text('Login',
|
Text('Login',
|
||||||
style: Theme.of(context)
|
style: Theme.of(context).textTheme.headlineLarge),
|
||||||
.textTheme
|
|
||||||
.headlineLarge),
|
|
||||||
SizedBox(height: size.height * 0.03),
|
SizedBox(height: size.height * 0.03),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment:
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
CrossAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Country/Region",
|
"Country/Region",
|
||||||
@ -140,81 +125,57 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
.textTheme
|
.textTheme
|
||||||
.bodySmall!
|
.bodySmall!
|
||||||
.copyWith(
|
.copyWith(
|
||||||
fontSize: 14,
|
fontSize: 14, fontWeight: FontWeight.w400),
|
||||||
fontWeight:
|
|
||||||
FontWeight.w400),
|
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
child: DropdownButtonFormField<
|
child: DropdownButtonFormField<String>(
|
||||||
String>(
|
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
value: loginBloc.regionList!
|
value: loginBloc.regionList!.any((region) =>
|
||||||
.any((region) =>
|
region.id == loginBloc.regionUuid)
|
||||||
region.id ==
|
|
||||||
loginBloc
|
|
||||||
.regionUuid)
|
|
||||||
? loginBloc.regionUuid
|
? loginBloc.regionUuid
|
||||||
: null,
|
: null,
|
||||||
validator:
|
validator: loginBloc.validateRegion,
|
||||||
loginBloc.validateRegion,
|
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons
|
Icons.keyboard_arrow_down_outlined,
|
||||||
.keyboard_arrow_down_outlined,
|
|
||||||
),
|
),
|
||||||
decoration: textBoxDecoration()!
|
decoration: textBoxDecoration()!.copyWith(
|
||||||
.copyWith(
|
errorStyle: const TextStyle(height: 0),
|
||||||
errorStyle: const TextStyle(
|
|
||||||
height: 0),
|
|
||||||
hintText: null,
|
hintText: null,
|
||||||
),
|
),
|
||||||
hint: SizedBox(
|
hint: SizedBox(
|
||||||
width: size.width * 0.12,
|
width: size.width * 0.12,
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment:
|
alignment: Alignment.centerLeft,
|
||||||
Alignment.centerLeft,
|
|
||||||
child: Text(
|
child: Text(
|
||||||
'Select your region/country',
|
'Select your region/country',
|
||||||
textAlign:
|
textAlign: TextAlign.center,
|
||||||
TextAlign.center,
|
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodySmall!
|
.bodySmall!
|
||||||
.copyWith(
|
.copyWith(
|
||||||
color:
|
color: ColorsManager.grayColor,
|
||||||
ColorsManager
|
fontWeight: FontWeight.w400),
|
||||||
.grayColor,
|
overflow: TextOverflow.ellipsis,
|
||||||
fontWeight:
|
|
||||||
FontWeight
|
|
||||||
.w400),
|
|
||||||
overflow:
|
|
||||||
TextOverflow.ellipsis,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
isDense: true,
|
isDense: true,
|
||||||
style: const TextStyle(
|
style: const TextStyle(color: Colors.black),
|
||||||
color: Colors.black),
|
items:
|
||||||
items: loginBloc.regionList!
|
loginBloc.regionList!.map((RegionModel region) {
|
||||||
.map((RegionModel region) {
|
return DropdownMenuItem<String>(
|
||||||
return DropdownMenuItem<
|
|
||||||
String>(
|
|
||||||
value: region.id,
|
value: region.id,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width:
|
width: size.width * 0.08,
|
||||||
size.width * 0.08,
|
child: Text(region.name)),
|
||||||
child:
|
|
||||||
Text(region.name)),
|
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
onChanged: (String? value) {
|
onChanged: (String? value) {
|
||||||
loginBloc
|
loginBloc.add(CheckEnableEvent());
|
||||||
.add(CheckEnableEvent());
|
loginBloc.add(SelectRegionEvent(val: value!));
|
||||||
loginBloc.add(
|
|
||||||
SelectRegionEvent(
|
|
||||||
val: value!));
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -222,10 +183,8 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 20.0),
|
const SizedBox(height: 20.0),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment:
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
CrossAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Email",
|
"Email",
|
||||||
@ -233,9 +192,7 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
.textTheme
|
.textTheme
|
||||||
.bodySmall!
|
.bodySmall!
|
||||||
.copyWith(
|
.copyWith(
|
||||||
fontSize: 14,
|
fontSize: 14, fontWeight: FontWeight.w400),
|
||||||
fontWeight:
|
|
||||||
FontWeight.w400),
|
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
@ -243,43 +200,30 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
loginBloc
|
loginBloc.add(CheckEnableEvent());
|
||||||
.add(CheckEnableEvent());
|
|
||||||
// print(loginBloc.checkEnable());
|
// print(loginBloc.checkEnable());
|
||||||
},
|
},
|
||||||
validator: loginBloc
|
validator: loginBloc.loginValidateEmail,
|
||||||
.loginValidateEmail,
|
controller: loginBloc.loginEmailController,
|
||||||
controller: loginBloc
|
decoration: textBoxDecoration()!.copyWith(
|
||||||
.loginEmailController,
|
errorStyle: const TextStyle(
|
||||||
decoration: textBoxDecoration()!
|
height: 0), // Hide the error text space
|
||||||
.copyWith(
|
hintText: 'Enter your email address',
|
||||||
errorStyle: const TextStyle(
|
hintStyle: Theme.of(context)
|
||||||
height:
|
.textTheme
|
||||||
0), // Hide the error text space
|
.bodySmall!
|
||||||
hintText:
|
.copyWith(
|
||||||
'Enter your email address',
|
color: ColorsManager.grayColor,
|
||||||
hintStyle: Theme.of(
|
fontWeight: FontWeight.w400)),
|
||||||
context)
|
style: const TextStyle(color: Colors.black),
|
||||||
.textTheme
|
|
||||||
.bodySmall!
|
|
||||||
.copyWith(
|
|
||||||
color: ColorsManager
|
|
||||||
.grayColor,
|
|
||||||
fontWeight:
|
|
||||||
FontWeight
|
|
||||||
.w400)),
|
|
||||||
style: const TextStyle(
|
|
||||||
color: Colors.black),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20.0),
|
const SizedBox(height: 20.0),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment:
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
CrossAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Password",
|
"Password",
|
||||||
@ -287,9 +231,7 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
.textTheme
|
.textTheme
|
||||||
.bodySmall!
|
.bodySmall!
|
||||||
.copyWith(
|
.copyWith(
|
||||||
fontSize: 14,
|
fontSize: 14, fontWeight: FontWeight.w400),
|
||||||
fontWeight:
|
|
||||||
FontWeight.w400),
|
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
@ -297,54 +239,39 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
loginBloc
|
loginBloc.add(CheckEnableEvent());
|
||||||
.add(CheckEnableEvent());
|
|
||||||
},
|
},
|
||||||
validator:
|
validator: loginBloc.validatePassword,
|
||||||
loginBloc.validatePassword,
|
obscureText: loginBloc.obscureText,
|
||||||
obscureText:
|
keyboardType: TextInputType.visiblePassword,
|
||||||
loginBloc.obscureText,
|
controller: loginBloc.loginPasswordController,
|
||||||
keyboardType: TextInputType
|
decoration: textBoxDecoration()!.copyWith(
|
||||||
.visiblePassword,
|
hintText: 'At least 8 characters',
|
||||||
controller: loginBloc
|
|
||||||
.loginPasswordController,
|
|
||||||
decoration: textBoxDecoration()!
|
|
||||||
.copyWith(
|
|
||||||
hintText:
|
|
||||||
'At least 8 characters',
|
|
||||||
hintStyle: Theme.of(context)
|
hintStyle: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodySmall!
|
.bodySmall!
|
||||||
.copyWith(
|
.copyWith(
|
||||||
color: ColorsManager
|
color: ColorsManager.grayColor,
|
||||||
.grayColor,
|
fontWeight: FontWeight.w400),
|
||||||
fontWeight:
|
|
||||||
FontWeight.w400),
|
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
loginBloc.add(
|
loginBloc.add(PasswordVisibleEvent(
|
||||||
PasswordVisibleEvent(
|
newValue: loginBloc.obscureText));
|
||||||
newValue: loginBloc
|
|
||||||
.obscureText));
|
|
||||||
},
|
},
|
||||||
icon: SizedBox(
|
icon: SizedBox(
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
loginBloc.obscureText
|
loginBloc.obscureText
|
||||||
? Assets
|
? Assets.visiblePassword
|
||||||
.visiblePassword
|
: Assets.invisiblePassword,
|
||||||
: Assets
|
|
||||||
.invisiblePassword,
|
|
||||||
height: 15,
|
height: 15,
|
||||||
width: 15,
|
width: 15,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
errorStyle: const TextStyle(
|
errorStyle: const TextStyle(
|
||||||
height:
|
height: 0), // Hide the error text space
|
||||||
0), // Hide the error text space
|
|
||||||
),
|
),
|
||||||
style: const TextStyle(
|
style: const TextStyle(color: Colors.black),
|
||||||
color: Colors.black),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -354,13 +281,11 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
MainAxisAlignment.end,
|
|
||||||
children: [
|
children: [
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context)
|
Navigator.of(context).push(MaterialPageRoute(
|
||||||
.push(MaterialPageRoute(
|
|
||||||
builder: (context) =>
|
builder: (context) =>
|
||||||
const ForgetPasswordPage(),
|
const ForgetPasswordPage(),
|
||||||
));
|
));
|
||||||
@ -373,8 +298,7 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
.copyWith(
|
.copyWith(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight:
|
fontWeight: FontWeight.w400),
|
||||||
FontWeight.w400),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -386,18 +310,16 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Transform.scale(
|
Transform.scale(
|
||||||
scale:
|
scale: 1.2, // Adjust the scale as needed
|
||||||
1.2, // Adjust the scale as needed
|
|
||||||
child: Checkbox(
|
child: Checkbox(
|
||||||
fillColor: MaterialStateProperty
|
fillColor:
|
||||||
.all<Color>(Colors.white),
|
MaterialStateProperty.all<Color>(Colors.white),
|
||||||
activeColor: Colors.white,
|
activeColor: Colors.white,
|
||||||
value: loginBloc.isChecked,
|
value: loginBloc.isChecked,
|
||||||
checkColor: Colors.black,
|
checkColor: Colors.black,
|
||||||
shape: const CircleBorder(),
|
shape: const CircleBorder(),
|
||||||
onChanged: (bool? newValue) {
|
onChanged: (bool? newValue) {
|
||||||
loginBloc.add(CheckBoxEvent(
|
loginBloc.add(CheckBoxEvent(newValue: newValue));
|
||||||
newValue: newValue));
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -406,45 +328,36 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
child: RichText(
|
child: RichText(
|
||||||
text: TextSpan(
|
text: TextSpan(
|
||||||
text: 'Agree to ',
|
text: 'Agree to ',
|
||||||
style: const TextStyle(
|
style: const TextStyle(color: Colors.white),
|
||||||
color: Colors.white),
|
|
||||||
children: [
|
children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text:
|
text: '(Terms of Service)',
|
||||||
'(Terms of Service)',
|
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
),
|
),
|
||||||
recognizer:
|
recognizer: TapGestureRecognizer()
|
||||||
TapGestureRecognizer()
|
..onTap = () {
|
||||||
..onTap = () {
|
loginBloc.launchURL(
|
||||||
loginBloc.launchURL(
|
'https://example.com/terms');
|
||||||
'https://example.com/terms');
|
},
|
||||||
},
|
|
||||||
),
|
),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text:
|
text: ' (Legal Statement)',
|
||||||
' (Legal Statement)',
|
style: const TextStyle(color: Colors.black),
|
||||||
style: const TextStyle(
|
recognizer: TapGestureRecognizer()
|
||||||
color: Colors.black),
|
..onTap = () {
|
||||||
recognizer:
|
loginBloc.launchURL(
|
||||||
TapGestureRecognizer()
|
'https://example.com/legal');
|
||||||
..onTap = () {
|
},
|
||||||
loginBloc.launchURL(
|
|
||||||
'https://example.com/legal');
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text:
|
text: ' (Privacy Statement)',
|
||||||
' (Privacy Statement)',
|
style: const TextStyle(color: Colors.black),
|
||||||
style: const TextStyle(
|
recognizer: TapGestureRecognizer()
|
||||||
color: Colors.black),
|
..onTap = () {
|
||||||
recognizer:
|
loginBloc.launchURL(
|
||||||
TapGestureRecognizer()
|
'https://example.com/privacy');
|
||||||
..onTap = () {
|
},
|
||||||
loginBloc.launchURL(
|
|
||||||
'https://example.com/privacy');
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -454,49 +367,35 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 20.0),
|
const SizedBox(height: 20.0),
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment:
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
CrossAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: size.width * 0.2,
|
width: size.width * 0.2,
|
||||||
child: DefaultButton(
|
child: DefaultButton(
|
||||||
enabled:
|
enabled: loginBloc.checkValidate,
|
||||||
loginBloc.checkValidate,
|
|
||||||
child: Text('Sign in',
|
child: Text('Sign in',
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.labelLarge!
|
.labelLarge!
|
||||||
.copyWith(
|
.copyWith(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: loginBloc
|
color: loginBloc.checkValidate
|
||||||
.checkValidate
|
? ColorsManager.whiteColors
|
||||||
? ColorsManager
|
: ColorsManager.whiteColors
|
||||||
.whiteColors
|
.withOpacity(0.2),
|
||||||
: ColorsManager
|
|
||||||
.whiteColors
|
|
||||||
.withOpacity(
|
|
||||||
0.2),
|
|
||||||
)),
|
)),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (loginBloc.loginFormKey
|
if (loginBloc.loginFormKey.currentState!
|
||||||
.currentState!
|
|
||||||
.validate()) {
|
.validate()) {
|
||||||
loginBloc
|
loginBloc.add(LoginButtonPressed(
|
||||||
.add(LoginButtonPressed(
|
regionUuid: loginBloc.regionUuid,
|
||||||
regionUuid:
|
username: loginBloc.loginEmailController.text,
|
||||||
loginBloc.regionUuid,
|
password:
|
||||||
username: loginBloc
|
loginBloc.loginPasswordController.text,
|
||||||
.loginEmailController
|
|
||||||
.text,
|
|
||||||
password: loginBloc
|
|
||||||
.loginPasswordController
|
|
||||||
.text,
|
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
loginBloc.add(
|
loginBloc.add(ChangeValidateEvent());
|
||||||
ChangeValidateEvent());
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -505,10 +404,8 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 15.0),
|
const SizedBox(height: 15.0),
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment:
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
CrossAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -533,8 +430,7 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (state is AuthLoading)
|
if (state is AuthLoading) const Center(child: CircularProgressIndicator())
|
||||||
const Center(child: CircularProgressIndicator())
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ Future<void> showCustomDialog({
|
|||||||
required String message,
|
required String message,
|
||||||
String? title,
|
String? title,
|
||||||
String? iconPath,
|
String? iconPath,
|
||||||
|
Widget? widget,
|
||||||
double? dialogHeight,
|
double? dialogHeight,
|
||||||
double? iconHeight,
|
double? iconHeight,
|
||||||
double? iconWidth,
|
double? iconWidth,
|
||||||
@ -54,6 +55,8 @@ Future<void> showCustomDialog({
|
|||||||
textAlign: TextAlign.center,
|
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(bool?)? selectAll;
|
||||||
final void Function(int, bool, dynamic)? onRowSelected;
|
final void Function(int, bool, dynamic)? onRowSelected;
|
||||||
final List<String>? initialSelectedIds;
|
final List<String>? initialSelectedIds;
|
||||||
|
|
||||||
const DynamicTable({
|
const DynamicTable({
|
||||||
super.key,
|
super.key,
|
||||||
required this.headers,
|
required this.headers,
|
||||||
@ -66,14 +65,11 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
decoration: widget.headerDecoration ??
|
decoration: widget.headerDecoration ?? BoxDecoration(color: Colors.grey[200]),
|
||||||
BoxDecoration(color: Colors.grey[200]),
|
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
if (widget.withCheckBox) _buildSelectAllCheckbox(),
|
if (widget.withCheckBox) _buildSelectAllCheckbox(),
|
||||||
...widget.headers
|
...widget.headers.map((header) => _buildTableHeaderCell(header)).toList(),
|
||||||
.map((header) => _buildTableHeaderCell(header))
|
|
||||||
.toList(),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -97,8 +93,7 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodySmall!
|
.bodySmall!
|
||||||
.copyWith(
|
.copyWith(color: ColorsManager.grayColor),
|
||||||
color: ColorsManager.grayColor),
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -118,12 +113,10 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
if (widget.withCheckBox)
|
if (widget.withCheckBox)
|
||||||
_buildRowCheckbox(
|
_buildRowCheckbox(index, widget.size.height * 0.10),
|
||||||
index, widget.size.height * 0.10),
|
|
||||||
...row
|
...row
|
||||||
.map((cell) => _buildTableCell(
|
.map((cell) =>
|
||||||
cell.toString(),
|
_buildTableCell(cell.toString(), widget.size.height * 0.10))
|
||||||
widget.size.height * 0.10))
|
|
||||||
.toList(),
|
.toList(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -211,6 +204,27 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
batteryLevel = double.tryParse(content.replaceAll('%', '').trim());
|
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(
|
return Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
height: size,
|
height: size,
|
||||||
@ -227,16 +241,11 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
content,
|
content,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: batteryLevel != null && batteryLevel < 20
|
color: batteryLevel != null && batteryLevel < 20
|
||||||
? ColorsManager.red // Red color for low battery
|
? ColorsManager.red
|
||||||
: content == 'Online'
|
: statusColor, // Use the passed color or default to black
|
||||||
? ColorsManager.green // Green color for Online
|
fontSize: 10,
|
||||||
: content == 'Offline'
|
fontWeight: FontWeight.w400),
|
||||||
? ColorsManager.red // Red color for Offline
|
|
||||||
: Colors.black,
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -36,10 +36,7 @@ class DateTimeWebWidget extends StatelessWidget {
|
|||||||
if (isRequired)
|
if (isRequired)
|
||||||
Text(
|
Text(
|
||||||
'* ',
|
'* ',
|
||||||
style: Theme.of(context)
|
style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: Colors.red),
|
||||||
.textTheme
|
|
||||||
.bodyMedium!
|
|
||||||
.copyWith(color: Colors.red),
|
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
@ -55,8 +52,7 @@ class DateTimeWebWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
height: size.height * 0.055,
|
height: size.height * 0.055,
|
||||||
padding:
|
padding: const EdgeInsets.only(top: 10, bottom: 10, right: 30, left: 10),
|
||||||
const EdgeInsets.only(top: 10, bottom: 10, right: 30, left: 10),
|
|
||||||
decoration: containerDecoration,
|
decoration: containerDecoration,
|
||||||
child: FittedBox(
|
child: FittedBox(
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -69,13 +65,10 @@ class DateTimeWebWidget extends StatelessWidget {
|
|||||||
child: FittedBox(
|
child: FittedBox(
|
||||||
child: Text(
|
child: Text(
|
||||||
firstString,
|
firstString,
|
||||||
style: Theme.of(context)
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
.textTheme
|
color: ColorsManager.grayColor,
|
||||||
.bodySmall!
|
fontSize: 12,
|
||||||
.copyWith(
|
fontWeight: FontWeight.w400),
|
||||||
color: ColorsManager.grayColor,
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: FontWeight.w400),
|
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
@ -90,13 +83,10 @@ class DateTimeWebWidget extends StatelessWidget {
|
|||||||
child: FittedBox(
|
child: FittedBox(
|
||||||
child: Text(
|
child: Text(
|
||||||
secondString,
|
secondString,
|
||||||
style: Theme.of(context)
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
.textTheme
|
color: ColorsManager.grayColor,
|
||||||
.bodySmall!
|
fontSize: 12,
|
||||||
.copyWith(
|
fontWeight: FontWeight.w400),
|
||||||
color: ColorsManager.grayColor,
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: FontWeight.w400),
|
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
const SizedBox(
|
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_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:graphview/GraphView.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/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_event.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_state.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/pages/home/home_model/home_item_model.dart';
|
||||||
import 'package:syncrow_web/services/home_api.dart';
|
import 'package:syncrow_web/services/home_api.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||||
|
|
||||||
class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||||
final Graph graph = Graph()..isTree = true;
|
final Graph graph = Graph()..isTree = true;
|
||||||
@ -43,8 +41,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
|
|
||||||
Future fetchUserInfo() async {
|
Future fetchUserInfo() async {
|
||||||
try {
|
try {
|
||||||
var uuid =
|
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||||
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
|
||||||
user = await HomeApi().fetchUserInfo(uuid);
|
user = await HomeApi().fetchUserInfo(uuid);
|
||||||
emit(HomeUserInfoLoaded(user!)); // Emit state after fetching user info
|
emit(HomeUserInfoLoaded(user!)); // Emit state after fetching user info
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -58,9 +55,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
icon: Assets.accessIcon,
|
icon: Assets.accessIcon,
|
||||||
active: true,
|
active: true,
|
||||||
onPress: (context) {
|
onPress: (context) {
|
||||||
Navigator.of(context).push(
|
context.go(RoutesConst.accessManagementPage);
|
||||||
MaterialPageRoute(builder: (context) => AccessManagementPage()),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
color: null,
|
color: null,
|
||||||
),
|
),
|
||||||
@ -76,9 +71,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
icon: Assets.devicesIcon,
|
icon: Assets.devicesIcon,
|
||||||
active: true,
|
active: true,
|
||||||
onPress: (context) {
|
onPress: (context) {
|
||||||
Navigator.of(context).push(
|
context.go(RoutesConst.deviceManagementPage);
|
||||||
MaterialPageRoute(builder: (context) => const DeviceManagementPage()),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
color: ColorsManager.primaryColor,
|
color: ColorsManager.primaryColor,
|
||||||
),
|
),
|
||||||
|
@ -24,13 +24,19 @@ class HomeCard extends StatelessWidget {
|
|||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.only(left: 10, right: 10, bottom: 10),
|
padding: const EdgeInsets.only(left: 10, right: 10, bottom: 10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color:
|
color: index == 0 && active
|
||||||
// evenNumbers && active
|
? ColorsManager.blue1.withOpacity(0.9)
|
||||||
// ? ColorsManager.blueColor.withOpacity(0.8)
|
: index == 1 && active
|
||||||
// :
|
? ColorsManager.blue2.withOpacity(0.9)
|
||||||
(active
|
: index == 2 && active
|
||||||
? ColorsManager.blueColor
|
? ColorsManager.blue3
|
||||||
: ColorsManager.blueColor.withOpacity(0.2)),
|
: 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),
|
borderRadius: BorderRadius.circular(30),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -8,7 +8,6 @@ class HomePage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveLayout(
|
return ResponsiveLayout(desktopBody: HomeWebPage(), mobileBody: HomeMobilePage());
|
||||||
desktopBody: HomeWebPage(), mobileBody: HomeMobilePage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,11 @@ class HomeWebPage extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Size size = MediaQuery.of(context).size;
|
Size size = MediaQuery.of(context).size;
|
||||||
return WebScaffold(
|
return PopScope(
|
||||||
|
canPop: false,
|
||||||
|
onPopInvoked: (didPop) => false,
|
||||||
|
child:
|
||||||
|
WebScaffold(
|
||||||
enableMenuSideba: false,
|
enableMenuSideba: false,
|
||||||
appBarTitle: Row(
|
appBarTitle: Row(
|
||||||
children: [
|
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 'dart:math';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:intl/intl.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_event.dart';
|
||||||
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_state.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/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/pages/visitor_password/model/schedule_model.dart';
|
||||||
import 'package:syncrow_web/services/access_mang_api.dart';
|
import 'package:syncrow_web/services/access_mang_api.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||||
|
|
||||||
class VisitorPasswordBloc
|
class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordState> {
|
||||||
extends Bloc<VisitorPasswordEvent, VisitorPasswordState> {
|
|
||||||
VisitorPasswordBloc() : super(VisitorPasswordInitial()) {
|
VisitorPasswordBloc() : super(VisitorPasswordInitial()) {
|
||||||
on<SelectUsageFrequency>(selectUsageFrequency);
|
on<SelectUsageFrequency>(selectUsageFrequency);
|
||||||
on<FetchDevice>(_onFetchDevice);
|
on<FetchDevice>(_onFetchDevice);
|
||||||
@ -37,8 +38,7 @@ class VisitorPasswordBloc
|
|||||||
final TextEditingController deviceNameController = TextEditingController();
|
final TextEditingController deviceNameController = TextEditingController();
|
||||||
final TextEditingController deviceIdController = TextEditingController();
|
final TextEditingController deviceIdController = TextEditingController();
|
||||||
final TextEditingController unitNameController = TextEditingController();
|
final TextEditingController unitNameController = TextEditingController();
|
||||||
final TextEditingController virtualAddressController =
|
final TextEditingController virtualAddressController = TextEditingController();
|
||||||
TextEditingController();
|
|
||||||
List<String> selectedDevices = [];
|
List<String> selectedDevices = [];
|
||||||
|
|
||||||
List<DeviceModel> data = [];
|
List<DeviceModel> data = [];
|
||||||
@ -62,15 +62,13 @@ class VisitorPasswordBloc
|
|||||||
|
|
||||||
String startTimeAccess = 'Start Time';
|
String startTimeAccess = 'Start Time';
|
||||||
String endTimeAccess = 'End Time';
|
String endTimeAccess = 'End Time';
|
||||||
|
PasswordStatus? passwordStatus;
|
||||||
selectAccessType(
|
selectAccessType(SelectPasswordType event, Emitter<VisitorPasswordState> emit) {
|
||||||
SelectPasswordType event, Emitter<VisitorPasswordState> emit) {
|
|
||||||
accessTypeSelected = event.type;
|
accessTypeSelected = event.type;
|
||||||
emit(PasswordTypeSelected(event.type));
|
emit(PasswordTypeSelected(event.type));
|
||||||
}
|
}
|
||||||
|
|
||||||
selectUsageFrequency(
|
selectUsageFrequency(SelectUsageFrequency event, Emitter<VisitorPasswordState> emit) {
|
||||||
SelectUsageFrequency event, Emitter<VisitorPasswordState> emit) {
|
|
||||||
usageFrequencySelected = event.usageType;
|
usageFrequencySelected = event.usageType;
|
||||||
emit(UsageFrequencySelected(event.usageType));
|
emit(UsageFrequencySelected(event.usageType));
|
||||||
}
|
}
|
||||||
@ -117,12 +115,10 @@ class VisitorPasswordBloc
|
|||||||
timePicked.minute,
|
timePicked.minute,
|
||||||
);
|
);
|
||||||
|
|
||||||
final selectedTimestamp =
|
final selectedTimestamp = selectedDateTime.millisecondsSinceEpoch ~/ 1000;
|
||||||
selectedDateTime.millisecondsSinceEpoch ~/ 1000;
|
|
||||||
|
|
||||||
if (event.isStart) {
|
if (event.isStart) {
|
||||||
if (expirationTimeTimeStamp != null &&
|
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
|
||||||
selectedTimestamp > expirationTimeTimeStamp!) {
|
|
||||||
CustomSnackBar.displaySnackBar(
|
CustomSnackBar.displaySnackBar(
|
||||||
'Effective Time cannot be later than Expiration Time.',
|
'Effective Time cannot be later than Expiration Time.',
|
||||||
);
|
);
|
||||||
@ -131,8 +127,7 @@ class VisitorPasswordBloc
|
|||||||
effectiveTimeTimeStamp = selectedTimestamp;
|
effectiveTimeTimeStamp = selectedTimestamp;
|
||||||
startTimeAccess = selectedDateTime.toString().split('.').first;
|
startTimeAccess = selectedDateTime.toString().split('.').first;
|
||||||
} else {
|
} else {
|
||||||
if (effectiveTimeTimeStamp != null &&
|
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
|
||||||
selectedTimestamp < effectiveTimeTimeStamp!) {
|
|
||||||
CustomSnackBar.displaySnackBar(
|
CustomSnackBar.displaySnackBar(
|
||||||
'Expiration Time cannot be earlier than Effective Time.',
|
'Expiration Time cannot be earlier than Effective Time.',
|
||||||
);
|
);
|
||||||
@ -147,8 +142,7 @@ class VisitorPasswordBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool toggleRepeat(
|
bool toggleRepeat(ToggleRepeatEvent event, Emitter<VisitorPasswordState> emit) {
|
||||||
ToggleRepeatEvent event, Emitter<VisitorPasswordState> emit) {
|
|
||||||
emit(LoadingInitialState());
|
emit(LoadingInitialState());
|
||||||
repeat = !repeat;
|
repeat = !repeat;
|
||||||
emit(IsRepeatState(repeat: repeat));
|
emit(IsRepeatState(repeat: repeat));
|
||||||
@ -180,8 +174,7 @@ class VisitorPasswordBloc
|
|||||||
emit(ChangeTimeState());
|
emit(ChangeTimeState());
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchDevice(
|
Future<void> _onFetchDevice(FetchDevice event, Emitter<VisitorPasswordState> emit) async {
|
||||||
FetchDevice event, Emitter<VisitorPasswordState> emit) async {
|
|
||||||
try {
|
try {
|
||||||
emit(DeviceLoaded());
|
emit(DeviceLoaded());
|
||||||
data = await AccessMangApi().fetchDevices();
|
data = await AccessMangApi().fetchDevices();
|
||||||
@ -192,48 +185,43 @@ class VisitorPasswordBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
//online password
|
//online password
|
||||||
Future<void> postOnlineOneTimePassword(OnlineOneTimePasswordEvent event,
|
Future<void> postOnlineOneTimePassword(
|
||||||
Emitter<VisitorPasswordState> emit) async {
|
OnlineOneTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
|
||||||
try {
|
try {
|
||||||
emit(LoadingInitialState());
|
emit(LoadingInitialState());
|
||||||
generate7DigitNumber();
|
generate7DigitNumber();
|
||||||
bool res = await AccessMangApi().postOnlineOneTime(
|
var res = await AccessMangApi().postOnlineOneTime(
|
||||||
email: event.email,
|
email: event.email,
|
||||||
password: passwordController,
|
password: passwordController,
|
||||||
devicesUuid: selectedDevices,
|
devicesUuid: selectedDevices,
|
||||||
passwordName: event.passwordName,
|
passwordName: event.passwordName,
|
||||||
effectiveTime: effectiveTimeTimeStamp.toString(),
|
effectiveTime: effectiveTimeTimeStamp.toString(),
|
||||||
invalidTime: expirationTimeTimeStamp.toString());
|
invalidTime: expirationTimeTimeStamp.toString());
|
||||||
if (res == true) {
|
if (res['statusCode'] == 201) {
|
||||||
|
passwordStatus = PasswordStatus.fromJson(res['data']);
|
||||||
emit(SuccessState());
|
emit(SuccessState());
|
||||||
} else {
|
|
||||||
throw Exception('Failed to create password');
|
|
||||||
}
|
}
|
||||||
emit(TableLoaded(data));
|
emit(TableLoaded(data));
|
||||||
} catch (e) {
|
} on DioException catch (e) {
|
||||||
emit(FailedState(e.toString()));
|
final errorData = e.response!.data;
|
||||||
Navigator.pop(event.context!);
|
String errorMessage = errorData['message'];
|
||||||
stateDialog(
|
print('errorMessage==$errorData');
|
||||||
context: event.context!,
|
emit(FailedState(errorMessage.toString()));
|
||||||
message: e.toString(),
|
|
||||||
title: 'Something Wrong');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> postOnlineMultipleTimePassword(
|
Future<void> postOnlineMultipleTimePassword(
|
||||||
OnlineMultipleTimePasswordEvent event,
|
OnlineMultipleTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
|
||||||
Emitter<VisitorPasswordState> emit) async {
|
|
||||||
try {
|
try {
|
||||||
emit(LoadingInitialState());
|
emit(LoadingInitialState());
|
||||||
|
|
||||||
await generate7DigitNumber();
|
await generate7DigitNumber();
|
||||||
bool res = await AccessMangApi().postOnlineMultipleTime(
|
var res = await AccessMangApi().postOnlineMultipleTime(
|
||||||
scheduleList: [
|
scheduleList: [
|
||||||
if (repeat)
|
if (repeat)
|
||||||
Schedule(
|
Schedule(
|
||||||
effectiveTime: getTimeFromDateTimeString(expirationTime),
|
effectiveTime: getTimeFromDateTimeString(expirationTime),
|
||||||
invalidTime:
|
invalidTime: getTimeFromDateTimeString(effectiveTime).toString(),
|
||||||
getTimeFromDateTimeString(effectiveTime).toString(),
|
|
||||||
workingDay: selectedDays,
|
workingDay: selectedDays,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -243,79 +231,66 @@ class VisitorPasswordBloc
|
|||||||
email: event.email,
|
email: event.email,
|
||||||
devicesUuid: selectedDevices,
|
devicesUuid: selectedDevices,
|
||||||
passwordName: event.passwordName);
|
passwordName: event.passwordName);
|
||||||
if (res == true) {
|
if (res['statusCode'] == 201) {
|
||||||
|
passwordStatus = PasswordStatus.fromJson(res['data']);
|
||||||
emit(SuccessState());
|
emit(SuccessState());
|
||||||
} else {
|
|
||||||
throw Exception('Failed to create password');
|
|
||||||
}
|
}
|
||||||
emit(TableLoaded(data));
|
emit(TableLoaded(data));
|
||||||
} catch (e) {
|
} on DioException catch (e) {
|
||||||
emit(FailedState(e.toString()));
|
final errorData = e.response!.data;
|
||||||
Navigator.pop(event.context!);
|
String errorMessage = errorData['message'];
|
||||||
stateDialog(
|
print('errorMessage==$errorData');
|
||||||
context: event.context!,
|
emit(FailedState(errorMessage.toString()));
|
||||||
message: e.toString(),
|
|
||||||
title: 'Something Wrong');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//offline password
|
//offline password
|
||||||
Future<void> postOfflineOneTimePassword(OfflineOneTimePasswordEvent event,
|
Future<void> postOfflineOneTimePassword(
|
||||||
Emitter<VisitorPasswordState> emit) async {
|
OfflineOneTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
|
||||||
try {
|
try {
|
||||||
emit(LoadingInitialState());
|
emit(LoadingInitialState());
|
||||||
await generate7DigitNumber();
|
await generate7DigitNumber();
|
||||||
bool res = await AccessMangApi().postOffLineOneTime(
|
var res = await AccessMangApi().postOffLineOneTime(
|
||||||
email: event.email,
|
email: event.email, devicesUuid: selectedDevices, passwordName: event.passwordName);
|
||||||
devicesUuid: selectedDevices,
|
if (res['statusCode'] == 201) {
|
||||||
passwordName: event.passwordName);
|
passwordStatus = PasswordStatus.fromJson(res['data']);
|
||||||
if (res == true) {
|
|
||||||
emit(SuccessState());
|
emit(SuccessState());
|
||||||
} else {
|
|
||||||
throw Exception('Failed to create password');
|
|
||||||
}
|
}
|
||||||
emit(TableLoaded(data));
|
emit(TableLoaded(data));
|
||||||
} catch (e) {
|
} on DioException catch (e) {
|
||||||
emit(FailedState(e.toString()));
|
final errorData = e.response!.data;
|
||||||
Navigator.pop(event.context!);
|
String errorMessage = errorData['message'];
|
||||||
stateDialog(
|
print('errorMessage==$errorData');
|
||||||
context: event.context!,
|
emit(FailedState(errorMessage.toString()));
|
||||||
message: e.toString(),
|
|
||||||
title: 'Something Wrong');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> postOfflineMultipleTimePassword(
|
Future<void> postOfflineMultipleTimePassword(
|
||||||
OfflineMultipleTimePasswordEvent event,
|
OfflineMultipleTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
|
||||||
Emitter<VisitorPasswordState> emit) async {
|
|
||||||
try {
|
try {
|
||||||
emit(LoadingInitialState());
|
emit(LoadingInitialState());
|
||||||
await generate7DigitNumber();
|
await generate7DigitNumber();
|
||||||
bool res = await AccessMangApi().postOffLineMultipleTime(
|
var res = await AccessMangApi().postOffLineMultipleTime(
|
||||||
email: event.email,
|
email: event.email,
|
||||||
devicesUuid: selectedDevices,
|
devicesUuid: selectedDevices,
|
||||||
passwordName: event.passwordName,
|
passwordName: event.passwordName,
|
||||||
invalidTime: expirationTimeTimeStamp.toString(),
|
invalidTime: expirationTimeTimeStamp.toString(),
|
||||||
effectiveTime: effectiveTimeTimeStamp.toString(),
|
effectiveTime: effectiveTimeTimeStamp.toString(),
|
||||||
);
|
);
|
||||||
if (res == true) {
|
if (res['statusCode'] == 201) {
|
||||||
|
passwordStatus = PasswordStatus.fromJson(res['data']);
|
||||||
emit(SuccessState());
|
emit(SuccessState());
|
||||||
} else {
|
|
||||||
throw Exception('Failed to create password');
|
|
||||||
}
|
}
|
||||||
emit(TableLoaded(data));
|
emit(TableLoaded(data));
|
||||||
} catch (e) {
|
} on DioException catch (e) {
|
||||||
emit(FailedState(e.toString()));
|
final errorData = e.response!.data;
|
||||||
Navigator.pop(event.context!);
|
String errorMessage = errorData['message'];
|
||||||
stateDialog(
|
print('errorMessage==$errorData');
|
||||||
context: event.context!,
|
emit(FailedState(errorMessage.toString()));
|
||||||
message: e.toString(),
|
|
||||||
title: 'Something Wrong');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void selectDevice(
|
void selectDevice(SelectDeviceEvent event, Emitter<VisitorPasswordState> emit) {
|
||||||
SelectDeviceEvent event, Emitter<VisitorPasswordState> emit) {
|
|
||||||
if (selectedDeviceIds.contains(event.deviceId)) {
|
if (selectedDeviceIds.contains(event.deviceId)) {
|
||||||
selectedDeviceIds.remove(event.deviceId);
|
selectedDeviceIds.remove(event.deviceId);
|
||||||
} else {
|
} else {
|
||||||
@ -358,8 +333,7 @@ class VisitorPasswordBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<VisitorPasswordState> mapEventToState(
|
Stream<VisitorPasswordState> mapEventToState(VisitorPasswordEvent event) async* {
|
||||||
VisitorPasswordEvent event) async* {
|
|
||||||
if (event is FetchDevice) {
|
if (event is FetchDevice) {
|
||||||
} else if (event is UpdateFilteredDevicesEvent) {
|
} else if (event is UpdateFilteredDevicesEvent) {
|
||||||
yield TableLoaded(event.filteredData);
|
yield TableLoaded(event.filteredData);
|
||||||
@ -407,27 +381,20 @@ class VisitorPasswordBloc
|
|||||||
).millisecondsSinceEpoch ~/
|
).millisecondsSinceEpoch ~/
|
||||||
1000; // Divide by 1000 to remove milliseconds
|
1000; // Divide by 1000 to remove milliseconds
|
||||||
if (event.isEffective) {
|
if (event.isEffective) {
|
||||||
if (expirationTimeTimeStamp != null &&
|
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
|
||||||
selectedTimestamp > expirationTimeTimeStamp!) {
|
CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.');
|
||||||
CustomSnackBar.displaySnackBar(
|
|
||||||
'Effective Time cannot be later than Expiration Time.');
|
|
||||||
} else {
|
} else {
|
||||||
effectiveTime = selectedDateTime
|
effectiveTime =
|
||||||
.toString()
|
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
|
||||||
.split('.')
|
|
||||||
.first; // Remove seconds and milliseconds
|
|
||||||
effectiveTimeTimeStamp = selectedTimestamp;
|
effectiveTimeTimeStamp = selectedTimestamp;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (effectiveTimeTimeStamp != null &&
|
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
|
||||||
selectedTimestamp < effectiveTimeTimeStamp!) {
|
|
||||||
CustomSnackBar.displaySnackBar(
|
CustomSnackBar.displaySnackBar(
|
||||||
'Expiration Time cannot be earlier than Effective Time.');
|
'Expiration Time cannot be earlier than Effective Time.');
|
||||||
} else {
|
} else {
|
||||||
expirationTime = selectedDateTime
|
expirationTime =
|
||||||
.toString()
|
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
|
||||||
.split('.')
|
|
||||||
.first; // Remove seconds and milliseconds
|
|
||||||
expirationTimeTimeStamp = selectedTimestamp;
|
expirationTimeTimeStamp = selectedTimestamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -468,23 +435,26 @@ class VisitorPasswordBloc
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> stateDialog({
|
Future stateDialog({
|
||||||
BuildContext? context,
|
BuildContext? context,
|
||||||
String? message,
|
String? message,
|
||||||
String? title,
|
String? title,
|
||||||
dynamic actions,
|
dynamic actions,
|
||||||
|
Widget? widgeta,
|
||||||
}) {
|
}) {
|
||||||
return showCustomDialog(
|
return showCustomDialog(
|
||||||
|
barrierDismissible: false,
|
||||||
context: context!,
|
context: context!,
|
||||||
message: message!,
|
message: message!,
|
||||||
iconPath: Assets.deviceNoteIcon,
|
iconPath: Assets.deviceNoteIcon,
|
||||||
title: title,
|
title: title,
|
||||||
dialogHeight: 150,
|
widget: widgeta,
|
||||||
|
dialogHeight: MediaQuery.of(context).size.height * 0.3,
|
||||||
actions: actions ??
|
actions: actions ??
|
||||||
<Widget>[
|
<Widget>[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop(true);
|
||||||
},
|
},
|
||||||
child: const Text('OK'),
|
child: const Text('OK'),
|
||||||
),
|
),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
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/enum/device_types.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||||
|
|
||||||
class DeviceModel {
|
class DeviceModel {
|
||||||
dynamic productUuid;
|
dynamic productUuid;
|
||||||
@ -54,8 +54,7 @@ class DeviceModel {
|
|||||||
|
|
||||||
if (type == DeviceType.LightBulb) {
|
if (type == DeviceType.LightBulb) {
|
||||||
tempIcon = Assets.lightBulb;
|
tempIcon = Assets.lightBulb;
|
||||||
} else if (type == DeviceType.CeilingSensor ||
|
} else if (type == DeviceType.CeilingSensor || type == DeviceType.WallSensor) {
|
||||||
type == DeviceType.WallSensor) {
|
|
||||||
tempIcon = Assets.sensors;
|
tempIcon = Assets.sensors;
|
||||||
} else if (type == DeviceType.AC) {
|
} else if (type == DeviceType.AC) {
|
||||||
tempIcon = Assets.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/pages/visitor_password/bloc/visitor_password_state.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.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';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class AddDeviceDialog extends StatelessWidget {
|
class AddDeviceDialog extends StatelessWidget {
|
||||||
|
@ -20,21 +20,75 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Size size = MediaQuery.of(context).size;
|
Size size = MediaQuery.of(context).size;
|
||||||
var text = Theme.of(context)
|
var text = Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.black, fontSize: 13);
|
||||||
.textTheme
|
|
||||||
.bodySmall!
|
|
||||||
.copyWith(color: Colors.black, fontSize: 13);
|
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => VisitorPasswordBloc(),
|
create: (context) => VisitorPasswordBloc(),
|
||||||
child: BlocListener<VisitorPasswordBloc, VisitorPasswordState>(
|
child: BlocListener<VisitorPasswordBloc, VisitorPasswordState>(
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
|
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
|
||||||
if (state is SuccessState) {
|
if (state is SuccessState) {
|
||||||
visitorBloc.stateDialog(
|
visitorBloc
|
||||||
context: context,
|
.stateDialog(
|
||||||
message: 'Password Created Successfully',
|
context: context,
|
||||||
title: 'Send Success',
|
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) {
|
} else if (state is FailedState) {
|
||||||
visitorBloc.stateDialog(
|
visitorBloc.stateDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@ -46,16 +100,15 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
child: BlocBuilder<VisitorPasswordBloc, VisitorPasswordState>(
|
child: BlocBuilder<VisitorPasswordBloc, VisitorPasswordState>(
|
||||||
builder: (BuildContext context, VisitorPasswordState state) {
|
builder: (BuildContext context, VisitorPasswordState state) {
|
||||||
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
|
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
|
||||||
bool isRepeat =
|
bool isRepeat = state is IsRepeatState ? state.repeat : visitorBloc.repeat;
|
||||||
state is IsRepeatState ? state.repeat : visitorBloc.repeat;
|
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
title: Text(
|
title: Text(
|
||||||
'Create visitor password',
|
'Create visitor password',
|
||||||
style: Theme.of(context).textTheme.headlineLarge!.copyWith(
|
style: Theme.of(context)
|
||||||
fontWeight: FontWeight.w400,
|
.textTheme
|
||||||
fontSize: 24,
|
.headlineLarge!
|
||||||
color: Colors.black),
|
.copyWith(fontWeight: FontWeight.w400, fontSize: 24, color: Colors.black),
|
||||||
),
|
),
|
||||||
content: state is LoadingInitialState
|
content: state is LoadingInitialState
|
||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
@ -73,8 +126,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
flex: 2,
|
flex: 2,
|
||||||
child: CustomWebTextField(
|
child: CustomWebTextField(
|
||||||
validator: visitorBloc.validate,
|
validator: visitorBloc.validate,
|
||||||
controller:
|
controller: visitorBloc.userNameController,
|
||||||
visitorBloc.userNameController,
|
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
textFieldName: 'Name',
|
textFieldName: 'Name',
|
||||||
description: '',
|
description: '',
|
||||||
@ -116,95 +168,111 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Flexible(
|
Expanded(
|
||||||
child: RadioListTile<String>(
|
flex: 2,
|
||||||
contentPadding: EdgeInsets.zero,
|
child: Row(
|
||||||
title: Text(
|
children: [
|
||||||
'Online Password',
|
SizedBox(
|
||||||
style: text,
|
width: size.width * 0.12,
|
||||||
),
|
child: RadioListTile<String>(
|
||||||
value: 'Online Password',
|
contentPadding: EdgeInsets.zero,
|
||||||
groupValue: (state
|
title: Text(
|
||||||
is PasswordTypeSelected)
|
'Online Password',
|
||||||
? state.selectedType
|
style: text,
|
||||||
: visitorBloc.accessTypeSelected,
|
),
|
||||||
onChanged: (String? value) {
|
value: 'Online Password',
|
||||||
if (value != null) {
|
groupValue: (state is PasswordTypeSelected)
|
||||||
context
|
? state.selectedType
|
||||||
.read<VisitorPasswordBloc>()
|
: visitorBloc.accessTypeSelected,
|
||||||
.add(SelectPasswordType(
|
onChanged: (String? value) {
|
||||||
value));
|
if (value != null) {
|
||||||
}
|
context
|
||||||
},
|
.read<VisitorPasswordBloc>()
|
||||||
),
|
.add(SelectPasswordType(value));
|
||||||
),
|
}
|
||||||
Flexible(
|
},
|
||||||
child: RadioListTile<String>(
|
),
|
||||||
contentPadding: EdgeInsets.zero,
|
),
|
||||||
title: Text('Offline Password',
|
SizedBox(
|
||||||
style: text),
|
width: size.width * 0.12,
|
||||||
value: 'Offline Password',
|
child: RadioListTile<String>(
|
||||||
groupValue: (state
|
contentPadding: EdgeInsets.zero,
|
||||||
is PasswordTypeSelected)
|
title: Text('Offline Password', style: text),
|
||||||
? state.selectedType
|
value: 'Offline Password',
|
||||||
: visitorBloc.accessTypeSelected,
|
groupValue: (state is PasswordTypeSelected)
|
||||||
onChanged: (String? value) {
|
? state.selectedType
|
||||||
if (value != null) {
|
: visitorBloc.accessTypeSelected,
|
||||||
context
|
onChanged: (String? value) {
|
||||||
.read<VisitorPasswordBloc>()
|
if (value != null) {
|
||||||
.add(SelectPasswordType(
|
context
|
||||||
value));
|
.read<VisitorPasswordBloc>()
|
||||||
}
|
.add(SelectPasswordType(value));
|
||||||
},
|
}
|
||||||
),
|
},
|
||||||
),
|
),
|
||||||
Flexible(
|
),
|
||||||
child: RadioListTile<String>(
|
SizedBox(
|
||||||
contentPadding: EdgeInsets.zero,
|
width: size.width * 0.12,
|
||||||
title: Text(
|
child: RadioListTile<String>(
|
||||||
'Dynamic Password',
|
contentPadding: EdgeInsets.zero,
|
||||||
style: text,
|
title: Text(
|
||||||
),
|
'Dynamic Password',
|
||||||
value: 'Dynamic Password',
|
style: text,
|
||||||
groupValue: (state
|
),
|
||||||
is PasswordTypeSelected)
|
value: 'Dynamic Password',
|
||||||
? state.selectedType
|
groupValue: (state is PasswordTypeSelected)
|
||||||
: visitorBloc.accessTypeSelected,
|
? state.selectedType
|
||||||
onChanged: (String? value) {
|
: visitorBloc.accessTypeSelected,
|
||||||
if (value != null) {
|
onChanged: (String? value) {
|
||||||
context
|
if (value != null) {
|
||||||
.read<VisitorPasswordBloc>()
|
context
|
||||||
.add(SelectPasswordType(
|
.read<VisitorPasswordBloc>()
|
||||||
value));
|
.add(SelectPasswordType(value));
|
||||||
visitorBloc
|
visitorBloc.usageFrequencySelected = '';
|
||||||
.usageFrequencySelected = '';
|
}
|
||||||
}
|
},
|
||||||
},
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
const Spacer(
|
||||||
|
flex: 2,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Text(
|
if (visitorBloc.accessTypeSelected == 'Online Password')
|
||||||
'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',
|
Text(
|
||||||
style: Theme.of(context)
|
'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',
|
||||||
.textTheme
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
.bodySmall!
|
fontWeight: FontWeight.w400,
|
||||||
.copyWith(
|
color: ColorsManager.grayColor,
|
||||||
fontWeight: FontWeight.w400,
|
fontSize: 9),
|
||||||
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(
|
const SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
visitorBloc.accessTypeSelected ==
|
visitorBloc.accessTypeSelected == 'Dynamic Password'
|
||||||
'Dynamic Password'
|
|
||||||
? const SizedBox()
|
? const SizedBox()
|
||||||
: Column(
|
: Column(
|
||||||
crossAxisAlignment:
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
@ -223,7 +291,8 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Flexible(
|
SizedBox(
|
||||||
|
width: size.width * 0.12,
|
||||||
child: RadioListTile<String>(
|
child: RadioListTile<String>(
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
title: Text(
|
title: Text(
|
||||||
@ -231,88 +300,113 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
style: text,
|
style: text,
|
||||||
),
|
),
|
||||||
value: 'One-Time',
|
value: 'One-Time',
|
||||||
groupValue: (state
|
groupValue: (state is UsageFrequencySelected)
|
||||||
is UsageFrequencySelected)
|
|
||||||
? state.selectedFrequency
|
? state.selectedFrequency
|
||||||
: visitorBloc
|
: visitorBloc.usageFrequencySelected,
|
||||||
.usageFrequencySelected,
|
|
||||||
onChanged: (String? value) {
|
onChanged: (String? value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
context
|
context
|
||||||
.read<
|
.read<VisitorPasswordBloc>()
|
||||||
VisitorPasswordBloc>()
|
.add(SelectUsageFrequency(value));
|
||||||
.add(
|
|
||||||
SelectUsageFrequency(
|
|
||||||
value));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Flexible(
|
SizedBox(
|
||||||
|
width: size.width * 0.12,
|
||||||
child: RadioListTile<String>(
|
child: RadioListTile<String>(
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
title: Text('Periodic',
|
title: Text('Periodic', style: text),
|
||||||
style: text),
|
|
||||||
value: 'Periodic',
|
value: 'Periodic',
|
||||||
groupValue: (state
|
groupValue: (state is UsageFrequencySelected)
|
||||||
is UsageFrequencySelected)
|
|
||||||
? state.selectedFrequency
|
? state.selectedFrequency
|
||||||
: visitorBloc
|
: visitorBloc.usageFrequencySelected,
|
||||||
.usageFrequencySelected,
|
|
||||||
onChanged: (String? value) {
|
onChanged: (String? value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
context
|
context
|
||||||
.read<
|
.read<VisitorPasswordBloc>()
|
||||||
VisitorPasswordBloc>()
|
.add(SelectUsageFrequency(value));
|
||||||
.add(
|
|
||||||
SelectUsageFrequency(
|
|
||||||
value));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Text(
|
|
||||||
'Within the validity period, each device can be unlocked only once.',
|
//One-Time
|
||||||
style: Theme.of(context)
|
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
|
||||||
.textTheme
|
visitorBloc.accessTypeSelected == 'Online Password')
|
||||||
.bodySmall!
|
Text(
|
||||||
.copyWith(
|
'Within the validity period, each device can be unlocked only once.',
|
||||||
color:
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
ColorsManager.grayColor,
|
color: ColorsManager.grayColor, fontSize: 9),
|
||||||
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(
|
const SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
if ((visitorBloc.usageFrequencySelected !=
|
if ((visitorBloc.usageFrequencySelected != 'One-Time' ||
|
||||||
'One-Time' ||
|
visitorBloc.accessTypeSelected != 'Offline Password') &&
|
||||||
visitorBloc.accessTypeSelected !=
|
|
||||||
'Offline Password') &&
|
|
||||||
(visitorBloc.usageFrequencySelected != ''))
|
(visitorBloc.usageFrequencySelected != ''))
|
||||||
DateTimeWebWidget(
|
DateTimeWebWidget(
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
title: 'Access Period',
|
title: 'Access Period',
|
||||||
size: size,
|
size: size,
|
||||||
endTime: () {
|
endTime: () {
|
||||||
visitorBloc.add(SelectTimeVisitorPassword(
|
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
|
||||||
context: context,
|
visitorBloc.accessTypeSelected == 'Offline Password') {
|
||||||
isStart: false,
|
visitorBloc.add(
|
||||||
isRepeat: false));
|
SelectTimeEvent(context: context, isEffective: false));
|
||||||
|
} else {
|
||||||
|
visitorBloc.add(SelectTimeVisitorPassword(
|
||||||
|
context: context, isStart: false, isRepeat: false));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
startTime: () {
|
startTime: () {
|
||||||
visitorBloc.add(SelectTimeVisitorPassword(
|
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
|
||||||
context: context,
|
visitorBloc.accessTypeSelected == 'Offline Password') {
|
||||||
isStart: true,
|
visitorBloc.add(
|
||||||
isRepeat: false));
|
SelectTimeEvent(context: context, isEffective: true));
|
||||||
|
} else {
|
||||||
|
visitorBloc.add(SelectTimeVisitorPassword(
|
||||||
|
context: context, isStart: true, isRepeat: false));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
firstString:
|
firstString: (visitorBloc.usageFrequencySelected ==
|
||||||
visitorBloc.startTimeAccess.toString(),
|
'Periodic' &&
|
||||||
secondString:
|
visitorBloc.accessTypeSelected == 'Offline Password')
|
||||||
visitorBloc.endTimeAccess.toString(),
|
? visitorBloc.effectiveTime
|
||||||
|
: visitorBloc.startTimeAccess.toString(),
|
||||||
|
secondString: (visitorBloc.usageFrequencySelected ==
|
||||||
|
'Periodic' &&
|
||||||
|
visitorBloc.accessTypeSelected == 'Offline Password')
|
||||||
|
? visitorBloc.expirationTime
|
||||||
|
: visitorBloc.endTimeAccess.toString(),
|
||||||
icon: Assets.calendarIcon),
|
icon: Assets.calendarIcon),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
@ -337,21 +431,16 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Within the validity period, each device can be unlocked only once.',
|
'Within the validity period, each device can be unlocked only once.',
|
||||||
style: Theme.of(context)
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
.textTheme
|
fontWeight: FontWeight.w400,
|
||||||
.bodySmall!
|
color: ColorsManager.grayColor,
|
||||||
.copyWith(
|
fontSize: 9),
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
color: ColorsManager.grayColor,
|
|
||||||
fontSize: 9),
|
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
if (visitorBloc.usageFrequencySelected ==
|
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
|
||||||
'Periodic' &&
|
visitorBloc.accessTypeSelected == 'Online Password')
|
||||||
visitorBloc.accessTypeSelected ==
|
|
||||||
'Online Password')
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 100,
|
width: 100,
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -362,8 +451,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
child: CupertinoSwitch(
|
child: CupertinoSwitch(
|
||||||
value: visitorBloc.repeat,
|
value: visitorBloc.repeat,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
visitorBloc
|
visitorBloc.add(ToggleRepeatEvent());
|
||||||
.add(ToggleRepeatEvent());
|
|
||||||
},
|
},
|
||||||
applyTheme: true,
|
applyTheme: true,
|
||||||
),
|
),
|
||||||
@ -371,13 +459,9 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (visitorBloc.usageFrequencySelected ==
|
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
|
||||||
'Periodic' &&
|
visitorBloc.accessTypeSelected == 'Online Password')
|
||||||
visitorBloc.accessTypeSelected ==
|
isRepeat ? const RepeatWidget() : const SizedBox(),
|
||||||
'Online Password')
|
|
||||||
isRepeat
|
|
||||||
? const RepeatWidget()
|
|
||||||
: const SizedBox(),
|
|
||||||
Container(
|
Container(
|
||||||
decoration: containerDecoration,
|
decoration: containerDecoration,
|
||||||
width: size.width / 9,
|
width: size.width / 9,
|
||||||
@ -388,28 +472,22 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AddDeviceDialog(
|
return AddDeviceDialog(
|
||||||
selectedDeviceIds:
|
selectedDeviceIds: visitorBloc.selectedDevices,
|
||||||
visitorBloc.selectedDevices,
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
).then((listDevice) {
|
).then((listDevice) {
|
||||||
if (listDevice != null) {
|
if (listDevice != null) {
|
||||||
visitorBloc.selectedDevices =
|
visitorBloc.selectedDevices = listDevice;
|
||||||
listDevice;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
child: Text(
|
child: Text(
|
||||||
'+ Add Device',
|
'+ Add Device',
|
||||||
style: Theme.of(context)
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
.textTheme
|
fontWeight: FontWeight.w400,
|
||||||
.bodySmall!
|
color: ColorsManager.whiteColors,
|
||||||
.copyWith(
|
fontSize: 12),
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
color:
|
|
||||||
ColorsManager.whiteColors,
|
|
||||||
fontSize: 12),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -447,15 +525,36 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (visitorBloc.forgetFormKey.currentState!.validate()) {
|
if (visitorBloc.forgetFormKey.currentState!.validate()) {
|
||||||
if (visitorBloc.selectedDevices.isNotEmpty) {
|
if (visitorBloc.selectedDevices.isNotEmpty) {
|
||||||
if (visitorBloc.effectiveTimeTimeStamp != null &&
|
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
|
||||||
visitorBloc.expirationTimeTimeStamp != null) {
|
visitorBloc.accessTypeSelected == 'Offline Password') {
|
||||||
|
setPasswordFunction(context, size, visitorBloc);
|
||||||
|
} else if (visitorBloc.accessTypeSelected == 'Dynamic Password') {
|
||||||
|
print('objectobjectobjectobject');
|
||||||
setPasswordFunction(context, size, visitorBloc);
|
setPasswordFunction(context, size, visitorBloc);
|
||||||
} else {
|
} else {
|
||||||
visitorBloc.stateDialog(
|
if (visitorBloc.effectiveTimeTimeStamp != null &&
|
||||||
context: context,
|
visitorBloc.expirationTimeTimeStamp != null) {
|
||||||
message:
|
if (isRepeat == true) {
|
||||||
'Please select Access Period to continue',
|
if (visitorBloc.expirationTime != 'End Time' &&
|
||||||
title: 'Access Period');
|
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 {
|
} else {
|
||||||
visitorBloc.stateDialog(
|
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,
|
borderRadius: 8,
|
||||||
child: Text(
|
child: Text(
|
||||||
'Ok',
|
'Ok',
|
||||||
@ -501,8 +651,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
height: size.height * 0.25,
|
height: size.height * 0.25,
|
||||||
child: Center(
|
child: Center(
|
||||||
child:
|
child: CircularProgressIndicator(), // Display a loading spinner
|
||||||
CircularProgressIndicator(), // Display a loading spinner
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -526,10 +675,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Set Password',
|
'Set Password',
|
||||||
style: Theme.of(context)
|
style: Theme.of(context).textTheme.headlineLarge!.copyWith(
|
||||||
.textTheme
|
|
||||||
.headlineLarge!
|
|
||||||
.copyWith(
|
|
||||||
fontSize: 30,
|
fontSize: 30,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
@ -578,47 +724,39 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
|
if (visitorBloc.accessTypeSelected == 'Dynamic Password') {
|
||||||
visitorBloc.accessTypeSelected ==
|
} else {
|
||||||
'Online Password') {
|
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
|
||||||
visitorBloc.add(OnlineOneTimePasswordEvent(
|
visitorBloc.accessTypeSelected == 'Online Password') {
|
||||||
context: context,
|
visitorBloc.add(OnlineOneTimePasswordEvent(
|
||||||
passwordName: visitorBloc.userNameController.text,
|
context: context,
|
||||||
email: visitorBloc.emailController.text,
|
passwordName: visitorBloc.userNameController.text,
|
||||||
));
|
email: visitorBloc.emailController.text,
|
||||||
} else if (visitorBloc.usageFrequencySelected ==
|
));
|
||||||
'Periodic' &&
|
} else if (visitorBloc.usageFrequencySelected == 'Periodic' &&
|
||||||
visitorBloc.accessTypeSelected ==
|
visitorBloc.accessTypeSelected == 'Online Password') {
|
||||||
'Online Password') {
|
visitorBloc.add(OnlineMultipleTimePasswordEvent(
|
||||||
visitorBloc.add(OnlineMultipleTimePasswordEvent(
|
passwordName: visitorBloc.userNameController.text,
|
||||||
passwordName: visitorBloc.userNameController.text,
|
email: visitorBloc.emailController.text,
|
||||||
email: visitorBloc.emailController.text,
|
effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(),
|
||||||
effectiveTime:
|
invalidTime: visitorBloc.expirationTimeTimeStamp.toString(),
|
||||||
visitorBloc.effectiveTimeTimeStamp.toString(),
|
));
|
||||||
invalidTime:
|
} else if (visitorBloc.usageFrequencySelected == 'One-Time' &&
|
||||||
visitorBloc.expirationTimeTimeStamp.toString(),
|
visitorBloc.accessTypeSelected == 'Offline Password') {
|
||||||
));
|
visitorBloc.add(OfflineOneTimePasswordEvent(
|
||||||
} else if (visitorBloc.usageFrequencySelected ==
|
context: context,
|
||||||
'One-Time' &&
|
passwordName: visitorBloc.userNameController.text,
|
||||||
visitorBloc.accessTypeSelected ==
|
email: visitorBloc.emailController.text,
|
||||||
'Offline Password') {
|
));
|
||||||
visitorBloc.add(OfflineOneTimePasswordEvent(
|
} else if (visitorBloc.usageFrequencySelected == 'Periodic' &&
|
||||||
context: context,
|
visitorBloc.accessTypeSelected == 'Offline Password') {
|
||||||
passwordName: visitorBloc.userNameController.text,
|
visitorBloc.add(OfflineMultipleTimePasswordEvent(
|
||||||
email: visitorBloc.emailController.text,
|
passwordName: visitorBloc.userNameController.text,
|
||||||
));
|
email: visitorBloc.emailController.text,
|
||||||
} else if (visitorBloc.usageFrequencySelected ==
|
effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(),
|
||||||
'Periodic' &&
|
invalidTime: visitorBloc.expirationTimeTimeStamp.toString(),
|
||||||
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(
|
child: Text(
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/model/password_model.dart';
|
import 'package:syncrow_web/pages/access_management/model/password_model.dart';
|
||||||
import 'package:syncrow_web/pages/visitor_password/model/device_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? email,
|
||||||
String? passwordName,
|
String? passwordName,
|
||||||
String? password,
|
String? password,
|
||||||
String? effectiveTime,
|
String? effectiveTime,
|
||||||
String? invalidTime,
|
String? invalidTime,
|
||||||
List<String>? devicesUuid}) async {
|
List<String>? devicesUuid}) async {
|
||||||
try {
|
final response = await HTTPService().post(
|
||||||
final response = await HTTPService().post(
|
path: ApiEndpoints.sendOnlineOneTime,
|
||||||
path: ApiEndpoints.sendOnlineOneTime,
|
body: jsonEncode({
|
||||||
body: jsonEncode({
|
"email": email,
|
||||||
"email": email,
|
"passwordName": passwordName,
|
||||||
"passwordName": passwordName,
|
"password": password,
|
||||||
"password": password,
|
"devicesUuid": devicesUuid,
|
||||||
"devicesUuid": devicesUuid,
|
"effectiveTime": effectiveTime,
|
||||||
"effectiveTime": effectiveTime,
|
"invalidTime": invalidTime
|
||||||
"invalidTime": invalidTime
|
}),
|
||||||
}),
|
showServerMessage: true,
|
||||||
showServerMessage: true,
|
expectedResponseModel: (json) {
|
||||||
expectedResponseModel: (json) {
|
return json;
|
||||||
if (json['statusCode'].toString() == '201') {
|
},
|
||||||
return true;
|
);
|
||||||
} else {
|
return response;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return response;
|
|
||||||
} on DioException catch (e) {
|
|
||||||
debugPrint('Error: ${e.message}');
|
|
||||||
debugPrint('Error fetching ${e.response!.statusMessage}');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future postOnlineMultipleTime(
|
Future postOnlineMultipleTime(
|
||||||
@ -91,66 +80,41 @@ class AccessMangApi {
|
|||||||
String? passwordName,
|
String? passwordName,
|
||||||
List<Schedule>? scheduleList,
|
List<Schedule>? scheduleList,
|
||||||
List<String>? devicesUuid}) async {
|
List<String>? devicesUuid}) async {
|
||||||
try {
|
Map<String, dynamic> body = {
|
||||||
Map<String, dynamic> body = {
|
"email": email,
|
||||||
"email": email,
|
"devicesUuid": devicesUuid,
|
||||||
"devicesUuid": devicesUuid,
|
"passwordName": passwordName,
|
||||||
"passwordName": passwordName,
|
"password": password,
|
||||||
"password": password,
|
"effectiveTime": effectiveTime,
|
||||||
"effectiveTime": effectiveTime,
|
"invalidTime": invalidTime,
|
||||||
"invalidTime": invalidTime,
|
};
|
||||||
};
|
if (scheduleList != null) {
|
||||||
if (scheduleList != null) {
|
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
final response = await HTTPService().post(
|
||||||
|
path: ApiEndpoints.sendOnlineMultipleTime,
|
||||||
|
body: jsonEncode(body),
|
||||||
|
showServerMessage: true,
|
||||||
|
expectedResponseModel: (json) {
|
||||||
|
return json;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OffLine One Time Password
|
// OffLine One Time Password
|
||||||
|
|
||||||
Future postOffLineOneTime(
|
Future postOffLineOneTime(
|
||||||
{String? email, String? passwordName, List<String>? devicesUuid}) async {
|
{String? email, String? passwordName, List<String>? devicesUuid}) async {
|
||||||
try {
|
final response = await HTTPService().post(
|
||||||
final response = await HTTPService().post(
|
path: ApiEndpoints.sendOffLineOneTime,
|
||||||
path: ApiEndpoints.sendOffLineOneTime,
|
body: jsonEncode({"email": email, "passwordName": passwordName, "devicesUuid": devicesUuid}),
|
||||||
body: jsonEncode({
|
showServerMessage: true,
|
||||||
"email": email,
|
expectedResponseModel: (json) {
|
||||||
"passwordName": passwordName,
|
return json;
|
||||||
"devicesUuid": devicesUuid
|
},
|
||||||
}),
|
);
|
||||||
showServerMessage: true,
|
return response;
|
||||||
expectedResponseModel: (json) {
|
|
||||||
if (json['data']['successOperations'][0]['success'].toString() ==
|
|
||||||
'true') {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return response;
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Error fetching $e');
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future postOffLineMultipleTime(
|
Future postOffLineMultipleTime(
|
||||||
@ -159,29 +123,27 @@ class AccessMangApi {
|
|||||||
String? effectiveTime,
|
String? effectiveTime,
|
||||||
String? invalidTime,
|
String? invalidTime,
|
||||||
List<String>? devicesUuid}) async {
|
List<String>? devicesUuid}) async {
|
||||||
try {
|
print(jsonEncode({
|
||||||
final response = await HTTPService().post(
|
"email": email,
|
||||||
path: ApiEndpoints.sendOffLineOneTime,
|
"devicesUuid": devicesUuid,
|
||||||
body: jsonEncode({
|
"passwordName": passwordName,
|
||||||
"email": email,
|
"effectiveTime": effectiveTime,
|
||||||
"devicesUuid": devicesUuid,
|
"invalidTime": invalidTime,
|
||||||
"passwordName": passwordName,
|
}));
|
||||||
"effectiveTime": effectiveTime,
|
final response = await HTTPService().post(
|
||||||
"invalidTime": invalidTime
|
path: ApiEndpoints.sendOffLineMultipleTime,
|
||||||
}),
|
body: jsonEncode({
|
||||||
showServerMessage: true,
|
"email": email,
|
||||||
expectedResponseModel: (json) {
|
"devicesUuid": devicesUuid,
|
||||||
if (json['data']['successOperations'][0]['success'].toString() ==
|
"passwordName": passwordName,
|
||||||
'true') {
|
"effectiveTime": effectiveTime,
|
||||||
return true;
|
"invalidTime": invalidTime,
|
||||||
} else {
|
}),
|
||||||
return false;
|
showServerMessage: true,
|
||||||
}
|
expectedResponseModel: (json) {
|
||||||
});
|
return json;
|
||||||
return response;
|
},
|
||||||
} catch (e) {
|
);
|
||||||
debugPrint('Error fetching $e');
|
return response;
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,17 +29,17 @@ class AuthenticationAPI {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<int?> sendOtp(
|
static Future<int?> sendOtp({required String email, required String regionUuid}) async {
|
||||||
{required String email, required String regionUuid}) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
path: ApiEndpoints.sendOtp,
|
path: ApiEndpoints.sendOtp,
|
||||||
body: {"email": email, "type": "PASSWORD", "regionUuid": regionUuid},
|
body: {"email": email, "type": "PASSWORD", "regionUuid": regionUuid},
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return 30;
|
return json['data']['cooldown'];
|
||||||
});
|
});
|
||||||
return 30;
|
|
||||||
|
return response;
|
||||||
} on DioException catch (e) {
|
} on DioException catch (e) {
|
||||||
if (e.response != null) {
|
if (e.response != null) {
|
||||||
if (e.response!.statusCode == 400) {
|
if (e.response!.statusCode == 400) {
|
||||||
@ -52,8 +52,7 @@ class AuthenticationAPI {
|
|||||||
return cooldown;
|
return cooldown;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debugPrint(
|
debugPrint('Error: ${e.response!.statusCode} - ${e.response!.statusMessage}');
|
||||||
'Error: ${e.response!.statusCode} - ${e.response!.statusMessage}');
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -66,8 +65,7 @@ class AuthenticationAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future verifyOtp(
|
static Future verifyOtp({required String email, required String otpCode}) async {
|
||||||
{required String email, required String otpCode}) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
path: ApiEndpoints.verifyOtp,
|
path: ApiEndpoints.verifyOtp,
|
||||||
@ -99,9 +97,7 @@ class AuthenticationAPI {
|
|||||||
path: ApiEndpoints.getRegion,
|
path: ApiEndpoints.getRegion,
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return (json as List)
|
return (json as List).map((zone) => RegionModel.fromJson(zone)).toList();
|
||||||
.map((zone) => RegionModel.fromJson(zone))
|
|
||||||
.toList();
|
|
||||||
});
|
});
|
||||||
return response;
|
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 blueColor = Color(0xFF0036E6);
|
||||||
static const Color boxColor = Color(0xFFF5F6F7);
|
static const Color boxColor = Color(0xFFF5F6F7);
|
||||||
static const Color boxDivider = Color(0xFFE0E0E0);
|
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 rightLine = "assets/images/right_line.png";
|
||||||
static const String google = "assets/images/google.svg";
|
static const String google = "assets/images/google.svg";
|
||||||
static const String facebook = "assets/images/facebook.svg";
|
static const String facebook = "assets/images/facebook.svg";
|
||||||
static const String invisiblePassword =
|
static const String invisiblePassword = "assets/images/Password_invisible.svg";
|
||||||
"assets/images/Password_invisible.svg";
|
|
||||||
static const String visiblePassword = "assets/images/Password_visible.svg";
|
static const String visiblePassword = "assets/images/Password_visible.svg";
|
||||||
static const String accessIcon = "assets/images/access_icon.svg";
|
static const String accessIcon = "assets/images/access_icon.svg";
|
||||||
static const String spaseManagementIcon =
|
static const String spaseManagementIcon = "assets/images/spase_management_icon.svg";
|
||||||
"assets/images/spase_management_icon.svg";
|
|
||||||
static const String devicesIcon = "assets/images/devices_icon.svg";
|
static const String devicesIcon = "assets/images/devices_icon.svg";
|
||||||
static const String moveinIcon = "assets/images/movein_icon.svg";
|
static const String moveinIcon = "assets/images/movein_icon.svg";
|
||||||
static const String constructionIcon = "assets/images/construction_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";
|
static const String emptyTable = "assets/images/empty_table.svg";
|
||||||
|
|
||||||
// General assets
|
// General assets
|
||||||
static const String motionlessDetection =
|
static const String motionlessDetection = "assets/icons/motionless_detection.svg";
|
||||||
"assets/icons/motionless_detection.svg";
|
|
||||||
static const String acHeating = "assets/icons/ac_heating.svg";
|
static const String acHeating = "assets/icons/ac_heating.svg";
|
||||||
static const String acPowerOff = "assets/icons/ac_power_off.svg";
|
static const String acPowerOff = "assets/icons/ac_power_off.svg";
|
||||||
static const String acFanMiddle = "assets/icons/ac_fan_middle.svg";
|
static const String acFanMiddle = "assets/icons/ac_fan_middle.svg";
|
||||||
static const String switchAlarmSound = "assets/icons/switch_alarm_sound.svg";
|
static const String switchAlarmSound = "assets/icons/switch_alarm_sound.svg";
|
||||||
static const String resetOff = "assets/icons/reset_off.svg";
|
static const String resetOff = "assets/icons/reset_off.svg";
|
||||||
static const String sensitivityOperationIcon =
|
static const String sensitivityOperationIcon = "assets/icons/sesitivity_operation_icon.svg";
|
||||||
"assets/icons/sesitivity_operation_icon.svg";
|
|
||||||
static const String motionDetection = "assets/icons/motion_detection.svg";
|
static const String motionDetection = "assets/icons/motion_detection.svg";
|
||||||
static const String freezing = "assets/icons/freezing.svg";
|
static const String freezing = "assets/icons/freezing.svg";
|
||||||
static const String indicator = "assets/icons/indicator.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 celsiusDegrees = "assets/icons/celsius_degrees.svg";
|
||||||
static const String masterState = "assets/icons/master_state.svg";
|
static const String masterState = "assets/icons/master_state.svg";
|
||||||
static const String acPower = "assets/icons/ac_power.svg";
|
static const String acPower = "assets/icons/ac_power.svg";
|
||||||
static const String farDetectionFunction =
|
static const String farDetectionFunction = "assets/icons/far_detection_function.svg";
|
||||||
"assets/icons/far_detection_function.svg";
|
|
||||||
static const String nobodyTime = "assets/icons/nobody_time.svg";
|
static const String nobodyTime = "assets/icons/nobody_time.svg";
|
||||||
|
|
||||||
// Automation functions
|
// Automation functions
|
||||||
@ -69,47 +64,33 @@ class Assets {
|
|||||||
"assets/icons/automation_functions/temp_password_unlock.svg";
|
"assets/icons/automation_functions/temp_password_unlock.svg";
|
||||||
static const String doorlockNormalOpen =
|
static const String doorlockNormalOpen =
|
||||||
"assets/icons/automation_functions/doorlock_normal_open.svg";
|
"assets/icons/automation_functions/doorlock_normal_open.svg";
|
||||||
static const String doorbell =
|
static const String doorbell = "assets/icons/automation_functions/doorbell.svg";
|
||||||
"assets/icons/automation_functions/doorbell.svg";
|
|
||||||
static const String remoteUnlockViaApp =
|
static const String remoteUnlockViaApp =
|
||||||
"assets/icons/automation_functions/remote_unlock_via_app.svg";
|
"assets/icons/automation_functions/remote_unlock_via_app.svg";
|
||||||
static const String doubleLock =
|
static const String doubleLock = "assets/icons/automation_functions/double_lock.svg";
|
||||||
"assets/icons/automation_functions/double_lock.svg";
|
static const String selfTestResult = "assets/icons/automation_functions/self_test_result.svg";
|
||||||
static const String selfTestResult =
|
static const String lockAlarm = "assets/icons/automation_functions/lock_alarm.svg";
|
||||||
"assets/icons/automation_functions/self_test_result.svg";
|
static const String presenceState = "assets/icons/automation_functions/presence_state.svg";
|
||||||
static const String lockAlarm =
|
static const String currentTemp = "assets/icons/automation_functions/current_temp.svg";
|
||||||
"assets/icons/automation_functions/lock_alarm.svg";
|
static const String presence = "assets/icons/automation_functions/presence.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 =
|
static const String residualElectricity =
|
||||||
"assets/icons/automation_functions/residual_electricity.svg";
|
"assets/icons/automation_functions/residual_electricity.svg";
|
||||||
static const String hijackAlarm =
|
static const String hijackAlarm = "assets/icons/automation_functions/hijack_alarm.svg";
|
||||||
"assets/icons/automation_functions/hijack_alarm.svg";
|
static const String passwordUnlock = "assets/icons/automation_functions/password_unlock.svg";
|
||||||
static const String passwordUnlock =
|
|
||||||
"assets/icons/automation_functions/password_unlock.svg";
|
|
||||||
static const String remoteUnlockRequest =
|
static const String remoteUnlockRequest =
|
||||||
"assets/icons/automation_functions/remote_unlock_req.svg";
|
"assets/icons/automation_functions/remote_unlock_req.svg";
|
||||||
static const String cardUnlock =
|
static const String cardUnlock = "assets/icons/automation_functions/card_unlock.svg";
|
||||||
"assets/icons/automation_functions/card_unlock.svg";
|
|
||||||
static const String motion = "assets/icons/automation_functions/motion.svg";
|
static const String motion = "assets/icons/automation_functions/motion.svg";
|
||||||
static const String fingerprintUnlock =
|
static const String fingerprintUnlock =
|
||||||
"assets/icons/automation_functions/fingerprint_unlock.svg";
|
"assets/icons/automation_functions/fingerprint_unlock.svg";
|
||||||
|
|
||||||
// Presence Sensor Assets
|
// Presence Sensor Assets
|
||||||
static const String sensorMotionIcon = "assets/icons/sensor_motion_ic.svg";
|
static const String sensorMotionIcon = "assets/icons/sensor_motion_ic.svg";
|
||||||
static const String sensorPresenceIcon =
|
static const String sensorPresenceIcon = "assets/icons/sensor_presence_ic.svg";
|
||||||
"assets/icons/sensor_presence_ic.svg";
|
|
||||||
static const String sensorVacantIcon = "assets/icons/sensor_vacant_ic.svg";
|
static const String sensorVacantIcon = "assets/icons/sensor_vacant_ic.svg";
|
||||||
static const String illuminanceRecordIcon =
|
static const String illuminanceRecordIcon = "assets/icons/illuminance_record_ic.svg";
|
||||||
"assets/icons/illuminance_record_ic.svg";
|
static const String presenceRecordIcon = "assets/icons/presence_record_ic.svg";
|
||||||
static const String presenceRecordIcon =
|
static const String helpDescriptionIcon = "assets/icons/help_description_ic.svg";
|
||||||
"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 lightPulp = "assets/icons/light_pulb.svg";
|
||||||
static const String acDevice = "assets/icons/ac_device.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 dyi = 'assets/icons/dyi.svg';
|
||||||
static const String office = 'assets/icons/office.svg';
|
static const String office = 'assets/icons/office.svg';
|
||||||
static const String parlour = 'assets/icons/parlour.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 =
|
static GlobalKey<ScaffoldMessengerState>? snackbarKey =
|
||||||
GlobalKey<ScaffoldMessengerState>();
|
GlobalKey<ScaffoldMessengerState>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
40
pubspec.lock
40
pubspec.lock
@ -216,6 +216,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.7.0"
|
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:
|
graphview:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -260,18 +268,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: leak_tracker
|
name: leak_tracker
|
||||||
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.0.5"
|
version: "10.0.4"
|
||||||
leak_tracker_flutter_testing:
|
leak_tracker_flutter_testing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: leak_tracker_flutter_testing
|
name: leak_tracker_flutter_testing
|
||||||
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.5"
|
version: "3.0.3"
|
||||||
leak_tracker_testing:
|
leak_tracker_testing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -288,6 +296,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.0"
|
||||||
|
logging:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: logging
|
||||||
|
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -300,18 +316,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.11.1"
|
version: "0.8.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.15.0"
|
version: "1.12.0"
|
||||||
nested:
|
nested:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -521,10 +537,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
|
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.2"
|
version: "0.7.0"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -569,10 +585,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.2.5"
|
version: "14.2.1"
|
||||||
web:
|
web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -44,7 +44,9 @@ dependencies:
|
|||||||
flutter_secure_storage: ^9.2.2
|
flutter_secure_storage: ^9.2.2
|
||||||
shared_preferences: ^2.3.0
|
shared_preferences: ^2.3.0
|
||||||
data_table_2: ^2.5.15
|
data_table_2: ^2.5.15
|
||||||
|
go_router:
|
||||||
intl: ^0.19.0
|
intl: ^0.19.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
Reference in New Issue
Block a user