˜milestone˜

This commit is contained in:
jantunesmessias 2024-11-19 15:31:22 -03:00
parent 0205c74f8c
commit b97c32f80b
7 changed files with 96 additions and 61 deletions

View File

@ -3,7 +3,7 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>FlutterDeepLinkingEnabled</key> <key>FlutterDeepLinkingEnabled</key>
<true/> <false/>
<key>CADisableMinimumFrameDurationOnPhone</key> <key>CADisableMinimumFrameDurationOnPhone</key>
<true/> <true/>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>

View File

@ -28,6 +28,8 @@ export 'serialization_util.dart';
const kTransitionInfoKey = '__transition_info__'; const kTransitionInfoKey = '__transition_info__';
final GlobalKey<NavigatorState> key = GlobalKey<NavigatorState>();
class AppStateNotifier extends ChangeNotifier { class AppStateNotifier extends ChangeNotifier {
AppStateNotifier._(); AppStateNotifier._();
@ -44,6 +46,7 @@ class AppStateNotifier extends ChangeNotifier {
GoRouter createRouter(AppStateNotifier appStateNotifier) { GoRouter createRouter(AppStateNotifier appStateNotifier) {
return GoRouter( return GoRouter(
navigatorKey: key,
initialLocation: '/', initialLocation: '/',
debugLogDiagnostics: true, debugLogDiagnostics: true,
refreshListenable: appStateNotifier, refreshListenable: appStateNotifier,
@ -80,19 +83,28 @@ GoRouter createRouter(AppStateNotifier appStateNotifier) {
builder: (context, _) { builder: (context, _) {
return FutureBuilder<Widget>( return FutureBuilder<Widget>(
future: () async { future: () async {
final bool isLogged = final bool isLogged = await StorageHelper().get(
await StorageHelper().get(SecureStorageKey.isLogged.value, Storage.SecureStorage) == 'true'; SecureStorageKey.isLogged.value, Storage.SecureStorage) ==
final bool haveLocal = 'true';
await StorageHelper().get(SecureStorageKey.haveLocal.value, Storage.SecureStorage) == 'true'; final bool haveLocal = await StorageHelper().get(
final bool haveUserUUID = SecureStorageKey.haveLocal.value,
(await StorageHelper().get(SQLiteStorageKey.userUUID.value, Storage.SQLiteStorage))?.isNotEmpty ?? Storage.SecureStorage) ==
false; 'true';
final bool haveDevUUID = final bool haveUserUUID = (await StorageHelper().get(
(await StorageHelper().get(SQLiteStorageKey.devUUID.value, Storage.SQLiteStorage))?.isNotEmpty ?? SQLiteStorageKey.userUUID.value,
false; Storage.SQLiteStorage))
?.isNotEmpty ??
false;
final bool haveDevUUID = (await StorageHelper().get(
SQLiteStorageKey.devUUID.value,
Storage.SQLiteStorage))
?.isNotEmpty ??
false;
if (isLogged && haveDevUUID && haveUserUUID) { if (isLogged && haveDevUUID && haveUserUUID) {
return haveLocal ? const HomePageWidget() : const ReceptionPageWidget(); return haveLocal
? const HomePageWidget()
: const ReceptionPageWidget();
} else { } else {
return const WelcomePageWidget(); return const WelcomePageWidget();
} }
@ -114,8 +126,10 @@ GoRouter createRouter(AppStateNotifier appStateNotifier) {
name: 'forgotPassword', name: 'forgotPassword',
path: '/forgotPassword', path: '/forgotPassword',
builder: (context, params) { builder: (context, params) {
late final String email = params.getParam('email', ParamType.String); late final String email =
late final String token = params.getParam('token', ParamType.String); params.getParam('email', ParamType.String);
late final String token =
params.getParam('token', ParamType.String);
return ForgotPasswordScreen( return ForgotPasswordScreen(
key: UniqueKey(), key: UniqueKey(),
@ -128,7 +142,10 @@ GoRouter createRouter(AppStateNotifier appStateNotifier) {
path: '/homePage', path: '/homePage',
builder: (context, params) => HomePageWidget(key: UniqueKey()), builder: (context, params) => HomePageWidget(key: UniqueKey()),
), ),
FFRoute(name: 'receptionPage', path: '/receptionPage', builder: (context, params) => const ReceptionPageWidget()), FFRoute(
name: 'receptionPage',
path: '/receptionPage',
builder: (context, params) => const ReceptionPageWidget()),
FFRoute( FFRoute(
name: 'messageHistoryPage', name: 'messageHistoryPage',
path: '/messageHistoryPage', path: '/messageHistoryPage',
@ -243,7 +260,9 @@ GoRouter createRouter(AppStateNotifier appStateNotifier) {
extension NavParamExtensions on Map<String, String?> { extension NavParamExtensions on Map<String, String?> {
Map<String, String> get withoutNulls => Map.fromEntries( Map<String, String> get withoutNulls => Map.fromEntries(
entries.where((e) => e.value != null).map((e) => MapEntry(e.key, e.value!)), entries
.where((e) => e.value != null)
.map((e) => MapEntry(e.key, e.value!)),
); );
} }
@ -260,7 +279,8 @@ extension NavigationExtensions on BuildContext {
} }
extension _GoRouterStateExtensions on GoRouterState { extension _GoRouterStateExtensions on GoRouterState {
Map<String, dynamic> get extraMap => extra != null ? extra as Map<String, dynamic> : {}; Map<String, dynamic> get extraMap =>
extra != null ? extra as Map<String, dynamic> : {};
Map<String, dynamic> get allParams => <String, dynamic>{} Map<String, dynamic> get allParams => <String, dynamic>{}
..addAll(pathParameters) ..addAll(pathParameters)
..addAll(uri.queryParameters) ..addAll(uri.queryParameters)
@ -273,8 +293,9 @@ extension _GoRouterStateExtensions on GoRouterState {
extension GoRouterLocationExtension on GoRouter { extension GoRouterLocationExtension on GoRouter {
String getCurrentLocation() { String getCurrentLocation() {
final RouteMatch lastMatch = routerDelegate.currentConfiguration.last; final RouteMatch lastMatch = routerDelegate.currentConfiguration.last;
final RouteMatchList matchList = final RouteMatchList matchList = lastMatch is ImperativeRouteMatch
lastMatch is ImperativeRouteMatch ? lastMatch.matches : routerDelegate.currentConfiguration; ? lastMatch.matches
: routerDelegate.currentConfiguration;
return matchList.uri.toString(); return matchList.uri.toString();
} }
} }
@ -290,13 +311,17 @@ class FFParameters {
// Parameters are empty if the params map is empty or if the only parameter // Parameters are empty if the params map is empty or if the only parameter
// present is the special extra parameter reserved for the transition info. // present is the special extra parameter reserved for the transition info.
bool get isEmpty => bool get isEmpty =>
state.allParams.isEmpty || (state.allParams.length == 1 && state.extraMap.containsKey(kTransitionInfoKey)); state.allParams.isEmpty ||
bool isAsyncParam(MapEntry<String, dynamic> param) => asyncParams.containsKey(param.key) && param.value is String; (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); bool get hasFutures => state.allParams.entries.any(isAsyncParam);
Future<bool> completeFutures() => Future.wait( Future<bool> completeFutures() => Future.wait(
state.allParams.entries.where(isAsyncParam).map( state.allParams.entries.where(isAsyncParam).map(
(param) async { (param) async {
final doc = await asyncParams[param.key]!(param.value).onError((_, __) => null); final doc = await asyncParams[param.key]!(param.value)
.onError((_, __) => null);
if (doc != null) { if (doc != null) {
futureParamValues[param.key] = doc; futureParamValues[param.key] = doc;
return true; return true;
@ -370,7 +395,9 @@ class FFRoute {
key: state.pageKey, key: state.pageKey,
child: child, child: child,
transitionDuration: transitionInfo.duration, transitionDuration: transitionInfo.duration,
transitionsBuilder: (context, animation, secondaryAnimation, child) => PageTransition( transitionsBuilder:
(context, animation, secondaryAnimation, child) =>
PageTransition(
type: transitionInfo.transitionType, type: transitionInfo.transitionType,
duration: transitionInfo.duration, duration: transitionInfo.duration,
reverseDuration: transitionInfo.duration, reverseDuration: transitionInfo.duration,
@ -402,7 +429,8 @@ class TransitionInfo {
final Duration duration; final Duration duration;
final Alignment? alignment; final Alignment? alignment;
static TransitionInfo appDefault() => const TransitionInfo(hasTransition: false); static TransitionInfo appDefault() =>
const TransitionInfo(hasTransition: false);
} }
class RootPageContext { class RootPageContext {
@ -414,7 +442,9 @@ class RootPageContext {
final rootPageContext = context.read<RootPageContext?>(); final rootPageContext = context.read<RootPageContext?>();
final isRootPage = rootPageContext?.isRootPage ?? false; final isRootPage = rootPageContext?.isRootPage ?? false;
final location = GoRouterState.of(context).uri.toString(); final location = GoRouterState.of(context).uri.toString();
return isRootPage && location != '/' && location != rootPageContext?.errorRoute; return isRootPage &&
location != '/' &&
location != rootPageContext?.errorRoute;
} }
static Widget wrap(Widget child, {String? errorRoute}) => Provider.value( static Widget wrap(Widget child, {String? errorRoute}) => Provider.value(

View File

@ -18,6 +18,7 @@ import 'package:hub/flutter_flow/internationalization.dart';
import 'package:hub/flutter_flow/nav/nav.dart'; import 'package:hub/flutter_flow/nav/nav.dart';
import 'package:hub/shared/helpers/base_storage.dart'; import 'package:hub/shared/helpers/base_storage.dart';
import 'package:hub/shared/helpers/storage_helper.dart'; import 'package:hub/shared/helpers/storage_helper.dart';
import 'package:hub/shared/services/deeplink/deep_link_service.dart';
import 'package:hub/shared/services/localization/localization_service.dart'; import 'package:hub/shared/services/localization/localization_service.dart';
import 'package:responsive_framework/responsive_framework.dart'; import 'package:responsive_framework/responsive_framework.dart';
@ -81,7 +82,8 @@ Future<void> _initializeFlutterFlow() async {
Future<void> _foregroundHandlerMessage(RemoteMessage message) async { Future<void> _foregroundHandlerMessage(RemoteMessage message) async {
if (message.data['click_action'] == 'enroll_cond') { if (message.data['click_action'] == 'enroll_cond') {
await StorageHelper().set(SecureStorageKey.haveLocal.value, 'true', Storage.SecureStorage); await StorageHelper()
.set(SecureStorageKey.haveLocal.value, 'true', Storage.SecureStorage);
StorageHelper().context?.go('/homePage'); StorageHelper().context?.go('/homePage');
} }
@ -95,7 +97,8 @@ Future<void> _foregroundHandlerMessage(RemoteMessage message) async {
Future<void> _backgroundHandlerMessage(RemoteMessage message) async { Future<void> _backgroundHandlerMessage(RemoteMessage message) async {
if (message.data['click_action'] == 'enroll_cond') { if (message.data['click_action'] == 'enroll_cond') {
await StorageHelper().set(SecureStorageKey.haveLocal.value, 'true', Storage.SecureStorage); await StorageHelper()
.set(SecureStorageKey.haveLocal.value, 'true', Storage.SecureStorage);
StorageHelper().context?.go('/homePage'); StorageHelper().context?.go('/homePage');
} }
} }
@ -106,7 +109,8 @@ class App extends StatefulWidget {
@override @override
State<App> createState() => _AppState(); State<App> createState() => _AppState();
static _AppState of(BuildContext context) => context.findAncestorStateOfType<_AppState>()!; static _AppState of(BuildContext context) =>
context.findAncestorStateOfType<_AppState>()!;
} }
class _AppState extends State<App> with WidgetsBindingObserver { class _AppState extends State<App> with WidgetsBindingObserver {
@ -148,7 +152,8 @@ class _AppState extends State<App> with WidgetsBindingObserver {
}), }),
), ),
); );
final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates = const [ final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates =
const [
FFLocalizationsDelegate(), FFLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate, GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate, GlobalWidgetsLocalizations.delegate,
@ -187,16 +192,19 @@ class _AppState extends State<App> with WidgetsBindingObserver {
FirebaseMessaging.onMessage.listen(_foregroundHandlerMessage); FirebaseMessaging.onMessage.listen(_foregroundHandlerMessage);
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async { FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
if (message.data['click_action'] == 'enroll_cond') { if (message.data['click_action'] == 'enroll_cond') {
await StorageHelper().set(SecureStorageKey.haveLocal.value, 'true', Storage.SecureStorage); await StorageHelper().set(
SecureStorageKey.haveLocal.value, 'true', Storage.SecureStorage);
log('onMessageOpenedApp'); log('onMessageOpenedApp');
} else { } else {
onMessageReceived(message.data, message.notification!.body, message.data['click_action']); onMessageReceived(message.data, message.notification!.body,
message.data['click_action']);
} }
}); });
FirebaseMessaging.instance.getInitialMessage().then((message) async { FirebaseMessaging.instance.getInitialMessage().then((message) async {
if (message != null) { if (message != null) {
if (message.data['click_action'] == 'enroll_cond') { if (message.data['click_action'] == 'enroll_cond') {
await StorageHelper().set(SecureStorageKey.haveLocal.value, 'true', Storage.SecureStorage); await StorageHelper().set(
SecureStorageKey.haveLocal.value, 'true', Storage.SecureStorage);
log('getInitialMessage'); log('getInitialMessage');
} }
} }
@ -229,6 +237,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
); );
_setupFirebaseMessaging(); _setupFirebaseMessaging();
DeepLinkService().ensureInitialization();
} }
@override @override

View File

@ -25,9 +25,6 @@ class _SignInPageWidgetState extends State<SignInPageWidget> {
void initState() { void initState() {
super.initState(); super.initState();
_model = createModel(context, () => SignInPageModel()); _model = createModel(context, () => SignInPageModel());
WidgetsBinding.instance.addPostFrameCallback((_) async {
await DeepLinkService().ensureInitialization();
});
} }
@override @override

View File

@ -26,9 +26,6 @@ class _SignUpPageWidgetState extends State<SignUpPageWidget> {
void initState() { void initState() {
super.initState(); super.initState();
_model = createModel(context, () => SignUpPageModel()); _model = createModel(context, () => SignUpPageModel());
WidgetsBinding.instance.addPostFrameCallback((_) async {
await DeepLinkService().ensureInitialization();
});
} }
@override @override

View File

@ -32,19 +32,19 @@ class _WelcomePageWidgetState extends State<WelcomePageWidget> {
// On page load action. // On page load action.
SchedulerBinding.instance.addPostFrameCallback((_) async { SchedulerBinding.instance.addPostFrameCallback((_) async {
if (isAndroid == true) { if (isAndroid == true) {
await StorageHelper().set(SecureStorageKey.deviceType.value, 'Android', Storage.SecureStorage); await StorageHelper().set(SecureStorageKey.deviceType.value, 'Android',
Storage.SecureStorage);
setState(() {}); setState(() {});
} else if (isiOS == true) { } else if (isiOS == true) {
await StorageHelper().set(SecureStorageKey.deviceType.value, 'iOS', Storage.SecureStorage); await StorageHelper().set(
SecureStorageKey.deviceType.value, 'iOS', Storage.SecureStorage);
setState(() {}); setState(() {});
} else { } else {
await StorageHelper().set(SecureStorageKey.deviceType.value, 'Web', Storage.SecureStorage); await StorageHelper().set(
SecureStorageKey.deviceType.value, 'Web', Storage.SecureStorage);
setState(() {}); setState(() {});
} }
}); });
WidgetsBinding.instance.addPostFrameCallback((_) async {
await DeepLinkService().ensureInitialization();
});
} }
@override @override

View File

@ -3,6 +3,7 @@ import 'dart:developer';
import 'package:app_links/app_links.dart'; import 'package:app_links/app_links.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart'; import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/nav/nav.dart';
import 'package:hub/pages/forgot_password_page/forgot_password_screen.dart'; import 'package:hub/pages/forgot_password_page/forgot_password_screen.dart';
import 'package:hub/shared/helpers/storage_helper.dart'; import 'package:hub/shared/helpers/storage_helper.dart';
@ -17,7 +18,7 @@ class DeepLinkService {
StreamSubscription<Uri>? _linkSubscription; StreamSubscription<Uri>? _linkSubscription;
bool _isInitialized = false; bool _isInitialized = false;
Future<void> ensureInitialization() async { void ensureInitialization() async {
if (_isInitialized) return; if (_isInitialized) return;
try { try {
_appLinks = AppLinks(); _appLinks = AppLinks();
@ -54,22 +55,23 @@ class DeepLinkService {
Future<void> _showForgotPasswordScreen(String email, String token) async { Future<void> _showForgotPasswordScreen(String email, String token) async {
try { try {
final FlutterFlowTheme theme = FlutterFlowTheme.of(StorageHelper().context!); WidgetsBinding.instance.addPostFrameCallback((_) async {
final ForgotPasswordScreen screen = ForgotPasswordScreen(email: email, token: token); await showModalBottomSheet(
await showModalBottomSheet( context: key.currentContext!,
context: StorageHelper().context!, builder: (context) => Padding(
builder: (context) => Padding( padding: MediaQuery.viewInsetsOf(context),
padding: MediaQuery.viewInsetsOf(context), child: ForgotPasswordScreen(email: email, token: token),
child: screen, ),
), isScrollControlled: true,
isScrollControlled: true, backgroundColor:
backgroundColor: theme.primaryBackground, FlutterFlowTheme.of(key.currentContext!).primaryBackground,
showDragHandle: true, showDragHandle: true,
useSafeArea: true, useSafeArea: true,
enableDrag: true, enableDrag: true,
).whenComplete(() { ).whenComplete(() {
StorageHelper().isRecovered = false; StorageHelper().isRecovered = false;
print('showModalBottomSheet completed'); print('showModalBottomSheet completed');
});
}); });
} catch (e, s) { } catch (e, s) {
print('Error showing forgot password screen: $e, $s'); print('Error showing forgot password screen: $e, $s');