go router added
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../views/home/home_screen.dart';
|
||||
import '../../views/login/login_screen.dart';
|
||||
import '../../views/profile/profile_screen.dart';
|
||||
import '../../views/tenders/tenders_screen.dart';
|
||||
import '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>();
|
||||
|
||||
// Main app router
|
||||
final GoRouter appRouter = GoRouter(
|
||||
routes: $appRoutes,
|
||||
initialLocation: '/login',
|
||||
navigatorKey: rootNavigatorKey,
|
||||
);
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
// 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'),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
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;
|
||||
}
|
||||
|
||||
// Route data classes
|
||||
class HomeRouteData extends GoRouteData with _$HomeRouteData {
|
||||
const HomeRouteData();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, GoRouterState state) {
|
||||
return 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 const TendersScreen();
|
||||
}
|
||||
}
|
||||
|
||||
class ProfileRouteData extends GoRouteData with _$ProfileRouteData {
|
||||
const ProfileRouteData();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, GoRouterState state) {
|
||||
return const ProfileScreen();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'app_routes.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// GoRouterGenerator
|
||||
// **************************************************************************
|
||||
|
||||
List<RouteBase> get $appRoutes => [$loginScreenRoute, $appShellRouteData];
|
||||
|
||||
RouteBase get $loginScreenRoute =>
|
||||
GoRouteData.$route(path: '/login', factory: _$LoginScreenRoute._fromState);
|
||||
|
||||
mixin _$LoginScreenRoute on GoRouteData {
|
||||
static LoginScreenRoute _fromState(GoRouterState state) =>
|
||||
const LoginScreenRoute();
|
||||
|
||||
@override
|
||||
String get location => GoRouteData.$location('/login');
|
||||
|
||||
@override
|
||||
void go(BuildContext context) => context.go(location);
|
||||
|
||||
@override
|
||||
Future<T?> push<T>(BuildContext context) => context.push<T>(location);
|
||||
|
||||
@override
|
||||
void pushReplacement(BuildContext context) =>
|
||||
context.pushReplacement(location);
|
||||
|
||||
@override
|
||||
void replace(BuildContext context) => context.replace(location);
|
||||
}
|
||||
|
||||
RouteBase get $appShellRouteData => StatefulShellRouteData.$route(
|
||||
parentNavigatorKey: AppShellRouteData.$parentNavigatorKey,
|
||||
factory: $AppShellRouteDataExtension._fromState,
|
||||
branches: [
|
||||
StatefulShellBranchData.$branch(
|
||||
navigatorKey: HomeBranch.$navigatorKey,
|
||||
|
||||
routes: [
|
||||
GoRouteData.$route(path: '/home', factory: _$HomeRouteData._fromState),
|
||||
],
|
||||
),
|
||||
StatefulShellBranchData.$branch(
|
||||
navigatorKey: TendersBranch.$navigatorKey,
|
||||
|
||||
routes: [
|
||||
GoRouteData.$route(
|
||||
path: '/tenders',
|
||||
|
||||
factory: _$TendersRouteData._fromState,
|
||||
),
|
||||
],
|
||||
),
|
||||
StatefulShellBranchData.$branch(
|
||||
navigatorKey: ProfileBranch.$navigatorKey,
|
||||
|
||||
routes: [
|
||||
GoRouteData.$route(
|
||||
path: '/profile',
|
||||
|
||||
factory: _$ProfileRouteData._fromState,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
extension $AppShellRouteDataExtension on AppShellRouteData {
|
||||
static AppShellRouteData _fromState(GoRouterState state) =>
|
||||
const AppShellRouteData();
|
||||
}
|
||||
|
||||
mixin _$HomeRouteData on GoRouteData {
|
||||
static HomeRouteData _fromState(GoRouterState state) => const HomeRouteData();
|
||||
|
||||
@override
|
||||
String get location => GoRouteData.$location('/home');
|
||||
|
||||
@override
|
||||
void go(BuildContext context) => context.go(location);
|
||||
|
||||
@override
|
||||
Future<T?> push<T>(BuildContext context) => context.push<T>(location);
|
||||
|
||||
@override
|
||||
void pushReplacement(BuildContext context) =>
|
||||
context.pushReplacement(location);
|
||||
|
||||
@override
|
||||
void replace(BuildContext context) => context.replace(location);
|
||||
}
|
||||
|
||||
mixin _$TendersRouteData on GoRouteData {
|
||||
static TendersRouteData _fromState(GoRouterState state) =>
|
||||
const TendersRouteData();
|
||||
|
||||
@override
|
||||
String get location => GoRouteData.$location('/tenders');
|
||||
|
||||
@override
|
||||
void go(BuildContext context) => context.go(location);
|
||||
|
||||
@override
|
||||
Future<T?> push<T>(BuildContext context) => context.push<T>(location);
|
||||
|
||||
@override
|
||||
void pushReplacement(BuildContext context) =>
|
||||
context.pushReplacement(location);
|
||||
|
||||
@override
|
||||
void replace(BuildContext context) => context.replace(location);
|
||||
}
|
||||
|
||||
mixin _$ProfileRouteData on GoRouteData {
|
||||
static ProfileRouteData _fromState(GoRouterState state) =>
|
||||
const ProfileRouteData();
|
||||
|
||||
@override
|
||||
String get location => GoRouteData.$location('/profile');
|
||||
|
||||
@override
|
||||
void go(BuildContext context) => context.go(location);
|
||||
|
||||
@override
|
||||
Future<T?> push<T>(BuildContext context) => context.push<T>(location);
|
||||
|
||||
@override
|
||||
void pushReplacement(BuildContext context) =>
|
||||
context.pushReplacement(location);
|
||||
|
||||
@override
|
||||
void replace(BuildContext context) => context.replace(location);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// Shell screen with bottom navigation
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../utils/size_config.dart';
|
||||
|
||||
class AppShellScreen extends StatelessWidget {
|
||||
const AppShellScreen({required this.navigationShell, super.key});
|
||||
|
||||
final StatefulNavigationShell navigationShell;
|
||||
|
||||
void _gotoBranch(int index) {
|
||||
navigationShell.goBranch(
|
||||
index,
|
||||
initialLocation: index == navigationShell.currentIndex,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: navigationShell,
|
||||
bottomNavigationBar: Container(
|
||||
height: 72.0.h(),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFE3E3E3),
|
||||
border: Border.fromBorderSide(
|
||||
BorderSide(color: const Color(0xFFE3E3E3)),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
_bottomNavigationItem(
|
||||
context: context,
|
||||
text: 'Home',
|
||||
isActive: navigationShell.currentIndex == 0,
|
||||
onTap: () => _gotoBranch(0),
|
||||
iconPath: 'assets/icons/home.svg',
|
||||
activeIconPath: 'assets/icons/homeActive.svg',
|
||||
),
|
||||
_bottomNavigationItem(
|
||||
context: context,
|
||||
text: 'Tenders',
|
||||
isActive: navigationShell.currentIndex == 1,
|
||||
onTap: () => _gotoBranch(1),
|
||||
iconPath: 'assets/icons/task_square.svg',
|
||||
activeIconPath: 'assets/icons/task-square_active.svg',
|
||||
),
|
||||
_bottomNavigationItem(
|
||||
context: context,
|
||||
text: 'Profile',
|
||||
isActive: navigationShell.currentIndex == 2,
|
||||
onTap: () => _gotoBranch(2),
|
||||
iconPath: 'assets/icons/profile-circle.svg',
|
||||
activeIconPath: 'assets/icons/profile-circle_active.svg',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _bottomNavigationItem({
|
||||
required BuildContext context,
|
||||
required String text,
|
||||
required bool isActive,
|
||||
required VoidCallback onTap,
|
||||
required String iconPath,
|
||||
required String activeIconPath,
|
||||
}) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: SizedBox(
|
||||
width: 64.0.w(),
|
||||
height: 72.0.h(),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 12.0.h(), bottom: 14.0.h()),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SvgPicture.asset(isActive ? activeIconPath : iconPath),
|
||||
Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 12.0.sp(),
|
||||
fontWeight: FontWeight.w400,
|
||||
color:
|
||||
isActive
|
||||
? const Color(0xFF0164FF)
|
||||
: const Color(0xFF777777),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user