Initial Flutter scaffold: Riverpod + GoRouter + Dio
This commit is contained in:
22
lib/app/app.dart
Normal file
22
lib/app/app.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'router.dart';
|
||||
import '../config/theme.dart';
|
||||
|
||||
class NetworkApp extends ConsumerWidget {
|
||||
const NetworkApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final router = ref.watch(routerProvider);
|
||||
|
||||
return MaterialApp.router(
|
||||
title: 'Network App',
|
||||
theme: AppTheme.light,
|
||||
darkTheme: AppTheme.dark,
|
||||
themeMode: ThemeMode.system,
|
||||
routerConfig: router,
|
||||
debugShowCheckedModeBanner: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
143
lib/app/router.dart
Normal file
143
lib/app/router.dart
Normal file
@@ -0,0 +1,143 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../features/auth/presentation/login_screen.dart';
|
||||
import '../features/auth/presentation/register_screen.dart';
|
||||
import '../features/clients/presentation/clients_screen.dart';
|
||||
import '../features/clients/presentation/client_detail_screen.dart';
|
||||
import '../features/clients/presentation/client_form_screen.dart';
|
||||
import '../features/emails/presentation/emails_screen.dart';
|
||||
import '../features/emails/presentation/email_compose_screen.dart';
|
||||
import '../features/events/presentation/events_screen.dart';
|
||||
import '../shared/providers/auth_provider.dart';
|
||||
|
||||
final routerProvider = Provider<GoRouter>((ref) {
|
||||
final authState = ref.watch(authStateProvider);
|
||||
|
||||
return GoRouter(
|
||||
initialLocation: '/',
|
||||
redirect: (context, state) {
|
||||
final isLoggedIn = authState.valueOrNull?.isAuthenticated ?? false;
|
||||
final isAuthRoute = state.matchedLocation == '/login' ||
|
||||
state.matchedLocation == '/register';
|
||||
|
||||
if (!isLoggedIn && !isAuthRoute) {
|
||||
return '/login';
|
||||
}
|
||||
|
||||
if (isLoggedIn && isAuthRoute) {
|
||||
return '/';
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
routes: [
|
||||
// Auth routes
|
||||
GoRoute(
|
||||
path: '/login',
|
||||
builder: (context, state) => const LoginScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/register',
|
||||
builder: (context, state) => const RegisterScreen(),
|
||||
),
|
||||
|
||||
// Main app routes
|
||||
ShellRoute(
|
||||
builder: (context, state, child) => MainShell(child: child),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/',
|
||||
builder: (context, state) => const ClientsScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/clients/new',
|
||||
builder: (context, state) => const ClientFormScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/clients/:id',
|
||||
builder: (context, state) => ClientDetailScreen(
|
||||
clientId: state.pathParameters['id']!,
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/clients/:id/edit',
|
||||
builder: (context, state) => ClientFormScreen(
|
||||
clientId: state.pathParameters['id'],
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/emails',
|
||||
builder: (context, state) => const EmailsScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/emails/compose',
|
||||
builder: (context, state) => EmailComposeScreen(
|
||||
clientId: state.uri.queryParameters['clientId'],
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/events',
|
||||
builder: (context, state) => const EventsScreen(),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
class MainShell extends StatelessWidget {
|
||||
final Widget child;
|
||||
|
||||
const MainShell({super.key, required this.child});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: child,
|
||||
bottomNavigationBar: NavigationBar(
|
||||
selectedIndex: _getSelectedIndex(context),
|
||||
onDestinationSelected: (index) => _onDestinationSelected(context, index),
|
||||
destinations: const [
|
||||
NavigationDestination(
|
||||
icon: Icon(Icons.people_outline),
|
||||
selectedIcon: Icon(Icons.people),
|
||||
label: 'Clients',
|
||||
),
|
||||
NavigationDestination(
|
||||
icon: Icon(Icons.email_outline),
|
||||
selectedIcon: Icon(Icons.email),
|
||||
label: 'Emails',
|
||||
),
|
||||
NavigationDestination(
|
||||
icon: Icon(Icons.event_outline),
|
||||
selectedIcon: Icon(Icons.event),
|
||||
label: 'Events',
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
int _getSelectedIndex(BuildContext context) {
|
||||
final location = GoRouterState.of(context).matchedLocation;
|
||||
if (location.startsWith('/emails')) return 1;
|
||||
if (location.startsWith('/events')) return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _onDestinationSelected(BuildContext context, int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
context.go('/');
|
||||
break;
|
||||
case 1:
|
||||
context.go('/emails');
|
||||
break;
|
||||
case 2:
|
||||
context.go('/events');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user