Last active
February 4, 2025 14:20
-
-
Save JohanScheepers/0164921fc4306a9ada7e0e3125cede06 to your computer and use it in GitHub Desktop.
Riverpod Gorouter navigation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:flutter_riverpod/flutter_riverpod.dart'; | |
import 'package:go_router/go_router.dart'; | |
import 'dart:async'; | |
void main() { | |
runApp(const ProviderScope(child: HomeAutoApp())); | |
} | |
class HomeAutoApp extends StatelessWidget { | |
const HomeAutoApp({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp.router( | |
debugShowCheckedModeBanner: false, | |
routeInformationProvider: AppRoutes.router.routeInformationProvider, | |
routeInformationParser: AppRoutes.router.routeInformationParser, | |
routerDelegate: AppRoutes.router.routerDelegate, | |
); | |
} | |
} | |
//Splash Page | |
class SplashPage extends StatefulWidget { | |
const SplashPage({super.key}); | |
static const String route = "/splash"; | |
@override | |
State<SplashPage> createState() => _SplashPageState(); | |
} | |
class _SplashPageState extends State<SplashPage> { | |
Timer durationTimer = Timer(Duration.zero, () {}); | |
@override | |
void dispose() { | |
durationTimer.cancel(); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
durationTimer = Timer(Duration(seconds: 2), () { | |
GoRouter.of(Utils.mainNav.currentContext!).go(HomePage.route); | |
}); | |
return Scaffold( | |
body: TextBoxDec( | |
text: | |
'Have you ever been asked to perform a task that would be easier or more efficient with a specialized tool or program?')); | |
} | |
} | |
//Main Page | |
class MainPage extends StatelessWidget { | |
final Widget child; | |
const MainPage({super.key, required this.child}); | |
static const String route = "/main"; | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
body: Flex( | |
direction: Axis.vertical, | |
children: [ | |
Expanded( | |
child: SafeArea(child: child), | |
), | |
const HomeAutomationBottomMenu() | |
], | |
), | |
); | |
} | |
} | |
//App Routes file | |
class AppRoutes { | |
static final router = GoRouter( | |
routerNeglect: true, | |
initialLocation: SplashPage.route, | |
navigatorKey: Utils.mainNav, | |
routes: [ | |
GoRoute( | |
parentNavigatorKey: Utils.mainNav, | |
path: SplashPage.route, | |
builder: (context, state) { | |
return const SplashPage(); | |
}, | |
), | |
ShellRoute( | |
navigatorKey: Utils.tabNav, | |
builder: (context, state, child) { | |
return MainPage(child: child); | |
}, | |
routes: [ | |
GoRoute( | |
parentNavigatorKey: Utils.tabNav, | |
path: HomePage.route, | |
pageBuilder: (context, state) { | |
return const NoTransitionPage( | |
child: HomePage(), | |
); | |
}, | |
), | |
GoRoute( | |
parentNavigatorKey: Utils.tabNav, | |
path: RoomsPage.route, | |
pageBuilder: (context, state) { | |
return const NoTransitionPage( | |
child: RoomsPage(), | |
); | |
}, | |
), | |
GoRoute( | |
parentNavigatorKey: Utils.tabNav, | |
path: DevicesPage.route, | |
pageBuilder: (context, state) { | |
return const NoTransitionPage( | |
child: DevicesPage(), | |
); | |
}, | |
), | |
GoRoute( | |
parentNavigatorKey: Utils.tabNav, | |
path: SettingsPage.route, | |
pageBuilder: (context, state) { | |
return const NoTransitionPage( | |
child: SettingsPage(), | |
); | |
}, | |
), | |
]), | |
]); | |
} | |
//BottomBarMenuItem Model | |
class BottomBarMenuItemModel { | |
final IconData iconOption; | |
final String label; | |
final String route; | |
final bool isSelected; | |
const BottomBarMenuItemModel({ | |
required this.iconOption, | |
this.label = '', | |
required this.route, | |
this.isSelected = false, | |
}); | |
BottomBarMenuItemModel copyWith({ | |
IconData? iconOption, | |
String? label, | |
String? route, | |
bool? isSelected, | |
}) { | |
return BottomBarMenuItemModel( | |
iconOption: iconOption ?? this.iconOption, | |
route: route ?? this.route, | |
label: label ?? this.label, | |
isSelected: isSelected ?? this.isSelected, | |
); | |
} | |
} | |
//PROVIDER | |
final bottomBarMenuProvider = | |
StateNotifierProvider<BottomBarMenuViewModel, List<BottomBarMenuItemModel>>( | |
(ref) { | |
final navItems = ref.read(bottomBarRepositoryProvider).getBottomBarNavItems(); | |
return BottomBarMenuViewModel(navItems, ref); | |
}); | |
final bottomBarRepositoryProvider = Provider((ref) { | |
return BottomMenuBarRepository(); | |
}); | |
//REPOSITORY | |
class BottomMenuBarRepository { | |
List<BottomBarMenuItemModel> getBottomBarNavItems() { | |
return const [ | |
BottomBarMenuItemModel( | |
iconOption: Icons.home, | |
route: HomePage.route, | |
isSelected: true, | |
), | |
BottomBarMenuItemModel( | |
iconOption: Icons.door_back_door, | |
route: RoomsPage.route, | |
), | |
BottomBarMenuItemModel( | |
iconOption: Icons.devices, | |
route: DevicesPage.route, | |
), | |
BottomBarMenuItemModel( | |
iconOption: Icons.build, | |
route: SettingsPage.route, | |
) | |
]; | |
} | |
} | |
//VIEW MODEL | |
class BottomBarMenuViewModel | |
extends StateNotifier<List<BottomBarMenuItemModel>> { | |
final Ref ref; | |
BottomBarMenuViewModel(super.state, this.ref); | |
void selectedItem(BottomBarMenuItemModel selectedItem) { | |
state = state.map((item) { | |
return item.copyWith( | |
isSelected: item.route == selectedItem.route, | |
); | |
}).toList(); | |
GoRouter.of(Utils.tabNav.currentContext!).go(selectedItem.route); | |
} | |
} | |
//Bottom menu | |
class HomeAutomationBottomMenu extends ConsumerWidget { | |
const HomeAutomationBottomMenu({super.key}); | |
@override | |
Widget build(BuildContext context, WidgetRef ref) { | |
final menuItems = ref.watch(bottomBarMenuProvider); | |
return Flex( | |
direction: Axis.horizontal, | |
mainAxisAlignment: MainAxisAlignment.spaceAround, | |
children: menuItems.map((e) { | |
return IconButton( | |
onPressed: () { | |
ref.read(bottomBarMenuProvider.notifier).selectedItem(e); | |
}, | |
icon: Icon( | |
e.iconOption, | |
color: e.isSelected | |
? Theme.of(context).colorScheme.primary | |
: Theme.of(context).iconTheme.color, | |
)); | |
}).toList()); | |
} | |
} | |
// Home Page | |
class HomePage extends StatelessWidget { | |
const HomePage({super.key}); | |
static const String route = '/home'; | |
@override | |
Widget build(BuildContext context) { | |
return TextBoxDec(text: 'So, what were you looking for?'); | |
} | |
} | |
//Rooms Page | |
class RoomsPage extends StatelessWidget { | |
const RoomsPage({super.key}); | |
static const String route = '/room'; | |
@override | |
Widget build(BuildContext context) { | |
return TextBoxDec( | |
text: | |
'We build software tailored to your unique business processes. Achieve maximum efficiency and unlock your full potential'); | |
} | |
} | |
//Devices Page | |
class DevicesPage extends StatelessWidget { | |
const DevicesPage({super.key}); | |
static const String route = '/devices'; | |
@override | |
Widget build(BuildContext context) { | |
return TextBoxDec(text: 'Might be easier than you think'); | |
} | |
} | |
//Settings Page | |
class SettingsPage extends StatelessWidget { | |
const SettingsPage({super.key}); | |
static const String route = '/settings'; | |
@override | |
Widget build(BuildContext context) { | |
return TextBoxDec( | |
text: 'Give us a call', | |
); | |
} | |
} | |
class TextBoxDec extends StatelessWidget { | |
const TextBoxDec({ | |
super.key, | |
required this.text, | |
}); | |
final String text; | |
@override | |
Widget build(BuildContext context) { | |
return Center( | |
child: SizedBox( | |
width: 300, | |
height: 150, | |
child: DecoratedBox( | |
decoration: BoxDecoration( | |
color: Colors.lightGreen, | |
borderRadius: BorderRadius.circular(15), | |
border: Border.all(width: 5, color: Colors.blue)), | |
child: Padding( | |
padding: const EdgeInsets.all(16.0), | |
child: Center(child: Text(text)), | |
), | |
), | |
), | |
); | |
} | |
} | |
//Utils file | |
class Utils { | |
static final mainNav = GlobalKey<NavigatorState>(); | |
static final tabNav = GlobalKey<NavigatorState>(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment