2020-10-14 19:09:16 +00:00
|
|
|
import 'dart:async';
|
|
|
|
|
2020-06-23 19:23:12 +00:00
|
|
|
import 'package:audio_service/audio_service.dart';
|
2020-09-18 17:36:41 +00:00
|
|
|
import 'package:custom_navigator/custom_navigator.dart';
|
2020-06-23 19:23:12 +00:00
|
|
|
import 'package:flutter/material.dart';
|
2020-07-16 20:25:30 +00:00
|
|
|
import 'package:flutter/rendering.dart';
|
2020-10-09 18:52:45 +00:00
|
|
|
import 'package:flutter/services.dart';
|
2020-09-18 17:36:41 +00:00
|
|
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
2020-10-09 18:52:45 +00:00
|
|
|
import 'package:freezer/api/cache.dart';
|
2020-10-15 18:37:36 +00:00
|
|
|
import 'package:freezer/api/definitions.dart';
|
2020-06-23 19:23:12 +00:00
|
|
|
import 'package:freezer/ui/library.dart';
|
|
|
|
import 'package:freezer/ui/login_screen.dart';
|
|
|
|
import 'package:freezer/ui/search.dart';
|
2020-09-18 17:36:41 +00:00
|
|
|
import 'package:i18n_extension/i18n_widget.dart';
|
2020-06-23 19:23:12 +00:00
|
|
|
import 'package:move_to_background/move_to_background.dart';
|
2020-09-18 17:36:41 +00:00
|
|
|
import 'package:freezer/translations.i18n.dart';
|
2020-10-16 18:54:04 +00:00
|
|
|
import 'package:quick_actions/quick_actions.dart';
|
2020-10-14 19:09:16 +00:00
|
|
|
import 'package:uni_links/uni_links.dart';
|
2020-06-23 19:23:12 +00:00
|
|
|
|
|
|
|
import 'api/deezer.dart';
|
|
|
|
import 'api/download.dart';
|
|
|
|
import 'api/player.dart';
|
2020-09-18 17:36:41 +00:00
|
|
|
import 'settings.dart';
|
2020-06-23 19:23:12 +00:00
|
|
|
import 'ui/home_screen.dart';
|
2020-09-18 17:36:41 +00:00
|
|
|
import 'ui/player_bar.dart';
|
2020-07-16 20:25:30 +00:00
|
|
|
|
2020-06-23 19:23:12 +00:00
|
|
|
Function updateTheme;
|
2020-07-16 20:25:30 +00:00
|
|
|
Function logOut;
|
2020-06-23 19:23:12 +00:00
|
|
|
GlobalKey<NavigatorState> mainNavigatorKey = GlobalKey<NavigatorState>();
|
|
|
|
GlobalKey<NavigatorState> navigatorKey;
|
|
|
|
|
|
|
|
|
2020-09-18 17:36:41 +00:00
|
|
|
void main() async {
|
2020-06-23 19:23:12 +00:00
|
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
|
|
|
|
|
|
//Initialize globals
|
|
|
|
settings = await Settings().loadSettings();
|
|
|
|
await downloadManager.init();
|
2020-10-09 18:52:45 +00:00
|
|
|
cache = await Cache.load();
|
2020-06-23 19:23:12 +00:00
|
|
|
|
|
|
|
runApp(FreezerApp());
|
|
|
|
}
|
|
|
|
|
|
|
|
class FreezerApp extends StatefulWidget {
|
|
|
|
@override
|
|
|
|
_FreezerAppState createState() => _FreezerAppState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _FreezerAppState extends State<FreezerApp> {
|
2020-10-14 19:09:16 +00:00
|
|
|
|
2020-06-23 19:23:12 +00:00
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
//Make update theme global
|
|
|
|
updateTheme = _updateTheme;
|
2020-10-16 18:54:04 +00:00
|
|
|
_updateTheme();
|
2020-06-23 19:23:12 +00:00
|
|
|
super.initState();
|
|
|
|
}
|
|
|
|
|
2020-08-16 20:17:22 +00:00
|
|
|
@override
|
|
|
|
void dispose() {
|
|
|
|
super.dispose();
|
|
|
|
}
|
|
|
|
|
2020-06-23 19:23:12 +00:00
|
|
|
void _updateTheme() {
|
|
|
|
setState(() {
|
|
|
|
settings.themeData;
|
|
|
|
});
|
2020-10-16 18:54:04 +00:00
|
|
|
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
|
|
|
|
systemNavigationBarColor: settings.themeData.bottomAppBarColor,
|
2020-10-20 19:55:14 +00:00
|
|
|
systemNavigationBarIconBrightness: settings.isDark? Brightness.light : Brightness.dark
|
2020-10-16 18:54:04 +00:00
|
|
|
));
|
2020-06-23 19:23:12 +00:00
|
|
|
}
|
|
|
|
|
2020-09-18 17:36:41 +00:00
|
|
|
Locale _locale() {
|
|
|
|
if (settings.language == null || settings.language.split('_').length < 2) return null;
|
|
|
|
return Locale(settings.language.split('_')[0], settings.language.split('_')[1]);
|
|
|
|
}
|
|
|
|
|
2020-06-23 19:23:12 +00:00
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return MaterialApp(
|
2020-09-18 17:36:41 +00:00
|
|
|
title: 'Freezer',
|
2020-06-23 19:23:12 +00:00
|
|
|
theme: settings.themeData,
|
2020-09-18 17:36:41 +00:00
|
|
|
localizationsDelegates: [
|
|
|
|
GlobalMaterialLocalizations.delegate,
|
|
|
|
GlobalWidgetsLocalizations.delegate,
|
|
|
|
GlobalCupertinoLocalizations.delegate,
|
|
|
|
],
|
|
|
|
supportedLocales: supportedLocales,
|
2020-06-23 19:23:12 +00:00
|
|
|
home: WillPopScope(
|
|
|
|
onWillPop: () async {
|
|
|
|
//For some reason AudioServiceWidget caused the app to freeze after 2 back button presses. "fix"
|
|
|
|
if (navigatorKey.currentState.canPop()) {
|
|
|
|
await navigatorKey.currentState.maybePop();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
await MoveToBackground.moveTaskToBack();
|
|
|
|
return false;
|
|
|
|
},
|
2020-09-18 17:36:41 +00:00
|
|
|
child: I18n(
|
|
|
|
initialLocale: _locale(),
|
|
|
|
child: LoginMainWrapper(),
|
|
|
|
),
|
2020-06-23 19:23:12 +00:00
|
|
|
),
|
|
|
|
navigatorKey: mainNavigatorKey,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Wrapper for login and main screen.
|
|
|
|
class LoginMainWrapper extends StatefulWidget {
|
|
|
|
@override
|
|
|
|
_LoginMainWrapperState createState() => _LoginMainWrapperState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _LoginMainWrapperState extends State<LoginMainWrapper> {
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
if (settings.arl != null) {
|
|
|
|
playerHelper.start();
|
|
|
|
//Load token on background
|
|
|
|
deezerAPI.arl = settings.arl;
|
|
|
|
settings.offlineMode = true;
|
2020-10-09 18:52:45 +00:00
|
|
|
deezerAPI.authorize().then((b) async {
|
2020-06-23 19:23:12 +00:00
|
|
|
if (b) setState(() => settings.offlineMode = false);
|
|
|
|
});
|
|
|
|
}
|
2020-07-16 20:25:30 +00:00
|
|
|
//Global logOut function
|
|
|
|
logOut = _logOut;
|
|
|
|
|
2020-06-23 19:23:12 +00:00
|
|
|
super.initState();
|
|
|
|
}
|
|
|
|
|
2020-07-16 20:25:30 +00:00
|
|
|
Future _logOut() async {
|
|
|
|
setState(() {
|
|
|
|
settings.arl = null;
|
|
|
|
settings.offlineMode = true;
|
|
|
|
deezerAPI = new DeezerAPI();
|
|
|
|
});
|
|
|
|
await settings.save();
|
|
|
|
}
|
|
|
|
|
2020-06-23 19:23:12 +00:00
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
if (settings.arl == null)
|
2020-09-18 17:36:41 +00:00
|
|
|
return LoginWidget(
|
|
|
|
callback: () => setState(() => {}),
|
|
|
|
);
|
2020-06-23 19:23:12 +00:00
|
|
|
return MainScreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class MainScreen extends StatefulWidget {
|
|
|
|
@override
|
|
|
|
_MainScreenState createState() => _MainScreenState();
|
|
|
|
}
|
|
|
|
|
2020-10-14 19:09:16 +00:00
|
|
|
class _MainScreenState extends State<MainScreen> with SingleTickerProviderStateMixin{
|
2020-09-18 17:36:41 +00:00
|
|
|
List<Widget> _screens = [HomeScreen(), SearchScreen(), LibraryScreen()];
|
2020-06-23 19:23:12 +00:00
|
|
|
int _selected = 0;
|
2020-10-14 19:09:16 +00:00
|
|
|
StreamSubscription _urlLinkStream;
|
2020-06-23 19:23:12 +00:00
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
navigatorKey = GlobalKey<NavigatorState>();
|
2020-10-14 19:09:16 +00:00
|
|
|
|
2020-10-16 18:54:04 +00:00
|
|
|
//Start with parameters
|
|
|
|
_setupUniLinks();
|
2020-10-15 18:37:36 +00:00
|
|
|
_loadPreloadInfo();
|
2020-10-16 18:54:04 +00:00
|
|
|
_prepareQuickActions();
|
2020-10-15 18:37:36 +00:00
|
|
|
|
2020-06-23 19:23:12 +00:00
|
|
|
super.initState();
|
|
|
|
}
|
|
|
|
|
2020-10-16 18:54:04 +00:00
|
|
|
void _prepareQuickActions() {
|
|
|
|
final QuickActions quickActions = QuickActions();
|
|
|
|
quickActions.initialize((type) {
|
|
|
|
if (type != null)
|
|
|
|
_startPreload(type);
|
|
|
|
});
|
|
|
|
|
|
|
|
//Actions
|
|
|
|
quickActions.setShortcutItems([
|
|
|
|
ShortcutItem(type: 'favorites', localizedTitle: 'Favorites'.i18n, icon: 'ic_favorites'),
|
|
|
|
ShortcutItem(type: 'flow', localizedTitle: 'Flow'.i18n, icon: 'ic_flow'),
|
|
|
|
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void _startPreload(String type) async {
|
|
|
|
await deezerAPI.authorize();
|
|
|
|
if (type == 'flow') {
|
|
|
|
await playerHelper.playFromSmartTrackList(SmartTrackList(id: 'flow'));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (type == 'favorites') {
|
|
|
|
Playlist p = await deezerAPI.fullPlaylist(deezerAPI.favoritesPlaylistId);
|
|
|
|
playerHelper.playFromPlaylist(p, p.tracks[0].id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-15 18:37:36 +00:00
|
|
|
void _loadPreloadInfo() async {
|
|
|
|
String info = await DownloadManager.platform.invokeMethod('getPreloadInfo');
|
|
|
|
if (info != null) {
|
|
|
|
//Used if started from android auto
|
|
|
|
await deezerAPI.authorize();
|
2020-10-16 18:54:04 +00:00
|
|
|
_startPreload(info);
|
2020-10-15 18:37:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-14 19:09:16 +00:00
|
|
|
@override
|
|
|
|
void dispose() {
|
|
|
|
if (_urlLinkStream != null)
|
|
|
|
_urlLinkStream.cancel();
|
|
|
|
super.dispose();
|
|
|
|
}
|
|
|
|
|
2020-10-16 18:54:04 +00:00
|
|
|
void _setupUniLinks() async {
|
2020-10-14 19:09:16 +00:00
|
|
|
//Listen to URLs
|
|
|
|
_urlLinkStream = getUriLinksStream().listen((Uri uri) {
|
|
|
|
openScreenByURL(context, uri.toString());
|
|
|
|
}, onError: (err) {});
|
|
|
|
//Get initial link on cold start
|
|
|
|
try {
|
|
|
|
String link = await getInitialLink();
|
|
|
|
if (link != null && link.length > 4)
|
|
|
|
openScreenByURL(context, link);
|
|
|
|
} catch (e) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-23 19:23:12 +00:00
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Scaffold(
|
2020-10-19 19:28:45 +00:00
|
|
|
bottomNavigationBar: Column(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: <Widget>[
|
|
|
|
PlayerBar(),
|
|
|
|
BottomNavigationBar(
|
|
|
|
backgroundColor: Theme.of(context).bottomAppBarColor,
|
|
|
|
currentIndex: _selected,
|
|
|
|
onTap: (int s) async {
|
|
|
|
|
|
|
|
//Pop all routes until home screen
|
|
|
|
while (navigatorKey.currentState.canPop()) {
|
2020-06-23 19:23:12 +00:00
|
|
|
await navigatorKey.currentState.maybePop();
|
2020-10-19 19:28:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
await navigatorKey.currentState.maybePop();
|
|
|
|
setState(() {
|
|
|
|
_selected = s;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
selectedItemColor: Theme.of(context).primaryColor,
|
|
|
|
items: <BottomNavigationBarItem>[
|
|
|
|
BottomNavigationBarItem(
|
|
|
|
icon: Icon(Icons.home), title: Text('Home'.i18n)),
|
|
|
|
BottomNavigationBarItem(
|
|
|
|
icon: Icon(Icons.search),
|
|
|
|
title: Text('Search'.i18n),
|
|
|
|
),
|
|
|
|
BottomNavigationBarItem(
|
|
|
|
icon: Icon(Icons.library_music), title: Text('Library'.i18n))
|
|
|
|
],
|
|
|
|
)
|
|
|
|
],
|
|
|
|
),
|
|
|
|
body: AudioServiceWidget(
|
|
|
|
child: CustomNavigator(
|
|
|
|
navigatorKey: navigatorKey,
|
|
|
|
home: _screens[_selected],
|
|
|
|
pageRoute: PageRoutes.materialPageRoute,
|
2020-06-23 19:23:12 +00:00
|
|
|
),
|
2020-10-19 19:28:45 +00:00
|
|
|
));
|
2020-06-23 19:23:12 +00:00
|
|
|
}
|
|
|
|
}
|