Files
zapstore/lib/main.dart
T
2024-02-22 14:21:21 -03:00

284 lines
8.7 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_data/flutter_data.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:ndk/ndk.dart' as ndk;
import 'package:zapstore/main.data.dart';
import 'package:zapstore/models/release.dart';
import 'package:zapstore/screens/app_detail_screen.dart';
import 'package:zapstore/screens/profile_screen.dart';
import 'package:zapstore/screens/search_screen.dart';
void main() {
runApp(
ProviderScope(
overrides: [
configureRepositoryLocalStorage(
clear: LocalStorageClearStrategy.always),
],
child: const ZapstoreApp(),
),
);
}
class ZapstoreApp extends StatelessWidget {
const ZapstoreApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: goRouter,
debugShowCheckedModeBanner: false,
theme: ThemeData.dark(useMaterial3: true),
);
}
}
// private navigators
final _rootNavigatorKey = GlobalKey<NavigatorState>();
final _searchNavigatorKey = GlobalKey<NavigatorState>(debugLabel: 'search');
final _updatesNavigatorKey = GlobalKey<NavigatorState>(debugLabel: 'updates');
final _profileNavigatorKey = GlobalKey<NavigatorState>(debugLabel: 'profile');
final goRouter = GoRouter(
initialLocation: '/search',
// * Passing a navigatorKey causes an issue on hot reload:
// * https://github.com/flutter/flutter/issues/113757#issuecomment-1518421380
// * However it's still necessary otherwise the navigator pops back to
// * root on hot reload
navigatorKey: _rootNavigatorKey,
// debugLogDiagnostics: true,
routes: [
// Stateful navigation based on:
// https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/stateful_shell_route.dart
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) {
return ScaffoldWithNestedNavigation(navigationShell: navigationShell);
},
branches: [
StatefulShellBranch(
navigatorKey: _searchNavigatorKey,
routes: [
GoRoute(
path: '/search',
pageBuilder: (context, state) => NoTransitionPage(
child: SearchScreen(),
),
routes: [
GoRoute(
path: 'details',
builder: (context, state) =>
AppDetailScreen(release: state.extra as Release),
),
],
),
],
),
StatefulShellBranch(
navigatorKey: _updatesNavigatorKey,
routes: [
GoRoute(
path: '/updates',
pageBuilder: (context, state) => NoTransitionPage(
child: Center(
child: ElevatedButton(
onPressed: () => context.go('/search/details', extra: 1),
child: const Text('Go to the Details screen'),
),
),
),
),
],
),
StatefulShellBranch(
navigatorKey: _profileNavigatorKey,
routes: [
GoRoute(
path: '/profile',
pageBuilder: (context, state) => NoTransitionPage(
child: Center(
child: ProfileScreen(),
),
),
),
],
),
],
),
],
);
final newInitializer = FutureProvider<void>((ref) async {
await ref.read(repositoryInitializerProvider.future);
await ref.read(ndk.frameProvider.notifier).initialize('wss://relay.damus.io');
});
// Stateful navigation based on:
// https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/stateful_shell_route.dart
class ScaffoldWithNestedNavigation extends HookConsumerWidget {
const ScaffoldWithNestedNavigation({
Key? key,
required this.navigationShell,
}) : super(
key: key ?? const ValueKey<String>('ScaffoldWithNestedNavigation'));
final StatefulNavigationShell navigationShell;
void _goBranch(int index) {
navigationShell.goBranch(
index,
// A common pattern when using bottom navigation bars is to support
// navigating to the initial location when tapping the item that is
// already active. This example demonstrates how to support this behavior,
// using the initialLocation parameter of goBranch.
initialLocation: index == navigationShell.currentIndex,
);
}
@override
Widget build(BuildContext context, WidgetRef ref) {
final initializer = ref.watch(newInitializer);
return SafeArea(
child: initializer.when(
data: (_) => LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 450) {
return ScaffoldWithNavigationBar(
body: navigationShell,
selectedIndex: navigationShell.currentIndex,
onDestinationSelected: _goBranch,
);
} else {
return ScaffoldWithNavigationRail(
body: navigationShell,
selectedIndex: navigationShell.currentIndex,
onDestinationSelected: _goBranch,
);
}
},
),
error: (e, _) => Text('error'),
loading: () => CircularProgressIndicator(),
),
);
}
}
class ScaffoldWithNavigationBar extends StatelessWidget {
const ScaffoldWithNavigationBar({
super.key,
required this.body,
required this.selectedIndex,
required this.onDestinationSelected,
});
final Widget body;
final int selectedIndex;
final ValueChanged<int> onDestinationSelected;
@override
Widget build(BuildContext context) {
return Scaffold(
body: body,
bottomNavigationBar: NavigationBar(
selectedIndex: selectedIndex,
labelBehavior: NavigationDestinationLabelBehavior.alwaysHide,
destinations: const [
NavigationDestination(
label: 'Search',
icon: Icon(Icons.search_outlined),
),
NavigationDestination(
label: 'Updates',
icon: Icon(Icons.download_for_offline_outlined),
),
NavigationDestination(
label: 'Profile',
icon: Icon(Icons.person_outline),
),
NavigationDestination(
label: 'Notifications',
icon: Icon(Icons.notifications_outlined),
),
],
onDestinationSelected: onDestinationSelected,
),
);
}
}
class ScaffoldWithNavigationRail extends StatelessWidget {
const ScaffoldWithNavigationRail({
super.key,
required this.body,
required this.selectedIndex,
required this.onDestinationSelected,
});
final Widget body;
final int selectedIndex;
final ValueChanged<int> onDestinationSelected;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: [
NavigationRail(
selectedIndex: selectedIndex,
onDestinationSelected: onDestinationSelected,
labelType: NavigationRailLabelType.all,
destinations: [
NavigationRailDestination(
label: Text('Search'),
icon: Icon(Icons.search_outlined),
),
NavigationRailDestination(
label: Text('Updates'),
icon: Icon(Icons.download_for_offline_outlined),
),
NavigationRailDestination(
label: Text('Profile'),
icon: Icon(Icons.person_outline),
),
],
),
body,
],
),
);
}
}
// const borderColor = Color(0xFF805306);
// const sidebarColor = Color(0xFFF6A00C);
// const backgroundStartColor = Color(0xFFFFD500);
// const backgroundEndColor = Color(0xFFF6A00C);
// final buttonColors = WindowButtonColors(
// iconNormal: const Color(0xFF805306),
// mouseOver: const Color(0xFFF6A00C),
// mouseDown: const Color(0xFF805306),
// iconMouseOver: const Color(0xFF805306),
// iconMouseDown: const Color(0xFFFFD500));
// final closeButtonColors = WindowButtonColors(
// mouseOver: const Color(0xFFD32F2F),
// mouseDown: const Color(0xFFB71C1C),
// iconNormal: const Color(0xFF805306),
// iconMouseOver: Colors.white);
// class WindowButtons extends StatelessWidget {
// const WindowButtons({super.key});
// @override
// Widget build(BuildContext context) {
// return Row(
// children: [
// MinimizeWindowButton(colors: buttonColors),
// MaximizeWindowButton(colors: buttonColors),
// CloseWindowButton(colors: closeButtonColors),
// ],
// );
// }
// }