472 lines
18 KiB
Dart
472 lines
18 KiB
Dart
import 'dart:async';
|
|
import 'dart:io';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:hub/features/backend/index.dart';
|
|
import 'package:hub/features/history/index.dart';
|
|
import 'package:hub/features/home/index.dart';
|
|
import 'package:hub/features/local/index.dart';
|
|
import 'package:hub/features/menu/index.dart';
|
|
import 'package:hub/features/property/index.dart';
|
|
import 'package:hub/features/storage/index.dart';
|
|
import 'package:hub/flutter_flow/flutter_flow_util.dart';
|
|
import 'package:hub/flutter_flow/nav/nav.dart';
|
|
import 'package:hub/pages/delivery_schedule_page/delivery_schedule_widget.dart';
|
|
import 'package:hub/pages/fast_pass_page/fast_pass_page_widget.dart';
|
|
import 'package:hub/pages/forgot_password_page/forgot_password_screen.dart';
|
|
import 'package:hub/pages/liberation_history/liberation_history_widget.dart';
|
|
import 'package:hub/pages/message_history_page/message_history_page_widget.dart';
|
|
import 'package:hub/pages/package_order_page/package_order_page.dart';
|
|
import 'package:hub/pages/people_on_the_property_page/people_on_the_property_page_widget.dart';
|
|
import 'package:hub/pages/pets_on_the_property_page/pets_history_screen.dart';
|
|
import 'package:hub/pages/pets_page/pets_page_widget.dart';
|
|
import 'package:hub/pages/preferences_settings_page/preferences_settings_widget.dart';
|
|
import 'package:hub/pages/provisional_schedule_page/provisional_schedule_widget.dart';
|
|
import 'package:hub/pages/qr_code_page/qr_code_page_widget.dart';
|
|
import 'package:hub/pages/reception_page/reception_page_widget.dart';
|
|
import 'package:hub/pages/register_visitor_page/register_visitor_page_widget.dart';
|
|
import 'package:hub/pages/reservation_page/reservation_page_widget.dart';
|
|
import 'package:hub/pages/residents_on_the_property/residents_on_the_property_screen.dart';
|
|
import 'package:hub/pages/schedule_complete_visit_page/schedule_complete_visit_page_widget.dart';
|
|
import 'package:hub/pages/sign_in_page/sign_in_page_widget.dart';
|
|
import 'package:hub/pages/sign_up_page/sign_up_page_widget.dart';
|
|
import 'package:hub/pages/vehicles_on_the_property/vehicles_on_the_property.dart';
|
|
import 'package:hub/pages/visits_on_the_property/visits_on_the_property_screen.dart';
|
|
import 'package:hub/pages/welcome_page/welcome_page_widget.dart';
|
|
import 'package:hub/shared/utils/dialog_util.dart';
|
|
import 'package:provider/provider.dart';
|
|
export 'package:go_router/go_router.dart';
|
|
|
|
export 'serialization_util.dart';
|
|
|
|
const kTransitionInfoKey = '__transition_info__';
|
|
|
|
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
|
|
|
class AppStateNotifier extends ChangeNotifier {
|
|
AppStateNotifier._();
|
|
|
|
static AppStateNotifier? _instance;
|
|
static AppStateNotifier get instance => _instance ??= AppStateNotifier._();
|
|
|
|
bool showSplashImage = true;
|
|
|
|
void stopShowingSplashImage() {
|
|
showSplashImage = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
GoRouter createRouter(AppStateNotifier appStateNotifier) {
|
|
return GoRouter(
|
|
navigatorKey: navigatorKey,
|
|
initialLocation: '/',
|
|
debugLogDiagnostics: true,
|
|
redirect: (context, state) {
|
|
if (Platform.isIOS) {
|
|
if (state.uri.toString().contains("freaccess://changepass/")) {
|
|
throw Exception('Redirecting to forgotPassword');
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
refreshListenable: appStateNotifier,
|
|
// errorBuilder: (context, state) => appStateNotifier.showSplashImage
|
|
// ? Builder( builder: (context) => Container(color: FlutterFlowTheme.of(context).primary, child: Image.asset( 'assets/images/logo.svg', fit: BoxFit.cover)))
|
|
// : const PeopleOnThePropertyPageWidget(),
|
|
routes: [
|
|
// FFRoute(name: '_initialize', path: '/',builder: (context, _) => appStateNotifier.showSplashImage
|
|
// ? Builder(builder: (context) => Container(color: FlutterFlowTheme.of(context).primary, child: Image.asset('assets/images/favicon.png', fit: BoxFit.cover)))
|
|
// : const OnBoardingPageWidget(),
|
|
// ),
|
|
FFRoute(
|
|
name: '_initialize',
|
|
path: '/',
|
|
builder: (context, _) {
|
|
return FutureBuilder<Widget>(
|
|
future: () async {
|
|
final bool isLogged =
|
|
await StorageHelper().get(SecureStorageKey.isLogged.value) ==
|
|
'true';
|
|
final bool haveLocal =
|
|
await StorageHelper().get(SecureStorageKey.haveLocal.value) ==
|
|
'true';
|
|
final bool haveUserUUID =
|
|
(await StorageHelper().get(ProfileStorageKey.userUUID.key))
|
|
?.isNotEmpty ??
|
|
false;
|
|
final bool haveDevUUID =
|
|
(await StorageHelper().get(ProfileStorageKey.devUUID.key))
|
|
?.isNotEmpty ??
|
|
false;
|
|
|
|
if (isLogged && haveDevUUID && haveUserUUID) {
|
|
return haveLocal
|
|
? MultiBlocProvider(
|
|
providers: [
|
|
BlocProvider(
|
|
create: (context) => MenuBloc(
|
|
style: MenuView.list_grid,
|
|
item: EnumMenuItem.button,
|
|
entries: MenuEntry.getEntriesByType(
|
|
MenuEntryType.Home),
|
|
)..add(MenuEvent()),
|
|
),
|
|
BlocProvider<HomeBloc>(
|
|
create: (context) => HomeBloc()..add(HomeEvent()),
|
|
),
|
|
BlocProvider(
|
|
create: (context) =>
|
|
LocalProfileBloc()..add(LocalProfileEvent()),
|
|
),
|
|
],
|
|
child: HomePageWidget(
|
|
key: UniqueKey(), LocalsRepositoryImpl().update),
|
|
)
|
|
: const ReceptionPageWidget();
|
|
} else {
|
|
return const WelcomePage();
|
|
}
|
|
}(),
|
|
builder: (context, snapshot) {
|
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
|
return const Center(child: CircularProgressIndicator());
|
|
} else if (snapshot.hasError) {
|
|
DialogUtil.error(context, snapshot.error.toString());
|
|
return const WelcomePage();
|
|
} else {
|
|
return snapshot.data!;
|
|
}
|
|
},
|
|
);
|
|
},
|
|
),
|
|
FFRoute(
|
|
name: 'forgotPassword',
|
|
path: '/forgotPassword',
|
|
builder: (context, params) {
|
|
late final String email =
|
|
params.getParam('email', ParamType.String);
|
|
late final String token =
|
|
params.getParam('token', ParamType.String);
|
|
|
|
return ForgotPasswordScreen(
|
|
key: ValueKey('ForgotPasswordScreen'),
|
|
email: email,
|
|
token: token,
|
|
);
|
|
}),
|
|
FFRoute(
|
|
name: 'aboutSystemPage',
|
|
path: '/aboutSystemPage',
|
|
builder: (context, params) => AboutSystemPage(),
|
|
),
|
|
FFRoute(
|
|
name: 'homePage',
|
|
path: '/homePage',
|
|
builder: (context, params) {
|
|
final Future<bool> Function(BuildContext context)? update =
|
|
params.getParam('update', ParamType.Function);
|
|
return MultiBlocProvider(
|
|
providers: [
|
|
BlocProvider(
|
|
create: (context) => MenuBloc(
|
|
style: MenuView.list_grid,
|
|
item: EnumMenuItem.button,
|
|
entries: MenuEntry.getEntriesByType(MenuEntryType.Home),
|
|
)..add(MenuEvent()),
|
|
),
|
|
BlocProvider<HomeBloc>(
|
|
create: (context) => HomeBloc()..add(HomeEvent()),
|
|
),
|
|
BlocProvider(
|
|
create: (context) =>
|
|
LocalProfileBloc()..add(LocalProfileEvent()),
|
|
),
|
|
],
|
|
child: HomePageWidget(key: UniqueKey(), update),
|
|
);
|
|
}),
|
|
FFRoute(
|
|
name: 'petsOnThePropertyPage',
|
|
path: '/petsOnThePropertyPage',
|
|
builder: (context, params) =>
|
|
Scaffold(body: const PetsHistoryScreen(isApp: true))),
|
|
FFRoute(
|
|
name: 'vehiclesOnThePropertyPage',
|
|
path: '/vehiclesOnThePropertyPage',
|
|
builder: (context, params) => const VehiclePage()),
|
|
FFRoute(
|
|
name: 'receptionPage',
|
|
path: '/receptionPage',
|
|
builder: (context, params) => const ReceptionPageWidget()),
|
|
FFRoute(
|
|
name: 'messageHistoryPage',
|
|
path: '/messageHistoryPage',
|
|
builder: (context, params) => const MessageHistoryPageWidget()),
|
|
FFRoute(
|
|
name: 'registerVisitorPage',
|
|
path: '/registerVisitorPage',
|
|
builder: (context, params) => const RegisterVisitorPageWidget()),
|
|
FFRoute(
|
|
name: 'scheduleCompleteVisitPage',
|
|
path: '/scheduleCompleteVisitPage',
|
|
builder: (context, params) =>
|
|
const ScheduleCompleteVisitPageWidget()),
|
|
FFRoute(
|
|
name: 'deliverySchedule',
|
|
path: '/deliverySchedule',
|
|
builder: (context, params) => const DeliverySchedule()),
|
|
FFRoute(
|
|
name: 'provisionalSchedule',
|
|
path: '/provisionalSchedule',
|
|
builder: (context, params) => const ProvisionalSchedule()),
|
|
FFRoute(
|
|
name: 'fastPassPage',
|
|
path: '/fastPassPage',
|
|
builder: (context, params) => FastPassPageWidget()),
|
|
FFRoute(
|
|
name: 'preferencesSettings',
|
|
path: '/preferencesSettings',
|
|
builder: (context, params) => PreferencesPageWidget()),
|
|
FFRoute(
|
|
name: 'aboutProperty',
|
|
path: '/aboutProperty',
|
|
builder: (context, params) => AboutPropertyPage()),
|
|
FFRoute(
|
|
name: 'residentsOnThePropertyPage',
|
|
path: '/residentsOnThePropertyPage',
|
|
builder: (context, params) => ResidentsOnTheProperty()),
|
|
FFRoute(
|
|
name: 'visitsOnThePropertyPage',
|
|
path: '/visitsOnThePropertyPage',
|
|
builder: (context, params) => VisitsOnTheProperty()),
|
|
FFRoute(
|
|
name: 'peopleOnThePropertyPage',
|
|
path: '/peopleOnThePropertyPage',
|
|
builder: (context, params) => PeopleOnThePropertyPage()),
|
|
FFRoute(
|
|
name: 'acessHistoryPage',
|
|
path: '/acessHistoryPage',
|
|
builder: (context, params) => AccessHistoryScreen(opt: const {
|
|
'personType': '.*',
|
|
'accessType': '.*',
|
|
'search': '.*'
|
|
})),
|
|
FFRoute(
|
|
name: 'provisionalHistoryPage',
|
|
path: '/provisionalHistoryPage',
|
|
builder: (context, params) => ProvisionalHistoryPage()),
|
|
FFRoute(
|
|
name: 'liberationHistory',
|
|
path: '/liberationHistory',
|
|
builder: (context, params) => const LiberationHistoryWidget()),
|
|
FFRoute(
|
|
name: 'signInPage',
|
|
path: '/signInPage',
|
|
builder: (context, params) => const SignInPageWidget()),
|
|
FFRoute(
|
|
name: 'signUpPage',
|
|
path: '/signUpPage',
|
|
builder: (context, params) => const SignUpPageWidget()),
|
|
FFRoute(
|
|
name: 'welcomePage',
|
|
path: '/welcomePage',
|
|
builder: (context, params) => const WelcomePage()),
|
|
FFRoute(
|
|
name: 'qrCodePage',
|
|
path: '/qrCodePage',
|
|
builder: (context, params) => const QrCodePageWidget()),
|
|
FFRoute(
|
|
name: 'preferencesPage',
|
|
path: '/preferencesPage',
|
|
builder: (context, params) => PreferencesPageWidget()),
|
|
FFRoute(
|
|
name: 'packageOrder',
|
|
path: '/packageOrder',
|
|
builder: (context, params) => const PackageOrderPage()),
|
|
FFRoute(
|
|
name: 'reservation',
|
|
path: '/reservation',
|
|
builder: (context, params) => ReservationPageWidget()),
|
|
FFRoute(
|
|
name: 'petsPage',
|
|
path: '/petsPage',
|
|
builder: (context, params) {
|
|
final pet = params.getParam('pet', ParamType.JSON);
|
|
return PetsPageWidget(pet: pet);
|
|
},
|
|
),
|
|
// FFRoute(name: 'settingsPage', path: '/settingsPage', builder: (context, params) => params.isEmpty ? const NavBarPage(initialPage: 'settingsPage') : const SettingsPageWidget())
|
|
].map((r) => r.toRoute(appStateNotifier)).toList(),
|
|
);
|
|
}
|
|
|
|
extension NavParamExtensions on Map<String, String?> {
|
|
Map<String, String> get withoutNulls => Map.fromEntries(
|
|
entries
|
|
.where((e) => e.value != null)
|
|
.map((e) => MapEntry(e.key, e.value!)),
|
|
);
|
|
}
|
|
|
|
extension NavigationExtensions on BuildContext {
|
|
void safePop() {
|
|
if (canPop())
|
|
pop();
|
|
else
|
|
go('/');
|
|
}
|
|
}
|
|
|
|
extension _GoRouterStateExtensions on GoRouterState {
|
|
Map<String, dynamic> get extraMap =>
|
|
extra != null ? extra as Map<String, dynamic> : {};
|
|
Map<String, dynamic> get allParams => <String, dynamic>{}
|
|
..addAll(pathParameters)
|
|
..addAll(uri.queryParameters)
|
|
..addAll(extraMap);
|
|
TransitionInfo get transitionInfo => extraMap.containsKey(kTransitionInfoKey)
|
|
? extraMap[kTransitionInfoKey] as TransitionInfo
|
|
: TransitionInfo.appDefault();
|
|
}
|
|
|
|
extension GoRouterLocationExtension on GoRouter {
|
|
String getCurrentLocation() {
|
|
final RouteMatch lastMatch = routerDelegate.currentConfiguration.last;
|
|
final RouteMatchList matchList = lastMatch is ImperativeRouteMatch
|
|
? lastMatch.matches
|
|
: routerDelegate.currentConfiguration;
|
|
return matchList.uri.toString();
|
|
}
|
|
}
|
|
|
|
class FFParameters {
|
|
FFParameters(this.state, [this.asyncParams = const {}]);
|
|
final GoRouterState state;
|
|
|
|
final Map<String, Future<dynamic> Function(String)> asyncParams;
|
|
Map<String, dynamic> futureParamValues = {};
|
|
|
|
bool get isEmpty =>
|
|
state.allParams.isEmpty ||
|
|
(state.allParams.length == 1 &&
|
|
state.extraMap.containsKey(kTransitionInfoKey));
|
|
bool isAsyncParam(MapEntry<String, dynamic> param) =>
|
|
asyncParams.containsKey(param.key) && param.value is String;
|
|
bool get hasFutures => state.allParams.entries.any(isAsyncParam);
|
|
Future<bool> completeFutures() => Future.wait(
|
|
state.allParams.entries.where(isAsyncParam).map(
|
|
(param) async {
|
|
final doc = await asyncParams[param.key]!(param.value)
|
|
.onError((_, __) => null);
|
|
if (doc != null) {
|
|
futureParamValues[param.key] = doc;
|
|
return true;
|
|
} else
|
|
return false;
|
|
},
|
|
),
|
|
).onError((_, __) => [false]).then((v) => v.every((e) => e));
|
|
|
|
dynamic getParam<T>(String paramName, ParamType type,
|
|
{bool isList = false, StructBuilder<T>? structBuilder}) {
|
|
if (futureParamValues.containsKey(paramName))
|
|
return futureParamValues[paramName];
|
|
if (!state.allParams.containsKey(paramName)) return null;
|
|
final param = state.allParams[paramName];
|
|
if (param is! String) return param;
|
|
return deserializeParam<T>(param, type, isList,
|
|
structBuilder: structBuilder);
|
|
}
|
|
}
|
|
|
|
class FFRoute {
|
|
const FFRoute({
|
|
required this.name,
|
|
required this.path,
|
|
required this.builder,
|
|
this.requireAuth = false,
|
|
this.asyncParams = const {},
|
|
this.routes = const [],
|
|
});
|
|
|
|
final String name;
|
|
final String path;
|
|
final bool requireAuth;
|
|
final Map<String, Future<dynamic> Function(String)> asyncParams;
|
|
final Widget Function(BuildContext, FFParameters) builder;
|
|
final List<GoRoute> routes;
|
|
|
|
GoRoute toRoute(AppStateNotifier appStateNotifier) => GoRoute(
|
|
name: name,
|
|
path: path,
|
|
pageBuilder: (context, state) {
|
|
fixStatusBarOniOS16AndBelow(context);
|
|
final ffParams = FFParameters(state, asyncParams);
|
|
final page = ffParams.hasFutures
|
|
? FutureBuilder(
|
|
future: ffParams.completeFutures(),
|
|
builder: (context, _) => builder(context, ffParams),
|
|
)
|
|
: builder(context, ffParams);
|
|
final child = page;
|
|
final transitionInfo = state.transitionInfo;
|
|
return transitionInfo.hasTransition
|
|
? CustomTransitionPage(
|
|
key: state.pageKey,
|
|
child: child,
|
|
transitionDuration: transitionInfo.duration,
|
|
transitionsBuilder:
|
|
(context, animation, secondaryAnimation, child) =>
|
|
PageTransition(
|
|
type: transitionInfo.transitionType,
|
|
duration: transitionInfo.duration,
|
|
reverseDuration: transitionInfo.duration,
|
|
alignment: transitionInfo.alignment,
|
|
child: child,
|
|
).buildTransitions(
|
|
context, animation, secondaryAnimation, child),
|
|
)
|
|
: MaterialPage(key: state.pageKey, child: child);
|
|
},
|
|
routes: routes,
|
|
);
|
|
}
|
|
|
|
class TransitionInfo {
|
|
const TransitionInfo({
|
|
required this.hasTransition,
|
|
this.transitionType = PageTransitionType.fade,
|
|
this.duration = const Duration(milliseconds: 300),
|
|
this.alignment,
|
|
});
|
|
|
|
final bool hasTransition;
|
|
final PageTransitionType transitionType;
|
|
final Duration duration;
|
|
final Alignment? alignment;
|
|
|
|
static TransitionInfo appDefault() =>
|
|
const TransitionInfo(hasTransition: false);
|
|
}
|
|
|
|
class RootPageContext {
|
|
const RootPageContext(this.isRootPage, [this.errorRoute]);
|
|
final bool isRootPage;
|
|
final String? errorRoute;
|
|
|
|
static bool isInactiveRootPage(BuildContext context) {
|
|
final rootPageContext = context.read<RootPageContext?>();
|
|
final isRootPage = rootPageContext?.isRootPage ?? false;
|
|
final location = GoRouterState.of(context).uri.toString();
|
|
return isRootPage &&
|
|
location != '/' &&
|
|
location != rootPageContext?.errorRoute;
|
|
}
|
|
|
|
static Widget wrap(Widget child, {String? errorRoute}) =>
|
|
Provider.value(value: RootPageContext(true, errorRoute), child: child);
|
|
}
|