2020-06-23 19:23:12 +00:00
|
|
|
import 'package:audio_service/audio_service.dart';
|
2020-10-11 20:06:29 +00:00
|
|
|
import 'package:flutter/scheduler.dart';
|
2020-10-09 18:52:45 +00:00
|
|
|
import 'package:freezer/api/download.dart';
|
2020-06-23 19:23:12 +00:00
|
|
|
import 'package:freezer/main.dart';
|
|
|
|
import 'package:freezer/ui/cached_image.dart';
|
2021-02-09 20:14:14 +00:00
|
|
|
import 'package:google_fonts/google_fonts.dart';
|
2020-06-23 19:23:12 +00:00
|
|
|
import 'package:json_annotation/json_annotation.dart';
|
|
|
|
import 'package:path_provider/path_provider.dart';
|
|
|
|
import 'package:ext_storage/ext_storage.dart';
|
|
|
|
import 'package:path/path.dart' as p;
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
|
|
import 'dart:io';
|
|
|
|
import 'dart:convert';
|
2020-10-11 20:06:29 +00:00
|
|
|
import 'dart:async';
|
2020-06-23 19:23:12 +00:00
|
|
|
|
|
|
|
part 'settings.g.dart';
|
|
|
|
|
|
|
|
Settings settings;
|
|
|
|
|
|
|
|
@JsonSerializable()
|
|
|
|
class Settings {
|
|
|
|
|
2020-09-18 17:36:41 +00:00
|
|
|
//Language
|
|
|
|
@JsonKey(defaultValue: null)
|
|
|
|
String language;
|
|
|
|
|
2021-02-09 20:14:14 +00:00
|
|
|
//Main
|
2020-10-19 19:28:45 +00:00
|
|
|
@JsonKey(defaultValue: false)
|
|
|
|
bool ignoreInterruptions;
|
2021-02-09 20:14:14 +00:00
|
|
|
@JsonKey(defaultValue: false)
|
|
|
|
bool enableEqualizer;
|
2020-10-19 19:28:45 +00:00
|
|
|
|
2020-06-23 19:23:12 +00:00
|
|
|
//Account
|
|
|
|
String arl;
|
|
|
|
@JsonKey(ignore: true)
|
|
|
|
bool offlineMode = false;
|
|
|
|
|
|
|
|
//Quality
|
|
|
|
@JsonKey(defaultValue: AudioQuality.MP3_320)
|
|
|
|
AudioQuality wifiQuality;
|
|
|
|
@JsonKey(defaultValue: AudioQuality.MP3_128)
|
|
|
|
AudioQuality mobileQuality;
|
|
|
|
@JsonKey(defaultValue: AudioQuality.FLAC)
|
|
|
|
AudioQuality offlineQuality;
|
|
|
|
@JsonKey(defaultValue: AudioQuality.FLAC)
|
|
|
|
AudioQuality downloadQuality;
|
|
|
|
|
2021-02-09 20:14:14 +00:00
|
|
|
|
2020-06-23 19:23:12 +00:00
|
|
|
//Download options
|
|
|
|
String downloadPath;
|
2020-09-01 14:41:15 +00:00
|
|
|
|
2020-12-04 17:02:50 +00:00
|
|
|
@JsonKey(defaultValue: "%artist% - %title%")
|
2020-09-01 14:41:15 +00:00
|
|
|
String downloadFilename;
|
|
|
|
@JsonKey(defaultValue: true)
|
|
|
|
bool albumFolder;
|
2020-06-23 19:23:12 +00:00
|
|
|
@JsonKey(defaultValue: true)
|
2020-09-01 14:41:15 +00:00
|
|
|
bool artistFolder;
|
|
|
|
@JsonKey(defaultValue: false)
|
|
|
|
bool albumDiscFolder;
|
2020-09-13 14:06:12 +00:00
|
|
|
@JsonKey(defaultValue: false)
|
|
|
|
bool overwriteDownload;
|
2020-10-09 18:52:45 +00:00
|
|
|
@JsonKey(defaultValue: 2)
|
|
|
|
int downloadThreads;
|
|
|
|
@JsonKey(defaultValue: false)
|
|
|
|
bool playlistFolder;
|
|
|
|
@JsonKey(defaultValue: true)
|
|
|
|
bool downloadLyrics;
|
2020-10-10 20:51:20 +00:00
|
|
|
@JsonKey(defaultValue: false)
|
|
|
|
bool trackCover;
|
2020-10-14 19:09:16 +00:00
|
|
|
@JsonKey(defaultValue: true)
|
|
|
|
bool albumCover;
|
2020-10-15 18:37:36 +00:00
|
|
|
@JsonKey(defaultValue: false)
|
|
|
|
bool nomediaFiles;
|
2020-12-04 17:02:50 +00:00
|
|
|
@JsonKey(defaultValue: ", ")
|
|
|
|
String artistSeparator;
|
|
|
|
@JsonKey(defaultValue: "%artist% - %title%")
|
|
|
|
String singletonFilename;
|
2020-12-14 17:29:28 +00:00
|
|
|
@JsonKey(defaultValue: 1400)
|
|
|
|
int albumArtResolution;
|
2021-02-09 20:14:14 +00:00
|
|
|
@JsonKey(defaultValue: ["title", "album", "artist", "track", "disc",
|
|
|
|
"albumArtist", "date", "label", "isrc", "upc", "trackTotal", "bpm",
|
|
|
|
"lyrics", "genre", "contributors", "art"])
|
|
|
|
List<String> tags;
|
|
|
|
|
2020-06-23 19:23:12 +00:00
|
|
|
|
|
|
|
//Appearance
|
2020-10-11 20:06:29 +00:00
|
|
|
@JsonKey(defaultValue: Themes.Dark)
|
2020-06-23 19:23:12 +00:00
|
|
|
Themes theme;
|
2020-10-11 20:06:29 +00:00
|
|
|
@JsonKey(defaultValue: false)
|
|
|
|
bool useSystemTheme;
|
2020-11-09 21:05:47 +00:00
|
|
|
@JsonKey(defaultValue: true)
|
|
|
|
bool colorGradientBackground;
|
2021-02-09 20:14:14 +00:00
|
|
|
@JsonKey(defaultValue: false)
|
|
|
|
bool blurPlayerBackground;
|
|
|
|
@JsonKey(defaultValue: "Deezer")
|
|
|
|
String font;
|
|
|
|
@JsonKey(defaultValue: false)
|
|
|
|
bool lyricsVisualizer;
|
2021-03-21 21:46:44 +00:00
|
|
|
@JsonKey(defaultValue: null)
|
|
|
|
int displayMode;
|
2020-06-23 19:23:12 +00:00
|
|
|
|
|
|
|
//Colors
|
|
|
|
@JsonKey(toJson: _colorToJson, fromJson: _colorFromJson)
|
|
|
|
Color primaryColor = Colors.blue;
|
|
|
|
|
|
|
|
static _colorToJson(Color c) => c.value;
|
|
|
|
static _colorFromJson(int v) => Color(v??Colors.blue.value);
|
|
|
|
|
|
|
|
@JsonKey(defaultValue: false)
|
|
|
|
bool useArtColor = false;
|
|
|
|
StreamSubscription _useArtColorSub;
|
|
|
|
|
|
|
|
//Deezer
|
|
|
|
@JsonKey(defaultValue: 'en')
|
|
|
|
String deezerLanguage;
|
|
|
|
@JsonKey(defaultValue: 'US')
|
|
|
|
String deezerCountry;
|
|
|
|
@JsonKey(defaultValue: false)
|
|
|
|
bool logListen;
|
2020-10-09 18:52:45 +00:00
|
|
|
@JsonKey(defaultValue: null)
|
|
|
|
String proxyAddress;
|
2020-06-23 19:23:12 +00:00
|
|
|
|
2020-11-09 21:05:47 +00:00
|
|
|
//LastFM
|
|
|
|
@JsonKey(defaultValue: null)
|
|
|
|
String lastFMUsername;
|
|
|
|
@JsonKey(defaultValue: null)
|
|
|
|
String lastFMPassword;
|
|
|
|
|
2021-04-05 20:22:32 +00:00
|
|
|
//Spotify
|
|
|
|
@JsonKey(defaultValue: null)
|
|
|
|
String spotifyClientId;
|
|
|
|
@JsonKey(defaultValue: null)
|
|
|
|
String spotifyClientSecret;
|
2021-04-06 07:57:38 +00:00
|
|
|
@JsonKey(defaultValue: null)
|
|
|
|
SpotifyCredentialsSave spotifyCredentials;
|
2021-04-05 20:22:32 +00:00
|
|
|
|
2020-11-09 21:05:47 +00:00
|
|
|
|
2020-06-23 19:23:12 +00:00
|
|
|
Settings({this.downloadPath, this.arl});
|
|
|
|
|
|
|
|
ThemeData get themeData {
|
2020-10-11 20:06:29 +00:00
|
|
|
//System theme
|
|
|
|
if (useSystemTheme) {
|
|
|
|
if (SchedulerBinding.instance.window.platformBrightness == Brightness.light) {
|
|
|
|
return _themeData[Themes.Light];
|
|
|
|
} else {
|
|
|
|
if (theme == Themes.Light) return _themeData[Themes.Dark];
|
|
|
|
return _themeData[theme];
|
|
|
|
}
|
2020-06-23 19:23:12 +00:00
|
|
|
}
|
2020-10-11 20:06:29 +00:00
|
|
|
//Theme
|
|
|
|
return _themeData[theme]??ThemeData();
|
2020-06-23 19:23:12 +00:00
|
|
|
}
|
|
|
|
|
2021-02-09 20:14:14 +00:00
|
|
|
//Get all available fonts
|
|
|
|
List<String> get fonts {
|
|
|
|
return ['Deezer', ...GoogleFonts.asMap().keys];
|
|
|
|
}
|
|
|
|
|
2020-10-09 18:52:45 +00:00
|
|
|
//JSON to forward into download service
|
|
|
|
Map getServiceSettings() {
|
2020-11-28 21:32:17 +00:00
|
|
|
return {"json": jsonEncode(this.toJson())};
|
2020-10-09 18:52:45 +00:00
|
|
|
}
|
2020-06-23 19:23:12 +00:00
|
|
|
|
|
|
|
void updateUseArtColor(bool v) {
|
|
|
|
useArtColor = v;
|
|
|
|
if (v) {
|
|
|
|
//On media item change set color
|
|
|
|
_useArtColorSub = AudioService.currentMediaItemStream.listen((event) async {
|
|
|
|
if (event == null || event.artUri == null) return;
|
|
|
|
this.primaryColor = await imagesDatabase.getPrimaryColor(event.artUri);
|
|
|
|
updateTheme();
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
//Cancel stream subscription
|
|
|
|
if (_useArtColorSub != null) {
|
|
|
|
_useArtColorSub.cancel();
|
|
|
|
_useArtColorSub = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SliderThemeData get _sliderTheme => SliderThemeData(
|
|
|
|
thumbColor: primaryColor,
|
|
|
|
activeTrackColor: primaryColor,
|
|
|
|
inactiveTrackColor: primaryColor.withOpacity(0.2)
|
|
|
|
);
|
|
|
|
|
|
|
|
//Load settings/init
|
|
|
|
Future<Settings> loadSettings() async {
|
|
|
|
String path = await getPath();
|
|
|
|
File f = File(path);
|
|
|
|
if (await f.exists()) {
|
|
|
|
String data = await f.readAsString();
|
|
|
|
return Settings.fromJson(jsonDecode(data));
|
|
|
|
}
|
|
|
|
Settings s = Settings.fromJson({});
|
|
|
|
//Set default path, because async
|
|
|
|
s.downloadPath = (await ExtStorage.getExternalStoragePublicDirectory(ExtStorage.DIRECTORY_MUSIC));
|
|
|
|
s.save();
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future save() async {
|
|
|
|
File f = File(await getPath());
|
|
|
|
await f.writeAsString(jsonEncode(this.toJson()));
|
2020-10-09 18:52:45 +00:00
|
|
|
downloadManager.updateServiceSettings();
|
2020-06-23 19:23:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Future updateAudioServiceQuality() async {
|
|
|
|
//Send wifi & mobile quality to audio service isolate
|
|
|
|
await AudioService.customAction('updateQuality', {
|
|
|
|
'mobileQuality': getQualityInt(mobileQuality),
|
|
|
|
'wifiQuality': getQualityInt(wifiQuality)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
//AudioQuality to deezer int
|
|
|
|
int getQualityInt(AudioQuality q) {
|
|
|
|
switch (q) {
|
|
|
|
case AudioQuality.MP3_128: return 1;
|
|
|
|
case AudioQuality.MP3_320: return 3;
|
|
|
|
case AudioQuality.FLAC: return 9;
|
2021-04-05 20:22:32 +00:00
|
|
|
//Deezer default
|
|
|
|
default: return 8;
|
2020-06-23 19:23:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-20 19:55:14 +00:00
|
|
|
//Check if is dark, can't use theme directly, because of system themes, and Theme.of(context).brightness broke
|
|
|
|
bool get isDark {
|
|
|
|
if (useSystemTheme) {
|
|
|
|
if (SchedulerBinding.instance.window.platformBrightness == Brightness.light) return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (theme == Themes.Light) return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-10-11 20:06:29 +00:00
|
|
|
static const deezerBg = Color(0xFF1F1A16);
|
2020-10-19 19:28:45 +00:00
|
|
|
static const deezerBottom = Color(0xFF1b1714);
|
2021-04-05 20:22:32 +00:00
|
|
|
TextTheme get _textTheme => (font == 'Deezer')
|
|
|
|
? null
|
2021-04-06 07:57:38 +00:00
|
|
|
: GoogleFonts.getTextTheme(font, isDark ? ThemeData.dark().textTheme : ThemeData.light().textTheme);
|
2021-02-09 20:14:14 +00:00
|
|
|
String get _fontFamily => (font == 'Deezer') ? 'MabryPro' : null;
|
|
|
|
|
2021-04-05 20:22:32 +00:00
|
|
|
//Overrides for the non-deprecated buttons to look like the old ones
|
2021-04-06 07:57:38 +00:00
|
|
|
OutlinedButtonThemeData get outlinedButtonTheme => OutlinedButtonThemeData(
|
2021-04-05 20:22:32 +00:00
|
|
|
style: ButtonStyle(
|
2021-04-06 07:57:38 +00:00
|
|
|
foregroundColor: MaterialStateProperty.all(isDark ? Colors.white : Colors.black),
|
2021-04-05 20:22:32 +00:00
|
|
|
)
|
|
|
|
);
|
2021-04-06 07:57:38 +00:00
|
|
|
TextButtonThemeData get textButtonTheme => TextButtonThemeData(
|
2021-04-05 20:22:32 +00:00
|
|
|
style: ButtonStyle(
|
2021-04-06 07:57:38 +00:00
|
|
|
foregroundColor: MaterialStateProperty.all(isDark ? Colors.white : Colors.black),
|
2021-04-05 20:22:32 +00:00
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2020-10-11 20:06:29 +00:00
|
|
|
Map<Themes, ThemeData> get _themeData => {
|
|
|
|
Themes.Light: ThemeData(
|
2021-02-09 20:14:14 +00:00
|
|
|
textTheme: _textTheme,
|
|
|
|
fontFamily: _fontFamily,
|
2020-10-20 19:55:14 +00:00
|
|
|
brightness: Brightness.light,
|
2020-10-11 20:06:29 +00:00
|
|
|
primaryColor: primaryColor,
|
|
|
|
accentColor: primaryColor,
|
|
|
|
sliderTheme: _sliderTheme,
|
|
|
|
toggleableActiveColor: primaryColor,
|
2020-10-19 19:28:45 +00:00
|
|
|
bottomAppBarColor: Color(0xfff5f5f5),
|
2021-04-05 20:22:32 +00:00
|
|
|
outlinedButtonTheme: outlinedButtonTheme,
|
|
|
|
textButtonTheme: textButtonTheme
|
2020-10-11 20:06:29 +00:00
|
|
|
),
|
|
|
|
Themes.Dark: ThemeData(
|
2021-02-09 20:14:14 +00:00
|
|
|
textTheme: _textTheme,
|
|
|
|
fontFamily: _fontFamily,
|
2020-10-11 20:06:29 +00:00
|
|
|
brightness: Brightness.dark,
|
|
|
|
primaryColor: primaryColor,
|
|
|
|
accentColor: primaryColor,
|
|
|
|
sliderTheme: _sliderTheme,
|
|
|
|
toggleableActiveColor: primaryColor,
|
2021-04-05 20:22:32 +00:00
|
|
|
outlinedButtonTheme: outlinedButtonTheme,
|
|
|
|
textButtonTheme: textButtonTheme
|
2020-10-11 20:06:29 +00:00
|
|
|
),
|
|
|
|
Themes.Deezer: ThemeData(
|
2021-02-09 20:14:14 +00:00
|
|
|
textTheme: _textTheme,
|
|
|
|
fontFamily: _fontFamily,
|
2020-10-11 20:06:29 +00:00
|
|
|
brightness: Brightness.dark,
|
|
|
|
primaryColor: primaryColor,
|
|
|
|
accentColor: primaryColor,
|
|
|
|
sliderTheme: _sliderTheme,
|
|
|
|
toggleableActiveColor: primaryColor,
|
|
|
|
backgroundColor: deezerBg,
|
|
|
|
scaffoldBackgroundColor: deezerBg,
|
2020-10-19 19:28:45 +00:00
|
|
|
bottomAppBarColor: deezerBottom,
|
|
|
|
dialogBackgroundColor: deezerBottom,
|
2020-10-11 20:06:29 +00:00
|
|
|
bottomSheetTheme: BottomSheetThemeData(
|
2020-10-19 19:28:45 +00:00
|
|
|
backgroundColor: deezerBottom
|
2020-10-11 20:06:29 +00:00
|
|
|
),
|
2021-04-05 20:22:32 +00:00
|
|
|
cardColor: deezerBg,
|
|
|
|
outlinedButtonTheme: outlinedButtonTheme,
|
|
|
|
textButtonTheme: textButtonTheme
|
2020-10-11 20:06:29 +00:00
|
|
|
),
|
|
|
|
Themes.Black: ThemeData(
|
2021-02-09 20:14:14 +00:00
|
|
|
textTheme: _textTheme,
|
|
|
|
fontFamily: _fontFamily,
|
2020-10-11 20:06:29 +00:00
|
|
|
brightness: Brightness.dark,
|
|
|
|
primaryColor: primaryColor,
|
|
|
|
accentColor: primaryColor,
|
|
|
|
backgroundColor: Colors.black,
|
|
|
|
scaffoldBackgroundColor: Colors.black,
|
|
|
|
bottomAppBarColor: Colors.black,
|
|
|
|
dialogBackgroundColor: Colors.black,
|
|
|
|
sliderTheme: _sliderTheme,
|
|
|
|
toggleableActiveColor: primaryColor,
|
|
|
|
bottomSheetTheme: BottomSheetThemeData(
|
2020-10-20 19:55:14 +00:00
|
|
|
backgroundColor: Colors.black,
|
2021-04-05 20:22:32 +00:00
|
|
|
),
|
|
|
|
outlinedButtonTheme: outlinedButtonTheme,
|
|
|
|
textButtonTheme: textButtonTheme
|
2020-10-20 19:55:14 +00:00
|
|
|
)
|
2020-10-11 20:06:29 +00:00
|
|
|
};
|
|
|
|
|
2020-06-23 19:23:12 +00:00
|
|
|
Future<String> getPath() async => p.join((await getApplicationDocumentsDirectory()).path, 'settings.json');
|
|
|
|
|
|
|
|
//JSON
|
|
|
|
factory Settings.fromJson(Map<String, dynamic> json) => _$SettingsFromJson(json);
|
|
|
|
Map<String, dynamic> toJson() => _$SettingsToJson(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
enum AudioQuality {
|
|
|
|
MP3_128,
|
|
|
|
MP3_320,
|
2020-10-19 19:28:45 +00:00
|
|
|
FLAC,
|
|
|
|
ASK
|
2020-06-23 19:23:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
enum Themes {
|
|
|
|
Light,
|
|
|
|
Dark,
|
2020-07-18 21:45:48 +00:00
|
|
|
Deezer,
|
2020-06-23 19:23:12 +00:00
|
|
|
Black
|
2021-04-06 07:57:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@JsonSerializable()
|
|
|
|
class SpotifyCredentialsSave {
|
|
|
|
String accessToken;
|
|
|
|
String refreshToken;
|
|
|
|
List<String> scopes;
|
|
|
|
DateTime expiration;
|
|
|
|
|
|
|
|
SpotifyCredentialsSave({this.accessToken, this.refreshToken, this.scopes, this.expiration});
|
|
|
|
|
|
|
|
//JSON
|
|
|
|
factory SpotifyCredentialsSave.fromJson(Map<String, dynamic> json) => _$SpotifyCredentialsSaveFromJson(json);
|
|
|
|
Map<String, dynamic> toJson() => _$SpotifyCredentialsSaveToJson(this);
|
2020-06-23 19:23:12 +00:00
|
|
|
}
|