cee5e6c6d6
- Implemented `ForgotPasswordViewModel`, `ResetPasswordViewModel`, and `VerifyOtpViewModel` for handling respective functionalities. - Created provider functions for lazy loading of these view models in the app. - Updated routing to utilize the new providers for managing state in the forgot password flow. - Refactored UI components to integrate with the new view models, ensuring proper state management and user feedback during operations.
310 lines
10 KiB
Dart
310 lines
10 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
import 'package:tm_app/views/completion_of_documents/pages/m_completion_of_documents_page.dart';
|
|
import 'package:tm_app/views/detail/pages/detail_screen.dart';
|
|
import 'package:tm_app/views/forget_password_create/pages/forgot_password_create_screen.dart';
|
|
import 'package:tm_app/views/forget_password_otp/pages/forgot_password_otp_screen.dart';
|
|
import 'package:tm_app/views/home/pages/home_screen.dart';
|
|
import 'package:tm_app/views/liked_tenders/pages/liked_tenders_screen.dart';
|
|
import 'package:tm_app/views/login/pages/login_screen.dart';
|
|
|
|
import '../../views/final_completion_of_documents/pages/final_completion_of_documents_screen.dart';
|
|
import '../../views/forgot_password/pages/forgot_password_screen.dart';
|
|
import '../../views/notification/pages/notification_screen.dart';
|
|
import '../../views/profile/pages/profile_screen.dart';
|
|
import '../../views/splash/pages/splash_screen.dart';
|
|
import '../../views/tenders/pages/tenders_screen.dart';
|
|
import '../../views/your_tenders/pages/your_tenders_screen.dart';
|
|
import '../providers/final_completion_provider.dart';
|
|
import '../providers/forgot_password_provider.dart';
|
|
import '../providers/home_provider.dart';
|
|
import '../providers/liked_tenders_provider.dart';
|
|
import '../providers/notification_provider.dart';
|
|
import '../providers/profile_provider.dart';
|
|
import '../providers/reset_password_provider.dart';
|
|
import '../providers/tender_detail_provider.dart';
|
|
import '../providers/tenders_provider.dart';
|
|
import '../providers/verify_otp_provider.dart';
|
|
import '../providers/your_tenders_provider.dart';
|
|
import 'app_shell/app_shell_screen.dart';
|
|
|
|
part 'app_routes.g.dart';
|
|
|
|
// Global navigator keys
|
|
final GlobalKey<NavigatorState> rootNavigatorKey = GlobalKey<NavigatorState>();
|
|
final GlobalKey<NavigatorState> homeNavigatorKey = GlobalKey<NavigatorState>();
|
|
final GlobalKey<NavigatorState> tendersNavigatorKey =
|
|
GlobalKey<NavigatorState>();
|
|
final GlobalKey<NavigatorState> profileNavigatorKey =
|
|
GlobalKey<NavigatorState>();
|
|
final GlobalKey<NavigatorState> notificationNavigatorKey =
|
|
GlobalKey<NavigatorState>();
|
|
|
|
// Main app router
|
|
final GoRouter appRouter = GoRouter(
|
|
routes: $appRoutes,
|
|
initialLocation: '/splash',
|
|
navigatorKey: rootNavigatorKey,
|
|
redirect: (context, state) {
|
|
final prefs = context.read<SharedPreferences>();
|
|
final hasToken = prefs.getString('bearer') != null;
|
|
final path = state.uri.path;
|
|
final location = state.matchedLocation;
|
|
final isSplash = path == '/splash' || location == '/splash';
|
|
final isLogin = path == '/login' || location == '/login';
|
|
final isForgotFlow =
|
|
path.startsWith('/forgot-password') ||
|
|
location.startsWith('/forgot-password');
|
|
final isPublic = isSplash || isLogin || isForgotFlow;
|
|
if (!hasToken && !isPublic) {
|
|
return '/splash';
|
|
}
|
|
return null;
|
|
},
|
|
);
|
|
|
|
// Login route - outside the shell
|
|
@TypedGoRoute<LoginScreenRoute>(path: '/login')
|
|
class LoginScreenRoute extends GoRouteData with _$LoginScreenRoute {
|
|
const LoginScreenRoute();
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return const LoginScreen();
|
|
}
|
|
}
|
|
|
|
// splash route - outside the shell
|
|
@TypedGoRoute<SplashScreenRoute>(path: '/splash')
|
|
class SplashScreenRoute extends GoRouteData with _$SplashScreenRoute {
|
|
final bool? navigateToNotification;
|
|
const SplashScreenRoute({this.navigateToNotification});
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return SplashScreen(
|
|
navigateToNotification: navigateToNotification ?? false,
|
|
);
|
|
}
|
|
}
|
|
|
|
// Shell route with bottom navigation using StatefulShellRoute.indexedStack
|
|
@TypedStatefulShellRoute<AppShellRouteData>(
|
|
branches: <TypedStatefulShellBranch<StatefulShellBranchData>>[
|
|
TypedStatefulShellBranch<HomeBranch>(
|
|
routes: <TypedRoute<RouteData>>[
|
|
TypedGoRoute<HomeRouteData>(path: '/home'),
|
|
],
|
|
),
|
|
TypedStatefulShellBranch<TendersBranch>(
|
|
routes: <TypedRoute<RouteData>>[
|
|
TypedGoRoute<TendersRouteData>(path: '/tenders'),
|
|
],
|
|
),
|
|
TypedStatefulShellBranch<ProfileBranch>(
|
|
routes: <TypedRoute<RouteData>>[
|
|
TypedGoRoute<ProfileRouteData>(path: '/profile'),
|
|
],
|
|
),
|
|
TypedStatefulShellBranch<NotificationBranch>(
|
|
routes: <TypedRoute<RouteData>>[
|
|
TypedGoRoute<NotificationRouteData>(path: '/notification'),
|
|
],
|
|
),
|
|
],
|
|
)
|
|
class AppShellRouteData extends StatefulShellRouteData {
|
|
const AppShellRouteData();
|
|
|
|
static final GlobalKey<NavigatorState> $parentNavigatorKey = rootNavigatorKey;
|
|
|
|
@override
|
|
Widget builder(
|
|
BuildContext context,
|
|
GoRouterState state,
|
|
StatefulNavigationShell navigationShell,
|
|
) {
|
|
return AppShellScreen(navigationShell: navigationShell);
|
|
}
|
|
}
|
|
|
|
// Branch data classes
|
|
class HomeBranch extends StatefulShellBranchData {
|
|
const HomeBranch();
|
|
static final GlobalKey<NavigatorState> $navigatorKey = homeNavigatorKey;
|
|
}
|
|
|
|
class TendersBranch extends StatefulShellBranchData {
|
|
const TendersBranch();
|
|
static final GlobalKey<NavigatorState> $navigatorKey = tendersNavigatorKey;
|
|
}
|
|
|
|
class ProfileBranch extends StatefulShellBranchData {
|
|
const ProfileBranch();
|
|
static final GlobalKey<NavigatorState> $navigatorKey = profileNavigatorKey;
|
|
}
|
|
|
|
class NotificationBranch extends StatefulShellBranchData {
|
|
const NotificationBranch();
|
|
static final GlobalKey<NavigatorState> $navigatorKey =
|
|
notificationNavigatorKey;
|
|
}
|
|
|
|
// Route data classes
|
|
class HomeRouteData extends GoRouteData with _$HomeRouteData {
|
|
const HomeRouteData();
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return homeProvider(child: const HomeScreen());
|
|
}
|
|
|
|
// @override
|
|
// Page<void> buildPage(BuildContext context, GoRouterState state) {
|
|
// return CustomTransitionPage<void>(
|
|
// key: state.pageKey,
|
|
// child: const HomeScreen(),
|
|
// transitionDuration: const Duration(milliseconds: 500),
|
|
// transitionsBuilder: (context, animation, secondaryAnimation, child) {
|
|
// const begin = Offset(1.0, 0.0); // From right to left
|
|
// const end = Offset.zero;
|
|
// const curve = Curves.linearToEaseOut;
|
|
|
|
// var tween = Tween(
|
|
// begin: begin,
|
|
// end: end,
|
|
// ).chain(CurveTween(curve: curve));
|
|
// var offsetAnimation = animation.drive(tween);
|
|
// return SlideTransition(position: offsetAnimation, child: child);
|
|
// },
|
|
// );
|
|
// }
|
|
}
|
|
|
|
class TendersRouteData extends GoRouteData with _$TendersRouteData {
|
|
const TendersRouteData();
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return tendersProvider(child: const TendersScreen());
|
|
}
|
|
}
|
|
|
|
class ProfileRouteData extends GoRouteData with _$ProfileRouteData {
|
|
const ProfileRouteData();
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return profileProvider(child: const ProfileScreen());
|
|
}
|
|
}
|
|
|
|
class NotificationRouteData extends GoRouteData with _$NotificationRouteData {
|
|
const NotificationRouteData();
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return notificationProvider(child: const NotificationScreen());
|
|
}
|
|
}
|
|
|
|
@TypedGoRoute<YourTendersRouteData>(path: '/your-tenders')
|
|
class YourTendersRouteData extends GoRouteData with _$YourTendersRouteData {
|
|
const YourTendersRouteData();
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return yourTendersProvider(child: const YourTendersScreen());
|
|
}
|
|
}
|
|
|
|
@TypedGoRoute<FinalCompletionOfDocumentsRouteData>(
|
|
path: '/final_completion_of_documents',
|
|
)
|
|
class FinalCompletionOfDocumentsRouteData extends GoRouteData
|
|
with _$FinalCompletionOfDocumentsRouteData {
|
|
const FinalCompletionOfDocumentsRouteData();
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return finalCompletionProvider(
|
|
child: const FinalCompletionOfDocumentsScreen(),
|
|
);
|
|
}
|
|
}
|
|
|
|
@TypedGoRoute<LikedTendersRouteData>(path: '/like-tenders')
|
|
class LikedTendersRouteData extends GoRouteData with _$LikedTendersRouteData {
|
|
const LikedTendersRouteData();
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return likedTendersProvider(child: const LikedTendersScreen());
|
|
}
|
|
}
|
|
|
|
@TypedGoRoute<CompletionOfDocumentsMobileRouteData>(
|
|
path: '/completion-of-documents',
|
|
)
|
|
class CompletionOfDocumentsMobileRouteData extends GoRouteData
|
|
with _$CompletionOfDocumentsMobileRouteData {
|
|
const CompletionOfDocumentsMobileRouteData();
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return finalCompletionProvider(
|
|
child: const CompletionOfDocumentsMobilePage(),
|
|
);
|
|
}
|
|
}
|
|
|
|
@TypedGoRoute<TenderDetailRouteData>(path: '/tender-detail')
|
|
class TenderDetailRouteData extends GoRouteData with _$TenderDetailRouteData {
|
|
final String tenderId;
|
|
const TenderDetailRouteData({required this.tenderId});
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return tenderDetailProvider(child: TenderDetailScreen(tenderId: tenderId));
|
|
}
|
|
}
|
|
|
|
@TypedGoRoute<ForgotPasswordRouteData>(path: '/forgot-password')
|
|
class ForgotPasswordRouteData extends GoRouteData
|
|
with _$ForgotPasswordRouteData {
|
|
const ForgotPasswordRouteData();
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return forgotPasswordProvider(child: const ForgotPasswordScreen());
|
|
}
|
|
}
|
|
|
|
@TypedGoRoute<ForgotPasswordOtpRouteData>(path: '/forgot-password-otp')
|
|
class ForgotPasswordOtpRouteData extends GoRouteData
|
|
with _$ForgotPasswordOtpRouteData {
|
|
final String email;
|
|
const ForgotPasswordOtpRouteData({required this.email});
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return verifyOtpProvider(child: ForgotPasswordOtpScreen(email: email));
|
|
}
|
|
}
|
|
|
|
@TypedGoRoute<ForgotPasswordCreateRouteData>(path: '/forgot-password-create')
|
|
class ForgotPasswordCreateRouteData extends GoRouteData
|
|
with _$ForgotPasswordCreateRouteData {
|
|
final String resetToken;
|
|
const ForgotPasswordCreateRouteData({required this.resetToken});
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return resetPasswordProvider(
|
|
child: ForgotPasswordCreateScreen(resetToken: resetToken),
|
|
);
|
|
}
|
|
}
|