e6b4720dcd
- Changed the iOS deployment target from 12.0 to 13.0 in Podfile and project settings. - Updated AppDelegate to support implicit Flutter engine initialization. - Modified Info.plist to include scene configuration for multiple scenes. - Enhanced CompletionOfDocumentsRouteData to accept a tenderId parameter. - Implemented tender submission functionality in TenderDetailViewModel and updated UI components to reflect loading states and success/error messages. - Added new strings for submission success and error notifications.
346 lines
11 KiB
Dart
346 lines
11 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/board/pages/board_screen.dart';
|
|
import 'package:tm_app/views/completion_of_documents/pages/complectopn_of_documents_screen.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/board_provider.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 user has token and tries to access login page, redirect to home
|
|
if (hasToken && isLogin) {
|
|
return '/home';
|
|
}
|
|
|
|
// If user doesn't have token and tries to access protected routes, redirect to splash
|
|
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<NotificationBranch>(
|
|
routes: <TypedRoute<RouteData>>[
|
|
TypedGoRoute<NotificationRouteData>(path: '/notification'),
|
|
],
|
|
),
|
|
TypedStatefulShellBranch<ProfileBranch>(
|
|
routes: <TypedRoute<RouteData>>[
|
|
TypedGoRoute<ProfileRouteData>(path: '/profile'),
|
|
],
|
|
),
|
|
],
|
|
)
|
|
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 {
|
|
final String status;
|
|
const YourTendersRouteData({required this.status});
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return yourTendersProvider(child: YourTendersScreen(status: status));
|
|
}
|
|
}
|
|
|
|
@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<CompletionOfDocumentsRouteData>(path: '/completion_of_documents')
|
|
class CompletionOfDocumentsRouteData extends GoRouteData
|
|
with _$CompletionOfDocumentsRouteData {
|
|
final String? tenderId;
|
|
const CompletionOfDocumentsRouteData({this.tenderId});
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return tenderDetailProvider(
|
|
child: CompletionOfDocumentsScreen(tenderId: tenderId),
|
|
);
|
|
}
|
|
}
|
|
|
|
@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<BoardRouteData>(path: '/board')
|
|
class BoardRouteData extends GoRouteData with _$BoardRouteData {
|
|
const BoardRouteData();
|
|
|
|
@override
|
|
Widget build(BuildContext context, GoRouterState state) {
|
|
return boardProvider(child: const BoardScreen());
|
|
}
|
|
}
|
|
|
|
// @TypedGoRoute<CompletionOfDocumentsRouteData>(
|
|
// 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),
|
|
);
|
|
}
|
|
}
|