309 lines
14 KiB
Dart
309 lines
14 KiB
Dart
import 'dart:async';
|
|
import 'dart:developer';
|
|
import 'dart:io';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:hub/backend/schema/util/schema_util.dart';
|
|
import 'package:hub/features/home/index.dart';
|
|
import 'package:hub/features/property/index.dart';
|
|
import 'package:hub/flutter_flow/flutter_flow_util.dart';
|
|
import 'package:hub/flutter_flow/nav/nav.dart';
|
|
import 'package:hub/pages/acess_history_page/acess_history_page_widget.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/helpers/storage/base_storage.dart';
|
|
import 'package:hub/shared/helpers/storage/storage_helper.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().g(SecureStorageKey.isLogged.value) == 'true';
|
|
final bool haveLocal = await StorageHelper().g(SecureStorageKey.haveLocal.value) == 'true';
|
|
final bool haveUserUUID = (await StorageHelper().g(KeychainStorageKey.userUUID.value))?.isNotEmpty ?? false;
|
|
final bool haveDevUUID = (await StorageHelper().g(KeychainStorageKey.devUUID.value))?.isNotEmpty ?? false;
|
|
|
|
if (isLogged && haveDevUUID && haveUserUUID) {
|
|
return haveLocal ? const HomePageWidget() : const ReceptionPageWidget();
|
|
} else {
|
|
return const WelcomePageWidget();
|
|
}
|
|
}(),
|
|
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 WelcomePageWidget();
|
|
} 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: UniqueKey(),
|
|
email: email,
|
|
token: token,
|
|
);
|
|
}),
|
|
FFRoute(name: 'homePage', path: '/homePage', builder: (context, params) => HomePageWidget(key: UniqueKey())),
|
|
FFRoute(name: 'petsOnThePropertyPage', path: '/petsOnThePropertyPage', builder: (context, params) => Scaffold(body: const PetsHistoryScreen(isApp: true))),
|
|
FFRoute(name: 'vehiclesOnThePropertyPage', path: '/vehiclesOnThePropertyPage', builder: (context, params) => const VehicleOnTheProperty()),
|
|
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) => /*const*/ 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: '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 WelcomePageWidget()),
|
|
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);
|
|
}
|