- Flutter app (Android/iOS): home, explore, albums, search, player with equalizer, mini player, sign up/sign in with email codes, profile, encrypted offline downloads, About page - server/: one-command deploy of self-hosted Supabase behind HestiaCP/nginx (or Caddy), migrations, backups, email templates - supabase/migrations: schema, row-level security, profiles - tools/: song scanner and importer Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
37 lines
1.3 KiB
Dart
37 lines
1.3 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
import 'mini_player.dart';
|
|
|
|
/// Bottom tabs (Home, Explore, Library, Downloads) with the mini player above them.
|
|
class AppShell extends StatelessWidget {
|
|
const AppShell({super.key, required this.shell});
|
|
|
|
final StatefulNavigationShell shell;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
body: shell,
|
|
bottomNavigationBar: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
const MiniPlayer(),
|
|
NavigationBar(
|
|
selectedIndex: shell.currentIndex,
|
|
onDestinationSelected: (i) => shell.goBranch(i, initialLocation: i == shell.currentIndex),
|
|
destinations: const [
|
|
NavigationDestination(icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home_rounded), label: 'Home'),
|
|
NavigationDestination(icon: Icon(Icons.search), selectedIcon: Icon(Icons.search), label: 'Explore'),
|
|
NavigationDestination(
|
|
icon: Icon(Icons.library_music_outlined), selectedIcon: Icon(Icons.library_music), label: 'Library'),
|
|
NavigationDestination(
|
|
icon: Icon(Icons.download_outlined), selectedIcon: Icon(Icons.download_rounded), label: 'Downloads'),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|