import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'api.dart'; import 'player.dart'; import 'session.dart'; import 'theme.dart'; import 'widgets.dart'; class _Section { const _Section(this.path, this.label, this.icon); final String path; final String label; final IconData icon; } const _sections = [ _Section('/', 'Overview', Icons.dashboard_outlined), _Section('/songs', 'Songs', Icons.music_note_outlined), _Section('/albums', 'Albums', Icons.album_outlined), _Section('/singers', 'Singers', Icons.mic_none_outlined), _Section('/applications', 'Creators', Icons.how_to_reg_outlined), ]; /// Sidebar (wide screens) or drawer (phones), the page, and the player bar. class AdminShell extends StatelessWidget { const AdminShell({super.key, required this.location, required this.child}); final String location; final Widget child; int get _selected { final i = _sections.lastIndexWhere((s) => s.path == '/' ? location == '/' : location.startsWith(s.path)); return i < 0 ? 0 : i; } @override Widget build(BuildContext context) { final session = AdminSession.instance; return ListenableBuilder( listenable: session, builder: (context, _) { if (session.state != SessionState.admin) { return const Scaffold(body: Center(child: CircularProgressIndicator())); } final wide = MediaQuery.sizeOf(context).width >= 900; final page = Column(children: [Expanded(child: child), const PlayerBar()]); if (!wide) { return Scaffold( appBar: AppBar( backgroundColor: NkColors.surface, title: Text(_sections[_selected].label), ), drawer: Drawer( backgroundColor: NkColors.surface, child: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Padding(padding: EdgeInsets.all(20), child: _Brand()), for (final (i, s) in _sections.indexed) ListTile( leading: Icon(s.icon, color: i == _selected ? NkColors.sun : NkColors.muted), title: Text(s.label), selected: i == _selected, selectedColor: NkColors.sun, onTap: () { Navigator.of(context).pop(); context.go(s.path); }, ), const Spacer(), _Account(email: session.email), ], ), ), ), body: page, ); } return Scaffold( body: Row( children: [ NavigationRail( extended: MediaQuery.sizeOf(context).width >= 1200, minExtendedWidth: 220, selectedIndex: _selected, onDestinationSelected: (i) => context.go(_sections[i].path), leading: const Padding(padding: EdgeInsets.fromLTRB(12, 20, 12, 24), child: _Brand()), trailing: Expanded( child: Align(alignment: Alignment.bottomLeft, child: _Account(email: session.email)), ), destinations: [ for (final s in _sections) NavigationRailDestination(icon: Icon(s.icon), label: Text(s.label)), ], ), const VerticalDivider(width: 1), Expanded(child: page), ], ), ); }, ); } } class _Brand extends StatelessWidget { const _Brand(); @override Widget build(BuildContext context) => Row( mainAxisSize: MainAxisSize.min, children: [ Container( width: 36, height: 36, alignment: Alignment.center, decoration: const BoxDecoration(color: NkColors.sun, shape: BoxShape.circle), child: const Text('NK', style: TextStyle(color: NkColors.ground, fontWeight: FontWeight.w900)), ), if (MediaQuery.sizeOf(context).width >= 1200 || MediaQuery.sizeOf(context).width < 900) ...[ const SizedBox(width: 10), Text('NK Admin', style: Theme.of(context).textTheme.titleLarge), ], ], ); } class _Account extends StatelessWidget { const _Account({required this.email}); final String? email; @override Widget build(BuildContext context) => Padding( padding: const EdgeInsets.all(12), child: Tooltip( message: email ?? '', child: TextButton.icon( onPressed: () async { if (await confirm(context, 'Sign out?', 'You will need a new email code to sign in again.', action: 'Sign out')) { await AdminPlayer.instance.close(); await AdminApi.signOut(); } }, icon: const Icon(Icons.logout, size: 18), label: const Text('Sign out'), ), ), ); }