import 'package:audio_service/audio_service.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; import 'app/router.dart'; import 'app/theme.dart'; import 'audio/nk_audio_handler.dart'; import 'audio/player_providers.dart'; import 'audio/sound_settings.dart'; import 'core/env.dart'; import 'data/user_library.dart'; import 'features/support/support_screen.dart'; import 'offline/download_store.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); if (Env.hasSupabase) { await Supabase.initialize(url: Env.supabaseUrl, publishableKey: Env.supabasePublishableKey); } final prefs = await SharedPreferences.getInstance(); final audioHandler = await AudioService.init( builder: NkAudioHandler.new, config: const AudioServiceConfig( androidNotificationChannelId: 'com.metatroncubesolutions.nanga_kathai.playback', androidNotificationChannelName: 'Nanga Kathai playback', androidNotificationOngoing: true, androidStopForegroundOnPause: true, ), ); final downloads = await DownloadStore.open(); audioHandler.localSource = (item) => downloads.sourceFor(item.id, tag: item); runApp( ProviderScope( overrides: [ sharedPrefsProvider.overrideWithValue(prefs), audioHandlerProvider.overrideWithValue(audioHandler), downloadStoreProvider.overrideWithValue(downloads), ], child: const NangaKathaiApp(), ), ); } class NangaKathaiApp extends ConsumerWidget { const NangaKathaiApp({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { ref.watch(soundSettingsProvider); // apply the saved equalizer and boost at startup ref.read(supportProvider); // finish any support payment that completed while the app was closed final router = ref.watch(routerProvider); // Guests hear a short preview of each song, then are invited to sign up. ref.listen(positionProvider, (_, next) { final position = next.value ?? Duration.zero; if (!Env.hasSupabase || isSignedIn || position < guestPreview) return; final handler = ref.read(audioHandlerProvider); if (!handler.playbackState.value.playing) return; handler ..pause() ..seek(Duration.zero); final context = router.routerDelegate.navigatorKey.currentContext; if (context != null) _showPreviewEnded(context); }); return MaterialApp.router( title: 'Nanga Kathai', debugShowCheckedModeBanner: false, theme: buildNkTheme(), routerConfig: router, ); } } const guestPreview = Duration(seconds: 30); void _showPreviewEnded(BuildContext context) { showModalBottomSheet( context: context, backgroundColor: NkColors.surface, showDragHandle: true, builder: (sheet) => SafeArea( child: Padding( padding: const EdgeInsets.fromLTRB(24, 0, 24, 24), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text('Enjoying the song?', style: Theme.of(sheet).textTheme.headlineSmall), const SizedBox(height: 8), const Text( 'Previews are 30 seconds. Create a free account to listen to every song in full.', style: TextStyle(color: NkColors.muted, height: 1.5), ), const SizedBox(height: 20), FilledButton( onPressed: () { Navigator.pop(sheet); GoRouter.of(context).push('/login?mode=signup'); }, child: const Text('Create free account'), ), TextButton( onPressed: () { Navigator.pop(sheet); GoRouter.of(context).push('/login'); }, child: const Text('I already have an account'), ), ], ), ), ), ); }