freezer/lib/settings.dart

388 lines
11 KiB
Dart
Raw Normal View History

import 'package:flutter/scheduler.dart';
2021-11-01 16:41:25 +00:00
import 'package:flutter/services.dart';
import 'package:freezer/api/definitions.dart';
import 'package:freezer/api/download.dart';
2021-09-01 12:38:32 +00:00
import 'package:freezer/api/player.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:path/path.dart' as p;
import 'package:flutter/material.dart';
import 'dart:io';
import 'dart:convert';
import 'dart:async';
2020-06-23 19:23:12 +00:00
part 'settings.g.dart';
2021-09-01 12:38:32 +00:00
late Settings settings;
2020-06-23 19:23:12 +00:00
@JsonSerializable()
class Settings {
//Language
@JsonKey(defaultValue: null)
2021-09-01 12:38:32 +00:00
String? language;
2021-02-09 20:14:14 +00:00
//Main
@JsonKey(defaultValue: false)
2021-11-01 16:41:25 +00:00
late bool ignoreInterruptions;
2021-02-09 20:14:14 +00:00
@JsonKey(defaultValue: false)
2021-11-01 16:41:25 +00:00
late bool enableEqualizer;
2020-06-23 19:23:12 +00:00
//Account
2021-09-01 12:38:32 +00:00
String? arl;
2020-06-23 19:23:12 +00:00
@JsonKey(ignore: true)
bool offlineMode = false;
//Quality
@JsonKey(defaultValue: AudioQuality.MP3_320)
2021-11-01 16:41:25 +00:00
late AudioQuality wifiQuality;
2020-06-23 19:23:12 +00:00
@JsonKey(defaultValue: AudioQuality.MP3_128)
2021-11-01 16:41:25 +00:00
late AudioQuality mobileQuality;
2020-06-23 19:23:12 +00:00
@JsonKey(defaultValue: AudioQuality.FLAC)
2021-11-01 16:41:25 +00:00
late AudioQuality offlineQuality;
2020-06-23 19:23:12 +00:00
@JsonKey(defaultValue: AudioQuality.FLAC)
2021-11-01 16:41:25 +00:00
late AudioQuality downloadQuality;
2020-06-23 19:23:12 +00:00
//Download options
2021-09-01 12:38:32 +00:00
String? downloadPath;
2020-09-01 14:41:15 +00:00
@JsonKey(defaultValue: "%artist% - %title%")
2021-11-01 16:41:25 +00:00
late String downloadFilename;
2020-09-01 14:41:15 +00:00
@JsonKey(defaultValue: true)
2021-11-01 16:41:25 +00:00
late bool albumFolder;
2020-06-23 19:23:12 +00:00
@JsonKey(defaultValue: true)
2021-11-01 16:41:25 +00:00
late bool artistFolder;
2020-09-01 14:41:15 +00:00
@JsonKey(defaultValue: false)
2021-11-01 16:41:25 +00:00
late bool albumDiscFolder;
@JsonKey(defaultValue: false)
2021-11-01 16:41:25 +00:00
late bool overwriteDownload;
@JsonKey(defaultValue: 2)
2021-11-01 16:41:25 +00:00
late int downloadThreads;
@JsonKey(defaultValue: false)
2021-11-01 16:41:25 +00:00
late bool playlistFolder;
@JsonKey(defaultValue: true)
2021-11-01 16:41:25 +00:00
late bool downloadLyrics;
2020-10-10 20:51:20 +00:00
@JsonKey(defaultValue: false)
2021-11-01 16:41:25 +00:00
late bool trackCover;
@JsonKey(defaultValue: true)
2021-11-01 16:41:25 +00:00
late bool albumCover;
@JsonKey(defaultValue: false)
2021-11-01 16:41:25 +00:00
late bool nomediaFiles;
@JsonKey(defaultValue: ", ")
2021-11-01 16:41:25 +00:00
late String artistSeparator;
@JsonKey(defaultValue: "%artist% - %title%")
2021-11-01 16:41:25 +00:00
late String singletonFilename;
@JsonKey(defaultValue: 1400)
2021-11-01 16:41:25 +00:00
late int albumArtResolution;
@JsonKey(defaultValue: [
"title",
"album",
"artist",
"track",
"disc",
"albumArtist",
"date",
"label",
"isrc",
"upc",
"trackTotal",
"bpm",
"lyrics",
"genre",
"contributors",
"art"
])
2021-11-01 16:41:25 +00:00
late List<String> tags;
2021-02-09 20:14:14 +00:00
2020-06-23 19:23:12 +00:00
//Appearance
@JsonKey(defaultValue: Themes.Dark)
2021-11-01 16:41:25 +00:00
late Themes theme;
@JsonKey(defaultValue: false)
2021-11-01 16:41:25 +00:00
late bool useSystemTheme;
@JsonKey(defaultValue: true)
2021-11-01 16:41:25 +00:00
late bool colorGradientBackground;
2021-02-09 20:14:14 +00:00
@JsonKey(defaultValue: false)
2021-11-01 16:41:25 +00:00
late bool blurPlayerBackground;
2021-02-09 20:14:14 +00:00
@JsonKey(defaultValue: "Deezer")
2021-11-01 16:41:25 +00:00
late String font;
2021-02-09 20:14:14 +00:00
@JsonKey(defaultValue: false)
2021-11-01 16:41:25 +00:00
late bool lyricsVisualizer;
2021-03-21 21:46:44 +00:00
@JsonKey(defaultValue: null)
2021-09-01 12:38:32 +00:00
int? displayMode;
2021-11-01 16:41:25 +00:00
@JsonKey(defaultValue: true)
late bool enableFilledPlayButton;
@JsonKey(defaultValue: false)
late bool playerBackgroundOnLyrics;
@JsonKey(defaultValue: NavigatorRouteType.material)
late NavigatorRouteType navigatorRouteType;
2020-06-23 19:23:12 +00:00
//Colors
@JsonKey(toJson: _colorToJson, fromJson: _colorFromJson)
Color primaryColor = Colors.blue;
static _colorToJson(Color c) => c.value;
2021-09-01 12:38:32 +00:00
static _colorFromJson(int? v) => Color(v ?? Colors.blue.value);
2020-06-23 19:23:12 +00:00
@JsonKey(defaultValue: false)
bool useArtColor = false;
//Deezer
@JsonKey(defaultValue: 'en')
2021-09-01 12:38:32 +00:00
String? deezerLanguage;
2020-06-23 19:23:12 +00:00
@JsonKey(defaultValue: 'US')
2021-09-01 12:38:32 +00:00
String? deezerCountry;
2020-06-23 19:23:12 +00:00
@JsonKey(defaultValue: false)
2021-09-01 12:38:32 +00:00
bool? logListen;
@JsonKey(defaultValue: null)
2021-09-01 12:38:32 +00:00
String? proxyAddress;
2020-06-23 19:23:12 +00:00
//LastFM
@JsonKey(defaultValue: null)
2021-09-01 12:38:32 +00:00
String? lastFMUsername;
@JsonKey(defaultValue: null)
2021-09-01 12:38:32 +00:00
String? lastFMPassword;
2021-04-05 20:22:32 +00:00
//Spotify
@JsonKey(defaultValue: null)
2021-09-01 12:38:32 +00:00
String? spotifyClientId;
2021-04-05 20:22:32 +00:00
@JsonKey(defaultValue: null)
2021-09-01 12:38:32 +00:00
String? spotifyClientSecret;
@JsonKey(defaultValue: null)
2021-09-01 12:38:32 +00:00
SpotifyCredentialsSave? spotifyCredentials;
2021-04-05 20:22:32 +00:00
2020-06-23 19:23:12 +00:00
Settings({this.downloadPath, this.arl});
2021-09-01 12:38:32 +00:00
ThemeData? get themeData {
//System theme
2021-11-01 16:41:25 +00:00
if (useSystemTheme) {
2021-09-01 12:38:32 +00:00
if (SchedulerBinding.instance!.window.platformBrightness ==
Brightness.light) {
return _themeData[Themes.Light];
} else {
if (theme == Themes.Light) return _themeData[Themes.Dark];
2021-11-01 16:41:25 +00:00
return _themeData[theme];
}
2020-06-23 19:23:12 +00:00
}
//Theme
2021-11-01 16:41:25 +00:00
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];
}
//JSON to forward into download service
Map getServiceSettings() {
2020-11-28 21:32:17 +00:00
return {"json": jsonEncode(this.toJson())};
}
2020-06-23 19:23:12 +00:00
void updateUseArtColor(bool v) {
useArtColor = v;
2021-09-01 12:38:32 +00:00
//TODO: let's reimplement this somewhere better
//if (v) {
// //On media item change set color
// _useArtColorSub =
// AudioService.currentMediaItemStream.listen((event) async {
// if (event == null || event.artUri == null) return;
// this.primaryColor =
2021-11-01 16:41:25 +00:00
// await imagesDatabase.getPrimaryColor(event.artUri.toString());
2021-09-01 12:38:32 +00:00
// updateTheme();
// });
//} else {
// //Cancel stream subscription
// if (_useArtColorSub != null) {
// _useArtColorSub!.cancel();
// _useArtColorSub = null;
// }
//}
2020-06-23 19:23:12 +00:00
}
SliderThemeData get _sliderTheme => SliderThemeData(
thumbColor: primaryColor,
activeTrackColor: primaryColor,
inactiveTrackColor: primaryColor.withOpacity(0.2));
2020-06-23 19:23:12 +00:00
//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
2021-08-30 12:51:51 +00:00
s.downloadPath =
await getExternalStorageDirectories(type: StorageDirectory.music)
2021-09-01 12:38:32 +00:00
.then((paths) => paths![0].path);
2020-06-23 19:23:12 +00:00
s.save();
return s;
}
2021-08-30 12:51:51 +00:00
Future<void> save() async {
2020-06-23 19:23:12 +00:00
File f = File(await getPath());
await f.writeAsString(jsonEncode(this.toJson()));
downloadManager.updateServiceSettings();
2020-06-23 19:23:12 +00:00
}
2021-08-30 12:51:51 +00:00
Future<void> updateAudioServiceQuality() async {
2020-06-23 19:23:12 +00:00
//Send wifi & mobile quality to audio service isolate
2021-09-01 12:38:32 +00:00
await audioHandler.customAction('updateQuality', {
2020-06-23 19:23:12 +00:00
'mobileQuality': getQualityInt(mobileQuality),
'wifiQuality': getQualityInt(wifiQuality)
});
}
//AudioQuality to deezer int
2021-09-01 12:38:32 +00:00
int getQualityInt(AudioQuality? q) {
2020-06-23 19:23:12 +00:00
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
}
}
MaterialColor get _primarySwatch =>
MaterialColor(primaryColor.value, <int, Color>{
50: primaryColor.withOpacity(.1),
100: primaryColor.withOpacity(.2),
200: primaryColor.withOpacity(.3),
300: primaryColor.withOpacity(.4),
400: primaryColor.withOpacity(.5),
500: primaryColor.withOpacity(.6),
600: primaryColor.withOpacity(.7),
700: primaryColor.withOpacity(.8),
800: primaryColor.withOpacity(.9),
900: primaryColor.withOpacity(1),
});
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 {
2021-11-01 16:41:25 +00:00
if (useSystemTheme) {
2021-09-01 12:38:32 +00:00
if (SchedulerBinding.instance!.window.platformBrightness ==
Brightness.light) return false;
2020-10-20 19:55:14 +00:00
return true;
}
if (theme == Themes.Light) return false;
return true;
}
static const deezerBg = Color(0xFF1F1A16);
static const deezerBottom = Color(0xFF1b1714);
2021-09-01 12:38:32 +00:00
TextTheme? get _textTheme => (font == 'Deezer')
2021-04-05 20:22:32 +00:00
? null
2021-04-05 21:27:15 +00:00
: GoogleFonts.getTextTheme(
2021-11-01 16:41:25 +00:00
font,
2021-04-05 21:27:15 +00:00
this.isDark
? ThemeData.dark().textTheme
: ThemeData.light().textTheme);
2021-09-01 12:38:32 +00:00
String? get _fontFamily => (font == 'Deezer') ? 'MabryPro' : null;
2021-02-09 20:14:14 +00:00
Map<Themes, ThemeData> get _themeData => {
Themes.Light: ThemeData(
textTheme: _textTheme,
fontFamily: _fontFamily,
brightness: Brightness.light,
primarySwatch: _primarySwatch,
2021-04-05 21:27:15 +00:00
primaryColor: primaryColor,
2021-09-01 12:38:32 +00:00
colorScheme: ColorScheme.fromSwatch(
primarySwatch: _primarySwatch,
accentColor: primaryColor,
brightness: Brightness.light),
sliderTheme: _sliderTheme,
toggleableActiveColor: primaryColor,
bottomAppBarColor: Color(0xfff5f5f5),
2021-11-01 16:41:25 +00:00
appBarTheme:
AppBarTheme(systemOverlayStyle: SystemUiOverlayStyle.light),
),
Themes.Dark: ThemeData(
textTheme: _textTheme,
fontFamily: _fontFamily,
brightness: Brightness.dark,
primarySwatch: _primarySwatch,
2021-04-05 21:27:15 +00:00
primaryColor: primaryColor,
2021-09-01 12:38:32 +00:00
colorScheme: ColorScheme.fromSwatch(
primarySwatch: _primarySwatch,
accentColor: primaryColor,
brightness: Brightness.dark),
sliderTheme: _sliderTheme,
toggleableActiveColor: primaryColor,
),
Themes.Deezer: ThemeData(
textTheme: _textTheme,
fontFamily: _fontFamily,
brightness: Brightness.dark,
2021-04-05 21:27:15 +00:00
primarySwatch: _primarySwatch,
primaryColor: primaryColor,
2021-09-01 12:38:32 +00:00
colorScheme: ColorScheme.fromSwatch(
primarySwatch: _primarySwatch,
accentColor: primaryColor,
brightness: Brightness.dark),
2021-04-05 21:27:15 +00:00
sliderTheme: _sliderTheme,
toggleableActiveColor: primaryColor,
backgroundColor: deezerBg,
scaffoldBackgroundColor: deezerBg,
bottomAppBarColor: deezerBottom,
dialogBackgroundColor: deezerBottom,
bottomSheetTheme: BottomSheetThemeData(backgroundColor: deezerBottom),
cardColor: deezerBg,
),
Themes.Black: ThemeData(
textTheme: _textTheme,
fontFamily: _fontFamily,
brightness: Brightness.dark,
primarySwatch: _primarySwatch,
2021-04-05 21:27:15 +00:00
primaryColor: primaryColor,
2021-09-01 12:38:32 +00:00
colorScheme: ColorScheme.fromSwatch(
primarySwatch: _primarySwatch,
accentColor: primaryColor,
brightness: Brightness.dark),
backgroundColor: Colors.black,
scaffoldBackgroundColor: Colors.black,
bottomAppBarColor: Colors.black,
dialogBackgroundColor: Colors.black,
sliderTheme: _sliderTheme,
toggleableActiveColor: primaryColor,
bottomSheetTheme: BottomSheetThemeData(
backgroundColor: Colors.black,
),
)
};
Future<String> getPath() async =>
p.join((await getApplicationDocumentsDirectory()).path, 'settings.json');
2020-06-23 19:23:12 +00:00
//JSON
factory Settings.fromJson(Map<String, dynamic> json) =>
_$SettingsFromJson(json);
2020-06-23 19:23:12 +00:00
Map<String, dynamic> toJson() => _$SettingsToJson(this);
}
enum AudioQuality { MP3_128, MP3_320, FLAC, ASK }
2020-06-23 19:23:12 +00:00
enum Themes { Light, Dark, Deezer, Black }
@JsonSerializable()
class SpotifyCredentialsSave {
2021-09-01 12:38:32 +00:00
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);
}