36 Commits

Author SHA1 Message Date
Bart Ribbers
dae166ecb9 Merge eaffffac4d into b0bb26f84b 2024-12-10 22:47:14 +01:00
Bart Ribbers
eaffffac4d fix: move all .of(context) out of the widget tree and into a variable
At some places <something>.of(context) was used multiple times in the
same widget. This, although small, can have an impact on performance
that's just plain unnecessary. It's better to just get things you need
out of the context first before you do anything else.
2024-12-10 22:47:06 +01:00
Bart Ribbers
e11250182d chore: upgrade to Flutter 3.24.5
At the time of writing the latest Flutter version.
2024-12-10 22:45:36 +01:00
Bart Ribbers
fc0daacfc0 chore: ignore VSCode's settings.json in git
Seettings in there can be different per user and should be, it should
not be committed
2024-12-10 20:42:50 +01:00
Bart Ribbers
7e5885e5c8 chore: cleanup fvm configuration
I guess fvm changed the way it does it's configuration at some point,
but rather than having .fvm/fmv_config.json checked in .fvmrc should be
checked in. The .fvm directory is used to store files and symlinks
related to the installed Flutter version and as such should not be
commited at all.
2024-12-10 20:42:49 +01:00
austinried
b0bb26f84b Fix initial server ping/feature tests always using token auth 2023-05-18 06:42:29 +09:00
austinried
e94fcf3128 bump version 2023-05-16 18:59:16 +09:00
josé m
bd6e818f36 Translated using Weblate (Galician)
Currently translated at 100.0% (94 of 94 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/gl/
Translation: Subtracks/subtracks
2023-05-16 18:57:04 +09:00
Max Smith
96d0c35c31 Translated using Weblate (Russian)
Currently translated at 100.0% (94 of 94 strings)

Co-authored-by: Max Smith <sevinfolds@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/ru/
Translation: Subtracks/subtracks
2023-05-16 18:57:04 +09:00
Tim Schneeberger
4ef3281a0b Translated using Weblate (German)
Currently translated at 100.0% (92 of 92 strings)

Co-authored-by: Tim Schneeberger <thebone.main@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/de/
Translation: Subtracks/subtracks
2023-05-16 18:57:04 +09:00
austinried
c56e3dba0f remove todo 2023-05-16 09:34:39 +09:00
austinried
53d284ace4 redact error too
create log file if it doesn't exist first
2023-05-16 09:34:39 +09:00
austinried
c2733482e5 show snackbar error for sync
log http errors
log sync errors
2023-05-16 09:34:39 +09:00
austinried
67f0c926c4 add snackbar method for errors
test (ping) server before saving source
display error message when saving source
2023-05-16 09:34:39 +09:00
Joel Calado
889be2ff2c return null 2023-05-15 07:11:58 +09:00
Joel Calado
52b51954aa improve url validation in settings 2023-05-15 07:11:58 +09:00
austinried
1c76293559 default force plaintext password off 2023-05-14 14:35:19 +09:00
austinried
250d6793a2 wording 2023-05-14 14:29:04 +09:00
austinried
121af2bca3 audio playback error logging
subsonic error logging
source save error logging
2023-05-14 14:29:04 +09:00
austinried
e410dcb2eb log sql exceptions 2023-05-14 14:29:04 +09:00
austinried
63ff9772e5 initial console/file logging framework 2023-05-14 14:29:04 +09:00
Vojtěch Fošnár
1ae29c5ade Translated using Weblate (Czech)
Currently translated at 85.8% (79 of 92 strings)

Co-authored-by: Vojtěch Fošnár <vfosnar@fosny.eu>
Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/cs/
Translation: Subtracks/subtracks
2023-05-11 10:07:23 +09:00
Joel Calado
fedd6a71bb Translated using Weblate (Portuguese)
Currently translated at 88.0% (81 of 92 strings)

Co-authored-by: Joel Calado <joelcalado@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/pt/
Translation: Subtracks/subtracks
2023-05-11 10:07:23 +09:00
austinried
8f64cfcbca bump version 2023-05-08 06:39:17 +09:00
austinried
1edb2c13da update todo 2023-05-08 06:37:10 +09:00
austinried
7f83204b24 don't pass all ids as params
instead, only pass ids to delete and chunk those by the param limit
2023-05-07 13:56:05 +09:00
austinried
0fe52494d0 update todo 2023-05-07 13:54:56 +09:00
Daniel Playfair Cal
56dbcde3b4 add autofill hints for source page 2023-05-07 13:54:26 +09:00
austinried
8fbc5e6ce4 add artist radio 2023-05-07 13:28:15 +09:00
austinried
979a4b7c73 add plaintext password option
fixes #161
2023-05-06 17:56:03 +09:00
josé m
7b1da24748 Translated using Weblate (Galician)
Currently translated at 100.0% (92 of 92 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/gl/
Translation: Subtracks/subtracks
2023-05-06 09:11:25 +09:00
Sacelo
7014aa85d1 Translated using Weblate (Spanish)
Currently translated at 77.1% (71 of 92 strings)

Co-authored-by: Sacelo <rion020806@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/es/
Translation: Subtracks/subtracks
2023-05-06 09:11:25 +09:00
雨杉叶
abab674322 Translated using Weblate (Chinese (Simplified))
Currently translated at 88.0% (81 of 92 strings)

Co-authored-by: 雨杉叶 <yushaye@outlook.com>
Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/zh_Hans/
Translation: Subtracks/subtracks
2023-05-06 09:11:25 +09:00
daniel-225
498bb22a69 Translated using Weblate (German)
Currently translated at 75.0% (69 of 92 strings)

Co-authored-by: daniel-225 <dsoukup@outlook.de>
Translate-URL: https://hosted.weblate.org/projects/subtracks/subtracks/de/
Translation: Subtracks/subtracks
2023-05-06 09:11:25 +09:00
austinried
11fe43a750 add server info fields 2023-04-28 21:59:33 +09:00
austinried
2a60a7306c use english as last fallback locale
fixes #160
2023-04-28 21:45:59 +09:00
83 changed files with 5126 additions and 3078 deletions

View File

@@ -1,4 +0,0 @@
{
"flutterSdkVersion": "3.7.11",
"flavors": {}
}

4
.fvmrc Normal file
View File

@@ -0,0 +1,4 @@
{
"flutter": "3.24.5",
"flavors": {}
}

View File

@@ -23,10 +23,14 @@ A clear and concise description of what you expected to happen.
**Screenshots** **Screenshots**
If applicable, add screenshots to help explain your problem. If applicable, add screenshots to help explain your problem.
**Smartphone (please complete the following information):** **Device**
- Device: [e.g. Pixel 4] - Model: [e.g. Pixel 4]
- OS: [e.g. Android 12] - OS: [e.g. Android 12]
- Subtracks version [e.g. 1.2.0] - Subtracks version [e.g. 1.2.0]
**Server**
- Software: [e.g. Navidrome]
- Version: [e.g. 0.49.3]
**Additional context** **Additional context**
Add any other context about the problem here. Add any other context about the problem here.

8
.gitignore vendored
View File

@@ -16,10 +16,8 @@ migrate_working_dir/
*.iws *.iws
.idea/ .idea/
# The .vscode folder contains launch configuration and tasks you configure in # VSCode related
# VS Code which you may wish to be included in version control, so this line .vscode/settings.json
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related # Flutter/Dart/Pub related
**/doc/api/ **/doc/api/
@@ -45,5 +43,5 @@ app.*.map.json
/.env /.env
*.sqlite* *.sqlite*
/.fvm/flutter_sdk .fvm/
*.keystore *.keystore

View File

@@ -22,6 +22,8 @@
"resourcesSortByTitle", "resourcesSortByTitle",
"resourcesSortByUpdated", "resourcesSortByUpdated",
"settingsAboutActionsSupport", "settingsAboutActionsSupport",
"settingsAboutShareLogs",
"settingsAboutChooseLog",
"settingsNetworkOptionsOfflineMode", "settingsNetworkOptionsOfflineMode",
"settingsNetworkOptionsOfflineModeOff", "settingsNetworkOptionsOfflineModeOff",
"settingsNetworkOptionsOfflineModeOn", "settingsNetworkOptionsOfflineModeOn",
@@ -53,6 +55,8 @@
"resourcesSortByTitle", "resourcesSortByTitle",
"resourcesSortByUpdated", "resourcesSortByUpdated",
"settingsAboutActionsSupport", "settingsAboutActionsSupport",
"settingsAboutShareLogs",
"settingsAboutChooseLog",
"settingsNetworkOptionsOfflineMode", "settingsNetworkOptionsOfflineMode",
"settingsNetworkOptionsOfflineModeOff", "settingsNetworkOptionsOfflineModeOff",
"settingsNetworkOptionsOfflineModeOn", "settingsNetworkOptionsOfflineModeOn",
@@ -62,32 +66,12 @@
], ],
"cs": [ "cs": [
"actionsCancel",
"actionsDelete",
"actionsDownload",
"actionsDownloadCancel",
"actionsDownloadDelete",
"actionsOk",
"controlsShuffle",
"resourcesAlbumCount", "resourcesAlbumCount",
"resourcesArtistCount", "resourcesArtistCount",
"resourcesFilterAlbum",
"resourcesFilterArtist",
"resourcesFilterOwner",
"resourcesFilterYear",
"resourcesPlaylistCount", "resourcesPlaylistCount",
"resourcesSongCount", "resourcesSongCount",
"resourcesSongListDeleteAllContent", "settingsAboutShareLogs",
"resourcesSongListDeleteAllTitle", "settingsAboutChooseLog",
"resourcesSortByAlbum",
"resourcesSortByAlbumCount",
"resourcesSortByTitle",
"resourcesSortByUpdated",
"settingsAboutActionsLicenses",
"settingsAboutActionsProjectHomepage",
"settingsAboutActionsSupport",
"settingsAboutName",
"settingsAboutVersion",
"settingsMusicName", "settingsMusicName",
"settingsMusicOptionsScrobbleDescriptionOff", "settingsMusicOptionsScrobbleDescriptionOff",
"settingsMusicOptionsScrobbleDescriptionOn", "settingsMusicOptionsScrobbleDescriptionOn",
@@ -96,12 +80,7 @@
"settingsNetworkOptionsMinBufferTitle", "settingsNetworkOptionsMinBufferTitle",
"settingsNetworkOptionsOfflineMode", "settingsNetworkOptionsOfflineMode",
"settingsNetworkOptionsOfflineModeOff", "settingsNetworkOptionsOfflineModeOff",
"settingsNetworkOptionsOfflineModeOn", "settingsNetworkOptionsOfflineModeOn"
"settingsNetworkOptionsStreamFormat",
"settingsNetworkOptionsStreamFormatServerDefault",
"settingsResetActionsClearImageCache",
"settingsResetName",
"settingsServersFieldsName"
], ],
"da": [ "da": [
@@ -133,6 +112,8 @@
"resourcesSortByTitle", "resourcesSortByTitle",
"resourcesSortByUpdated", "resourcesSortByUpdated",
"settingsAboutActionsSupport", "settingsAboutActionsSupport",
"settingsAboutShareLogs",
"settingsAboutChooseLog",
"settingsMusicOptionsScrobbleDescriptionOff", "settingsMusicOptionsScrobbleDescriptionOff",
"settingsNetworkOptionsOfflineMode", "settingsNetworkOptionsOfflineMode",
"settingsNetworkOptionsOfflineModeOff", "settingsNetworkOptionsOfflineModeOff",
@@ -146,44 +127,11 @@
], ],
"de": [ "de": [
"actionsCancel", "settingsAboutShareLogs",
"actionsDelete", "settingsAboutChooseLog"
"actionsDownload",
"actionsDownloadCancel",
"actionsDownloadDelete",
"actionsOk",
"controlsShuffle",
"resourcesAlbumCount",
"resourcesArtistCount",
"resourcesFilterAlbum",
"resourcesFilterArtist",
"resourcesFilterOwner",
"resourcesFilterYear",
"resourcesPlaylistCount",
"resourcesSongCount",
"resourcesSongListDeleteAllContent",
"resourcesSongListDeleteAllTitle",
"resourcesSortByAlbum",
"resourcesSortByAlbumCount",
"resourcesSortByTitle",
"resourcesSortByUpdated",
"settingsAboutActionsSupport",
"settingsNetworkOptionsOfflineMode",
"settingsNetworkOptionsOfflineModeOff",
"settingsNetworkOptionsOfflineModeOn",
"settingsNetworkOptionsStreamFormat",
"settingsNetworkOptionsStreamFormatServerDefault",
"settingsServersFieldsName"
], ],
"es": [ "es": [
"actionsCancel",
"actionsDelete",
"actionsDownload",
"actionsDownloadCancel",
"actionsDownloadDelete",
"actionsOk",
"controlsShuffle",
"resourcesAlbumCount", "resourcesAlbumCount",
"resourcesArtistCount", "resourcesArtistCount",
"resourcesFilterAlbum", "resourcesFilterAlbum",
@@ -199,6 +147,8 @@
"resourcesSortByTitle", "resourcesSortByTitle",
"resourcesSortByUpdated", "resourcesSortByUpdated",
"settingsAboutActionsSupport", "settingsAboutActionsSupport",
"settingsAboutShareLogs",
"settingsAboutChooseLog",
"settingsNetworkOptionsOfflineMode", "settingsNetworkOptionsOfflineMode",
"settingsNetworkOptionsOfflineModeOff", "settingsNetworkOptionsOfflineModeOff",
"settingsNetworkOptionsOfflineModeOn", "settingsNetworkOptionsOfflineModeOn",
@@ -230,37 +180,8 @@
"resourcesSortByTitle", "resourcesSortByTitle",
"resourcesSortByUpdated", "resourcesSortByUpdated",
"settingsAboutActionsSupport", "settingsAboutActionsSupport",
"settingsNetworkOptionsOfflineMode", "settingsAboutShareLogs",
"settingsNetworkOptionsOfflineModeOff", "settingsAboutChooseLog",
"settingsNetworkOptionsOfflineModeOn",
"settingsNetworkOptionsStreamFormat",
"settingsNetworkOptionsStreamFormatServerDefault",
"settingsServersFieldsName"
],
"gl": [
"actionsCancel",
"actionsDelete",
"actionsDownload",
"actionsDownloadCancel",
"actionsDownloadDelete",
"actionsOk",
"controlsShuffle",
"resourcesAlbumCount",
"resourcesArtistCount",
"resourcesFilterAlbum",
"resourcesFilterArtist",
"resourcesFilterOwner",
"resourcesFilterYear",
"resourcesPlaylistCount",
"resourcesSongCount",
"resourcesSongListDeleteAllContent",
"resourcesSongListDeleteAllTitle",
"resourcesSortByAlbum",
"resourcesSortByAlbumCount",
"resourcesSortByTitle",
"resourcesSortByUpdated",
"settingsAboutActionsSupport",
"settingsNetworkOptionsOfflineMode", "settingsNetworkOptionsOfflineMode",
"settingsNetworkOptionsOfflineModeOff", "settingsNetworkOptionsOfflineModeOff",
"settingsNetworkOptionsOfflineModeOn", "settingsNetworkOptionsOfflineModeOn",
@@ -292,6 +213,8 @@
"resourcesSortByTitle", "resourcesSortByTitle",
"resourcesSortByUpdated", "resourcesSortByUpdated",
"settingsAboutActionsSupport", "settingsAboutActionsSupport",
"settingsAboutShareLogs",
"settingsAboutChooseLog",
"settingsNetworkOptionsOfflineMode", "settingsNetworkOptionsOfflineMode",
"settingsNetworkOptionsOfflineModeOff", "settingsNetworkOptionsOfflineModeOff",
"settingsNetworkOptionsOfflineModeOn", "settingsNetworkOptionsOfflineModeOn",
@@ -343,6 +266,8 @@
"settingsAboutActionsLicenses", "settingsAboutActionsLicenses",
"settingsAboutActionsSupport", "settingsAboutActionsSupport",
"settingsAboutName", "settingsAboutName",
"settingsAboutShareLogs",
"settingsAboutChooseLog",
"settingsAboutVersion", "settingsAboutVersion",
"settingsMusicOptionsScrobbleDescriptionOff", "settingsMusicOptionsScrobbleDescriptionOff",
"settingsMusicOptionsScrobbleDescriptionOn", "settingsMusicOptionsScrobbleDescriptionOn",
@@ -399,6 +324,8 @@
"resourcesSortByTitle", "resourcesSortByTitle",
"resourcesSortByUpdated", "resourcesSortByUpdated",
"settingsAboutActionsSupport", "settingsAboutActionsSupport",
"settingsAboutShareLogs",
"settingsAboutChooseLog",
"settingsNetworkOptionsOfflineMode", "settingsNetworkOptionsOfflineMode",
"settingsNetworkOptionsOfflineModeOff", "settingsNetworkOptionsOfflineModeOff",
"settingsNetworkOptionsOfflineModeOn", "settingsNetworkOptionsOfflineModeOn",
@@ -430,6 +357,8 @@
"resourcesSortByTitle", "resourcesSortByTitle",
"resourcesSortByUpdated", "resourcesSortByUpdated",
"settingsAboutActionsSupport", "settingsAboutActionsSupport",
"settingsAboutShareLogs",
"settingsAboutChooseLog",
"settingsNetworkOptionsOfflineMode", "settingsNetworkOptionsOfflineMode",
"settingsNetworkOptionsOfflineModeOff", "settingsNetworkOptionsOfflineModeOff",
"settingsNetworkOptionsOfflineModeOn", "settingsNetworkOptionsOfflineModeOn",
@@ -461,6 +390,8 @@
"resourcesSortByTitle", "resourcesSortByTitle",
"resourcesSortByUpdated", "resourcesSortByUpdated",
"settingsAboutActionsSupport", "settingsAboutActionsSupport",
"settingsAboutShareLogs",
"settingsAboutChooseLog",
"settingsNetworkOptionsOfflineMode", "settingsNetworkOptionsOfflineMode",
"settingsNetworkOptionsOfflineModeOff", "settingsNetworkOptionsOfflineModeOff",
"settingsNetworkOptionsOfflineModeOn", "settingsNetworkOptionsOfflineModeOn",
@@ -470,63 +401,17 @@
], ],
"pt": [ "pt": [
"actionsCancel",
"actionsDelete",
"actionsDownload",
"actionsDownloadCancel",
"actionsDownloadDelete",
"actionsOk",
"controlsShuffle",
"resourcesAlbumCount", "resourcesAlbumCount",
"resourcesArtistCount", "resourcesArtistCount",
"resourcesFilterAlbum",
"resourcesFilterArtist",
"resourcesFilterOwner", "resourcesFilterOwner",
"resourcesFilterYear",
"resourcesPlaylistCount", "resourcesPlaylistCount",
"resourcesSongCount", "resourcesSongCount",
"resourcesSongListDeleteAllContent", "resourcesSongListDeleteAllContent",
"resourcesSongListDeleteAllTitle", "resourcesSongListDeleteAllTitle",
"resourcesSortByAlbum",
"resourcesSortByAlbumCount", "resourcesSortByAlbumCount",
"resourcesSortByTitle",
"resourcesSortByUpdated", "resourcesSortByUpdated",
"settingsAboutActionsSupport", "settingsAboutShareLogs",
"settingsNetworkOptionsOfflineMode", "settingsAboutChooseLog",
"settingsNetworkOptionsOfflineModeOff",
"settingsNetworkOptionsOfflineModeOn",
"settingsNetworkOptionsStreamFormat",
"settingsNetworkOptionsStreamFormatServerDefault",
"settingsServersFieldsName"
],
"ru": [
"actionsCancel",
"actionsDelete",
"actionsDownload",
"actionsDownloadCancel",
"actionsDownloadDelete",
"actionsOk",
"controlsShuffle",
"resourcesAlbumCount",
"resourcesArtistCount",
"resourcesFilterAlbum",
"resourcesFilterArtist",
"resourcesFilterOwner",
"resourcesFilterYear",
"resourcesPlaylistCount",
"resourcesSongCount",
"resourcesSongListDeleteAllContent",
"resourcesSongListDeleteAllTitle",
"resourcesSortByAlbum",
"resourcesSortByAlbumCount",
"resourcesSortByTitle",
"resourcesSortByUpdated",
"settingsAboutActionsSupport",
"settingsNetworkOptionsOfflineMode",
"settingsNetworkOptionsOfflineModeOff",
"settingsNetworkOptionsOfflineModeOn",
"settingsNetworkOptionsStreamFormat",
"settingsNetworkOptionsStreamFormatServerDefault", "settingsNetworkOptionsStreamFormatServerDefault",
"settingsServersFieldsName" "settingsServersFieldsName"
], ],
@@ -554,6 +439,8 @@
"resourcesSortByTitle", "resourcesSortByTitle",
"resourcesSortByUpdated", "resourcesSortByUpdated",
"settingsAboutActionsSupport", "settingsAboutActionsSupport",
"settingsAboutShareLogs",
"settingsAboutChooseLog",
"settingsNetworkOptionsOfflineMode", "settingsNetworkOptionsOfflineMode",
"settingsNetworkOptionsOfflineModeOff", "settingsNetworkOptionsOfflineModeOff",
"settingsNetworkOptionsOfflineModeOn", "settingsNetworkOptionsOfflineModeOn",
@@ -585,6 +472,8 @@
"resourcesSortByTitle", "resourcesSortByTitle",
"resourcesSortByUpdated", "resourcesSortByUpdated",
"settingsAboutActionsSupport", "settingsAboutActionsSupport",
"settingsAboutShareLogs",
"settingsAboutChooseLog",
"settingsNetworkOptionsOfflineMode", "settingsNetworkOptionsOfflineMode",
"settingsNetworkOptionsOfflineModeOff", "settingsNetworkOptionsOfflineModeOff",
"settingsNetworkOptionsOfflineModeOn", "settingsNetworkOptionsOfflineModeOn",
@@ -594,28 +483,13 @@
], ],
"zh": [ "zh": [
"actionsCancel",
"actionsDelete",
"actionsDownload",
"actionsDownloadCancel",
"actionsDownloadDelete",
"actionsOk",
"controlsShuffle", "controlsShuffle",
"resourcesAlbumCount", "resourcesAlbumCount",
"resourcesArtistCount", "resourcesArtistCount",
"resourcesFilterAlbum",
"resourcesFilterArtist",
"resourcesFilterOwner",
"resourcesFilterYear",
"resourcesPlaylistCount", "resourcesPlaylistCount",
"resourcesSongCount", "resourcesSongCount",
"resourcesSongListDeleteAllContent", "settingsAboutShareLogs",
"resourcesSongListDeleteAllTitle", "settingsAboutChooseLog",
"resourcesSortByAlbum",
"resourcesSortByAlbumCount",
"resourcesSortByTitle",
"resourcesSortByUpdated",
"settingsAboutActionsSupport",
"settingsNetworkOptionsOfflineMode", "settingsNetworkOptionsOfflineMode",
"settingsNetworkOptionsOfflineModeOff", "settingsNetworkOptionsOfflineModeOff",
"settingsNetworkOptionsOfflineModeOn", "settingsNetworkOptionsOfflineModeOn",

62
TODO.md
View File

@@ -1,34 +1,30 @@
## To-do ## To-do
- [ ] Star/unstar - Star/unstar
- [ ] Context menus - Context menus
- [ ] Download actions for song - Download actions for song
- [ ] Playlist management - Playlist management
- [ ] Add to playlist (from context) - Add to playlist (from context)
- [ ] Queue management - Queue management
- [ ] View playing queue - View playing queue
- [ ] Re-order queue - Re-order queue
- [ ] Add to queue (from context) - Add to queue (from context)
- [ ] Remove from queue - Remove from queue
- [ ] Scrobbling - Scrobbling
- [ ] Library filters (year/genre/etc) - Library filters (year/genre/etc)
- [ ] Library list display modes - Library list display modes
- [ ] Search - Search
- [ ] Individual "more" results pages - Individual "more" results pages
- [ ] Radio modes - Now playing gestures
- [ ] Artist - Swipe bar/album to skip
- [ ] Now playing gestures - Double-tap to seek forward/back (bar only)
- [ ] Swipe bar/album to skip - Settings
- [ ] Double-tap to seek forward/back (bar only) - Music
- [ ] Settings - Scrobble
- [ ] Sources - Downloads
- [ ] Use plaintext password - Used/available space
- [ ] Music - Clear downloads
- [ ] Scrobble - Clear images
- [ ] Downloads - About
- [ ] Used/available space - Licenses
- [ ] Clear downloads - Welcome/setup flow
- [ ] Clear images - Proper loading screen/animation
- [ ] About
- [ ] Licenses
- [ ] Welcome/setup flow
- [ ] Proper loading screen/animation

View File

@@ -1,3 +1,9 @@
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties() def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties') def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) { if (localPropertiesFile.exists()) {
@@ -6,11 +12,6 @@ if (localPropertiesFile.exists()) {
} }
} }
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode') def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) { if (flutterVersionCode == null) {
flutterVersionCode = '1' flutterVersionCode = '1'
@@ -21,10 +22,6 @@ if (flutterVersionName == null) {
flutterVersionName = '1.0' flutterVersionName = '1.0'
} }
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def keystoreProperties = new Properties() def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties') def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) { if (keystorePropertiesFile.exists()) {
@@ -53,7 +50,7 @@ android {
applicationId "com.subtracks2" applicationId "com.subtracks2"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion 19 minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
@@ -82,7 +79,3 @@ android {
flutter { flutter {
source '../..' source '../..'
} }
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

View File

@@ -5,4 +5,9 @@
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
--> -->
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<!-- audio_service -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
</manifest> </manifest>

View File

@@ -69,4 +69,5 @@
<!-- audio_service --> <!-- audio_service -->
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
</manifest> </manifest>

View File

@@ -1,25 +0,0 @@
// Generated file.
//
// If you wish to remove Flutter's multidex support, delete this entire file.
//
// Modifications to this file should be done in a copy under a different name
// as this file may be regenerated.
package io.flutter.app;
import android.app.Application;
import android.content.Context;
import androidx.annotation.CallSuper;
import androidx.multidex.MultiDex;
/**
* Extension of {@link android.app.Application}, adding multidex support.
*/
public class FlutterMultiDexApplication extends Application {
@Override
@CallSuper
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}

View File

@@ -5,4 +5,9 @@
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
--> -->
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<!-- audio_service -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
</manifest> </manifest>

View File

@@ -1,16 +1,3 @@
buildscript {
ext.kotlin_version = '1.7.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects { allprojects {
repositories { repositories {
google() google()
@@ -26,6 +13,6 @@ subprojects {
project.evaluationDependsOn(':app') project.evaluationDependsOn(':app')
} }
task clean(type: Delete) { tasks.register("clean", Delete) {
delete rootProject.buildDir delete rootProject.buildDir
} }

View File

@@ -1,11 +1,25 @@
include ':app' pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
def localPropertiesFile = new File(rootProject.projectDir, "local.properties") includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
def properties = new Properties()
assert localPropertiesFile.exists() repositories {
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } google()
mavenCentral()
gradlePluginPortal()
}
}
def flutterSdkPath = properties.getProperty("flutter.sdk") plugins {
assert flutterSdkPath != null, "flutter.sdk not set in local.properties" id "dev.flutter.flutter-plugin-loader" version "1.0.0"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" id "com.android.application" version "7.2.0" apply false
id "org.jetbrains.kotlin.android" version "2.0.21" apply false
}
include ":app"

View File

@@ -1,3 +1,4 @@
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -77,7 +78,8 @@ class App extends HookConsumerWidget {
), ),
routeInformationParser: appRouter.defaultRouteParser(), routeInformationParser: appRouter.defaultRouteParser(),
localizationsDelegates: AppLocalizations.localizationsDelegates, localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales, supportedLocales: [...AppLocalizations.supportedLocales]
..moveToTheFront(const Locale('en')),
); );
} }
} }

View File

@@ -20,4 +20,5 @@ final lastPathProvider = NotifierProvider<LastPath, String>.internal(
); );
typedef _$LastPath = Notifier<String>; typedef _$LastPath = Notifier<String>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -32,6 +32,8 @@ class RadioPlayFab extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context);
return FloatingActionButton( return FloatingActionButton(
heroTag: null, heroTag: null,
onPressed: onPressed, onPressed: onPressed,
@@ -44,7 +46,7 @@ class RadioPlayFab extends StatelessWidget {
right: -10, right: -10,
child: Icon( child: Icon(
Icons.play_arrow_rounded, Icons.play_arrow_rounded,
color: Theme.of(context).colorScheme.primaryContainer, color: theme.colorScheme.primaryContainer,
size: 26, size: 26,
), ),
), ),

View File

@@ -25,7 +25,7 @@ Future<T?> showContextMenu<T>({
required WidgetBuilder builder, required WidgetBuilder builder,
}) { }) {
return showModalBottomSheet<T>( return showModalBottomSheet<T>(
backgroundColor: ref.read(baseThemeProvider).theme.colorScheme.background, backgroundColor: ref.read(baseThemeProvider).theme.colorScheme.surface,
useRootNavigator: true, useRootNavigator: true,
isScrollControlled: true, isScrollControlled: true,
context: context, context: context,
@@ -327,8 +327,9 @@ class _DownloadAction extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final l = AppLocalizations.of(context);
return _MenuItem( return _MenuItem(
title: _actionText(AppLocalizations.of(context)), title: _actionText(l),
icon: downloadAction.iconBuilder(context), icon: downloadAction.iconBuilder(context),
onTap: downloadAction.action, onTap: downloadAction.action,
); );

View File

@@ -54,11 +54,12 @@ class BackgroundGradient extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final mediaQuery = MediaQuery.of(context);
final base = ref.watch(baseThemeProvider); final base = ref.watch(baseThemeProvider);
return SizedBox( return SizedBox(
width: double.infinity, width: double.infinity,
height: MediaQuery.of(context).size.height, height: mediaQuery.size.height,
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient( gradient: LinearGradient(

View File

@@ -112,9 +112,9 @@ List<DownloadAction> useListDownloadActions({
DownloadAction cancel() { DownloadAction cancel() {
return DownloadAction( return DownloadAction(
type: DownloadActionType.cancel, type: DownloadActionType.cancel,
iconBuilder: (context) => Stack( iconBuilder: (context) => const Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: const [ children: [
Icon(Icons.cancel_rounded), Icon(Icons.cancel_rounded),
SizedBox( SizedBox(
height: 32, height: 32,

View File

@@ -103,6 +103,8 @@ class ArtistArtImage extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final theme = Theme.of(context);
final cache = ref.watch(_artistArtUriCacheInfoProvider( final cache = ref.watch(_artistArtUriCacheInfoProvider(
artistId: artistId, artistId: artistId,
thumbnail: thumbnail, thumbnail: thumbnail,
@@ -123,7 +125,7 @@ class ArtistArtImage extends HookConsumerWidget {
width: width, width: width,
), ),
loading: () => Container( loading: () => Container(
color: Theme.of(context).colorScheme.secondaryContainer, color: theme.colorScheme.secondaryContainer,
height: height, height: height,
width: width, width: width,
), ),
@@ -211,9 +213,11 @@ class CardClip extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final cardShape = Theme.of(context).cardTheme.shape; final cardShape = Theme.of(context).cardTheme.shape;
return ClipRRect( return ClipRRect(
borderRadius: borderRadius: cardShape is RoundedRectangleBorder
cardShape is RoundedRectangleBorder ? cardShape.borderRadius : null, ? cardShape.borderRadius
: BorderRadius.zero,
child: !square child: !square
? child ? child
: AspectRatio( : AspectRatio(
@@ -247,6 +251,8 @@ class UriCacheInfoImage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context);
return CachedNetworkImage( return CachedNetworkImage(
imageUrl: cache.uri.toString(), imageUrl: cache.uri.toString(),
cacheKey: cache.cacheKey, cacheKey: cache.cacheKey,
@@ -260,7 +266,7 @@ class UriCacheInfoImage extends StatelessWidget {
placeholderStyle == PlaceholderStyle.spinner placeholderStyle == PlaceholderStyle.spinner
? Container() ? Container()
: Container( : Container(
color: Theme.of(context).colorScheme.secondaryContainer, color: theme.colorScheme.secondaryContainer,
), ),
errorWidget: (context, url, error) => PlaceholderImage( errorWidget: (context, url, error) => PlaceholderImage(
fit: fit, fit: fit,

View File

@@ -30,8 +30,6 @@ class _SystemHash {
} }
} }
typedef _ArtistArtCacheInfoRef = AutoDisposeProviderRef<CacheInfo>;
/// See also [_artistArtCacheInfo]. /// See also [_artistArtCacheInfo].
@ProviderFor(_artistArtCacheInfo) @ProviderFor(_artistArtCacheInfo)
const _artistArtCacheInfoProvider = _ArtistArtCacheInfoFamily(); const _artistArtCacheInfoProvider = _ArtistArtCacheInfoFamily();
@@ -81,11 +79,11 @@ class _ArtistArtCacheInfoFamily extends Family<CacheInfo> {
class _ArtistArtCacheInfoProvider extends AutoDisposeProvider<CacheInfo> { class _ArtistArtCacheInfoProvider extends AutoDisposeProvider<CacheInfo> {
/// See also [_artistArtCacheInfo]. /// See also [_artistArtCacheInfo].
_ArtistArtCacheInfoProvider({ _ArtistArtCacheInfoProvider({
required this.artistId, required String artistId,
this.thumbnail = true, bool thumbnail = true,
}) : super.internal( }) : this._internal(
(ref) => _artistArtCacheInfo( (ref) => _artistArtCacheInfo(
ref, ref as _ArtistArtCacheInfoRef,
artistId: artistId, artistId: artistId,
thumbnail: thumbnail, thumbnail: thumbnail,
), ),
@@ -98,11 +96,48 @@ class _ArtistArtCacheInfoProvider extends AutoDisposeProvider<CacheInfo> {
dependencies: _ArtistArtCacheInfoFamily._dependencies, dependencies: _ArtistArtCacheInfoFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
_ArtistArtCacheInfoFamily._allTransitiveDependencies, _ArtistArtCacheInfoFamily._allTransitiveDependencies,
artistId: artistId,
thumbnail: thumbnail,
); );
_ArtistArtCacheInfoProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.artistId,
required this.thumbnail,
}) : super.internal();
final String artistId; final String artistId;
final bool thumbnail; final bool thumbnail;
@override
Override overrideWith(
CacheInfo Function(_ArtistArtCacheInfoRef provider) create,
) {
return ProviderOverride(
origin: this,
override: _ArtistArtCacheInfoProvider._internal(
(ref) => create(ref as _ArtistArtCacheInfoRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
artistId: artistId,
thumbnail: thumbnail,
),
);
}
@override
AutoDisposeProviderElement<CacheInfo> createElement() {
return _ArtistArtCacheInfoProviderElement(this);
}
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is _ArtistArtCacheInfoProvider && return other is _ArtistArtCacheInfoProvider &&
@@ -120,9 +155,26 @@ class _ArtistArtCacheInfoProvider extends AutoDisposeProvider<CacheInfo> {
} }
} }
mixin _ArtistArtCacheInfoRef on AutoDisposeProviderRef<CacheInfo> {
/// The parameter `artistId` of this provider.
String get artistId;
/// The parameter `thumbnail` of this provider.
bool get thumbnail;
}
class _ArtistArtCacheInfoProviderElement
extends AutoDisposeProviderElement<CacheInfo> with _ArtistArtCacheInfoRef {
_ArtistArtCacheInfoProviderElement(super.provider);
@override
String get artistId => (origin as _ArtistArtCacheInfoProvider).artistId;
@override
bool get thumbnail => (origin as _ArtistArtCacheInfoProvider).thumbnail;
}
String _$artistArtCachedUrlHash() => String _$artistArtCachedUrlHash() =>
r'2a5e0fea614ff12a1d562faccec6cfe98394af42'; r'2a5e0fea614ff12a1d562faccec6cfe98394af42';
typedef _ArtistArtCachedUrlRef = AutoDisposeFutureProviderRef<String?>;
/// See also [_artistArtCachedUrl]. /// See also [_artistArtCachedUrl].
@ProviderFor(_artistArtCachedUrl) @ProviderFor(_artistArtCachedUrl)
@@ -173,11 +225,11 @@ class _ArtistArtCachedUrlFamily extends Family<AsyncValue<String?>> {
class _ArtistArtCachedUrlProvider extends AutoDisposeFutureProvider<String?> { class _ArtistArtCachedUrlProvider extends AutoDisposeFutureProvider<String?> {
/// See also [_artistArtCachedUrl]. /// See also [_artistArtCachedUrl].
_ArtistArtCachedUrlProvider({ _ArtistArtCachedUrlProvider({
required this.artistId, required String artistId,
this.thumbnail = true, bool thumbnail = true,
}) : super.internal( }) : this._internal(
(ref) => _artistArtCachedUrl( (ref) => _artistArtCachedUrl(
ref, ref as _ArtistArtCachedUrlRef,
artistId: artistId, artistId: artistId,
thumbnail: thumbnail, thumbnail: thumbnail,
), ),
@@ -190,11 +242,48 @@ class _ArtistArtCachedUrlProvider extends AutoDisposeFutureProvider<String?> {
dependencies: _ArtistArtCachedUrlFamily._dependencies, dependencies: _ArtistArtCachedUrlFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
_ArtistArtCachedUrlFamily._allTransitiveDependencies, _ArtistArtCachedUrlFamily._allTransitiveDependencies,
artistId: artistId,
thumbnail: thumbnail,
); );
_ArtistArtCachedUrlProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.artistId,
required this.thumbnail,
}) : super.internal();
final String artistId; final String artistId;
final bool thumbnail; final bool thumbnail;
@override
Override overrideWith(
FutureOr<String?> Function(_ArtistArtCachedUrlRef provider) create,
) {
return ProviderOverride(
origin: this,
override: _ArtistArtCachedUrlProvider._internal(
(ref) => create(ref as _ArtistArtCachedUrlRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
artistId: artistId,
thumbnail: thumbnail,
),
);
}
@override
AutoDisposeFutureProviderElement<String?> createElement() {
return _ArtistArtCachedUrlProviderElement(this);
}
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is _ArtistArtCachedUrlProvider && return other is _ArtistArtCachedUrlProvider &&
@@ -212,9 +301,27 @@ class _ArtistArtCachedUrlProvider extends AutoDisposeFutureProvider<String?> {
} }
} }
mixin _ArtistArtCachedUrlRef on AutoDisposeFutureProviderRef<String?> {
/// The parameter `artistId` of this provider.
String get artistId;
/// The parameter `thumbnail` of this provider.
bool get thumbnail;
}
class _ArtistArtCachedUrlProviderElement
extends AutoDisposeFutureProviderElement<String?>
with _ArtistArtCachedUrlRef {
_ArtistArtCachedUrlProviderElement(super.provider);
@override
String get artistId => (origin as _ArtistArtCachedUrlProvider).artistId;
@override
bool get thumbnail => (origin as _ArtistArtCachedUrlProvider).thumbnail;
}
String _$artistArtUriCacheInfoHash() => String _$artistArtUriCacheInfoHash() =>
r'9bdc0f5654882265236ef746ea697a6d107a4b6f'; r'9bdc0f5654882265236ef746ea697a6d107a4b6f';
typedef _ArtistArtUriCacheInfoRef = AutoDisposeFutureProviderRef<UriCacheInfo>;
/// See also [_artistArtUriCacheInfo]. /// See also [_artistArtUriCacheInfo].
@ProviderFor(_artistArtUriCacheInfo) @ProviderFor(_artistArtUriCacheInfo)
@@ -266,11 +373,11 @@ class _ArtistArtUriCacheInfoProvider
extends AutoDisposeFutureProvider<UriCacheInfo> { extends AutoDisposeFutureProvider<UriCacheInfo> {
/// See also [_artistArtUriCacheInfo]. /// See also [_artistArtUriCacheInfo].
_ArtistArtUriCacheInfoProvider({ _ArtistArtUriCacheInfoProvider({
required this.artistId, required String artistId,
this.thumbnail = true, bool thumbnail = true,
}) : super.internal( }) : this._internal(
(ref) => _artistArtUriCacheInfo( (ref) => _artistArtUriCacheInfo(
ref, ref as _ArtistArtUriCacheInfoRef,
artistId: artistId, artistId: artistId,
thumbnail: thumbnail, thumbnail: thumbnail,
), ),
@@ -283,11 +390,48 @@ class _ArtistArtUriCacheInfoProvider
dependencies: _ArtistArtUriCacheInfoFamily._dependencies, dependencies: _ArtistArtUriCacheInfoFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
_ArtistArtUriCacheInfoFamily._allTransitiveDependencies, _ArtistArtUriCacheInfoFamily._allTransitiveDependencies,
artistId: artistId,
thumbnail: thumbnail,
); );
_ArtistArtUriCacheInfoProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.artistId,
required this.thumbnail,
}) : super.internal();
final String artistId; final String artistId;
final bool thumbnail; final bool thumbnail;
@override
Override overrideWith(
FutureOr<UriCacheInfo> Function(_ArtistArtUriCacheInfoRef provider) create,
) {
return ProviderOverride(
origin: this,
override: _ArtistArtUriCacheInfoProvider._internal(
(ref) => create(ref as _ArtistArtUriCacheInfoRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
artistId: artistId,
thumbnail: thumbnail,
),
);
}
@override
AutoDisposeFutureProviderElement<UriCacheInfo> createElement() {
return _ArtistArtUriCacheInfoProviderElement(this);
}
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is _ArtistArtUriCacheInfoProvider && return other is _ArtistArtUriCacheInfoProvider &&
@@ -304,4 +448,24 @@ class _ArtistArtUriCacheInfoProvider
return _SystemHash.finish(hash); return _SystemHash.finish(hash);
} }
} }
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
mixin _ArtistArtUriCacheInfoRef on AutoDisposeFutureProviderRef<UriCacheInfo> {
/// The parameter `artistId` of this provider.
String get artistId;
/// The parameter `thumbnail` of this provider.
bool get thumbnail;
}
class _ArtistArtUriCacheInfoProviderElement
extends AutoDisposeFutureProviderElement<UriCacheInfo>
with _ArtistArtUriCacheInfoRef {
_ArtistArtUriCacheInfoProviderElement(super.provider);
@override
String get artistId => (origin as _ArtistArtUriCacheInfoProvider).artistId;
@override
bool get thumbnail => (origin as _ArtistArtUriCacheInfoProvider).thumbnail;
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -204,12 +204,14 @@ class ArtistListTile extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final l = AppLocalizations.of(context);
return ListTile( return ListTile(
leading: CircleClip( leading: CircleClip(
child: ArtistArtImage(artistId: artist.id), child: ArtistArtImage(artistId: artist.id),
), ),
title: Text(artist.name), title: Text(artist.name),
subtitle: Text(AppLocalizations.of(context).resourcesAlbumCount( subtitle: Text(l.resourcesAlbumCount(
artist.albumCount, artist.albumCount,
)), )),
onTap: onTap, onTap: onTap,
@@ -239,6 +241,8 @@ class PlaylistListTile extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final l = AppLocalizations.of(context);
// generate the palette used in other views ahead of time // generate the palette used in other views ahead of time
ref.watch(playlistArtPaletteProvider(playlist.id)); ref.watch(playlistArtPaletteProvider(playlist.id));
final cache = ref.watch(cacheServiceProvider).playlistArt(playlist); final cache = ref.watch(cacheServiceProvider).playlistArt(playlist);
@@ -248,7 +252,7 @@ class PlaylistListTile extends HookConsumerWidget {
child: UriCacheInfoImage(cache: cache), child: UriCacheInfoImage(cache: cache),
), ),
title: Text(playlist.name), title: Text(playlist.name),
subtitle: Text(AppLocalizations.of(context).resourcesSongCount( subtitle: Text(l.resourcesSongCount(
playlist.songCount, playlist.songCount,
)), )),
onTap: onTap, onTap: onTap,

View File

@@ -4,6 +4,7 @@ import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import '../services/sync_service.dart'; import '../services/sync_service.dart';
import 'items.dart'; import 'items.dart';
import 'snackbars.dart';
class PagedListQueryView<T> extends HookConsumerWidget { class PagedListQueryView<T> extends HookConsumerWidget {
final PagingController<int, T> pagingController; final PagingController<int, T> pagingController;
@@ -71,6 +72,8 @@ class PagedGridQueryView<T> extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final mediaQuery = MediaQuery.of(context);
SliverGridDelegate gridDelegate; SliverGridDelegate gridDelegate;
double spacing; double spacing;
@@ -91,7 +94,7 @@ class PagedGridQueryView<T> extends HookConsumerWidget {
} }
final listView = PagedGridView<int, T>( final listView = PagedGridView<int, T>(
padding: MediaQuery.of(context).padding + EdgeInsets.all(spacing), padding: mediaQuery.padding + EdgeInsets.all(spacing),
pagingController: pagingController, pagingController: pagingController,
builderDelegate: PagedChildBuilderDelegate( builderDelegate: PagedChildBuilderDelegate(
itemBuilder: (context, item, index) => itemBuilder: (context, item, index) =>
@@ -122,7 +125,14 @@ class SyncAllRefresh extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
return RefreshIndicator( return RefreshIndicator(
onRefresh: () => ref.read(syncServiceProvider.notifier).syncAll(), onRefresh: () async {
try {
await ref.read(syncServiceProvider.notifier).syncAll();
} catch (e) {
if (!context.mounted) return;
showErrorSnackbar(context, e.toString());
}
},
child: child, child: child,
); );
} }

View File

@@ -30,13 +30,13 @@ class NowPlayingBar extends HookConsumerWidget {
elevation: 3, elevation: 3,
color: colors?.darkBackground, color: colors?.darkBackground,
// surfaceTintColor: theme?.colorScheme.background, // surfaceTintColor: theme?.colorScheme.background,
child: Column( child: const Column(
children: [ children: [
SizedBox( SizedBox(
height: 70, height: 70,
child: Row( child: Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: const [ children: [
Padding( Padding(
padding: EdgeInsets.all(10), padding: EdgeInsets.all(10),
child: _ArtImage(), child: _ArtImage(),
@@ -54,7 +54,7 @@ class NowPlayingBar extends HookConsumerWidget {
], ],
), ),
), ),
const _ProgressBar(), _ProgressBar(),
], ],
), ),
), ),
@@ -112,6 +112,8 @@ class _TrackInfo extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final theme = Theme.of(context);
final item = ref.watch(mediaItemProvider); final item = ref.watch(mediaItemProvider);
return Column( return Column(
@@ -125,11 +127,11 @@ class _TrackInfo extends HookConsumerWidget {
// maxLines: 1, // maxLines: 1,
// softWrap: false, // softWrap: false,
// overflow: TextOverflow.fade, // overflow: TextOverflow.fade,
// style: Theme.of(context).textTheme.labelLarge, // style: theme.textTheme.labelLarge,
// ), // ),
ScrollableText( ScrollableText(
data?.title ?? 'Nothing!!!', data?.title ?? 'Nothing!!!',
style: Theme.of(context).textTheme.labelLarge, style: theme.textTheme.labelLarge,
), ),
const SizedBox(height: 2), const SizedBox(height: 2),
Text( Text(
@@ -137,7 +139,7 @@ class _TrackInfo extends HookConsumerWidget {
maxLines: 1, maxLines: 1,
softWrap: false, softWrap: false,
overflow: TextOverflow.fade, overflow: TextOverflow.fade,
style: Theme.of(context).textTheme.labelMedium, style: theme.textTheme.labelMedium,
), ),
], ],
error: (_, __) => const [Text('Error!')], error: (_, __) => const [Text('Error!')],
@@ -158,6 +160,8 @@ class PlayPauseButton extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final theme = Theme.of(context);
final playing = ref.watch(playingProvider); final playing = ref.watch(playingProvider);
final state = ref.watch(processingStateProvider); final state = ref.watch(processingStateProvider);
@@ -173,7 +177,7 @@ class PlayPauseButton extends HookConsumerWidget {
width: size / 3, width: size / 3,
child: CircularProgressIndicator( child: CircularProgressIndicator(
strokeWidth: size / 16, strokeWidth: size / 16,
color: Theme.of(context).colorScheme.background, color: theme.colorScheme.surface,
), ),
), ),
], ],
@@ -195,7 +199,7 @@ class PlayPauseButton extends HookConsumerWidget {
} }
}, },
icon: icon, icon: icon,
color: Theme.of(context).colorScheme.onBackground, color: theme.colorScheme.surface,
); );
} }
} }

View File

@@ -1,13 +1,19 @@
import 'dart:math'; import 'dart:math';
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../../database/database.dart';
import '../../models/query.dart';
import '../../models/support.dart';
import '../../services/audio_service.dart';
import '../../state/music.dart'; import '../../state/music.dart';
import '../../state/settings.dart'; import '../../state/settings.dart';
import '../app_router.dart'; import '../app_router.dart';
import '../buttons.dart';
import '../images.dart'; import '../images.dart';
import '../items.dart'; import '../items.dart';
@@ -27,6 +33,26 @@ class ArtistPage extends HookConsumerWidget {
final albums = ref.watch(albumsByArtistIdProvider(id)); final albums = ref.watch(albumsByArtistIdProvider(id));
return Scaffold( return Scaffold(
floatingActionButton: RadioPlayFab(
onPressed: () => artist.hasValue
? ref.read(audioControlProvider).playRadio(
context: QueueContextType.artist,
contextId: artist.valueOrNull!.id,
query: ListQuery(
filters: IList([
FilterWith.equals(
column: 'artist_id',
value: artist.valueOrNull!.id,
)
]),
),
getSongs: (query) => ref
.read(databaseProvider)
.songsList(ref.read(sourceIdProvider), query)
.get(),
)
: null,
),
body: CustomScrollView( body: CustomScrollView(
slivers: [ slivers: [
SliverToBoxAdapter( SliverToBoxAdapter(
@@ -92,10 +118,11 @@ class _Title extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context);
return Text( return Text(
text, text,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.displayMedium!.copyWith( style: theme.textTheme.displayMedium!.copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.white, color: Colors.white,
shadows: [ shadows: [

View File

@@ -46,6 +46,8 @@ class BottomNavTabsPage extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final theme = Theme.of(context);
final observer = ref.watch(bottomTabObserverProvider); final observer = ref.watch(bottomTabObserverProvider);
const navElevation = 3.0; const navElevation = 3.0;
@@ -63,8 +65,8 @@ class BottomNavTabsPage extends HookConsumerWidget {
return AnnotatedRegion<SystemUiOverlayStyle>( return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light.copyWith( value: SystemUiOverlayStyle.light.copyWith(
systemNavigationBarColor: ElevationOverlay.applySurfaceTint( systemNavigationBarColor: ElevationOverlay.applySurfaceTint(
Theme.of(context).colorScheme.surface, theme.colorScheme.surface,
Theme.of(context).colorScheme.surfaceTint, theme.colorScheme.surfaceTint,
navElevation, navElevation,
), ),
statusBarColor: Colors.transparent, statusBarColor: Colors.transparent,
@@ -111,13 +113,13 @@ class OfflineIndicator extends HookConsumerWidget {
), ),
child: FilledButton.tonal( child: FilledButton.tonal(
style: const ButtonStyle( style: const ButtonStyle(
padding: MaterialStatePropertyAll<EdgeInsetsGeometry>( padding: WidgetStatePropertyAll<EdgeInsetsGeometry>(
EdgeInsets.zero, EdgeInsets.zero,
), ),
fixedSize: MaterialStatePropertyAll<Size>( fixedSize: WidgetStatePropertyAll<Size>(
Size(42, 42), Size(42, 42),
), ),
minimumSize: MaterialStatePropertyAll<Size>( minimumSize: WidgetStatePropertyAll<Size>(
Size(42, 42), Size(42, 42),
), ),
), ),
@@ -136,7 +138,6 @@ class OfflineIndicator extends HookConsumerWidget {
padding: EdgeInsets.only(left: 2, bottom: 2), padding: EdgeInsets.only(left: 2, bottom: 2),
child: Icon( child: Icon(
Icons.cloud_off_rounded, Icons.cloud_off_rounded,
// color: Theme.of(context).colorScheme.secondary,
size: 20, size: 20,
), ),
), ),
@@ -154,6 +155,7 @@ class _BottomNavBar extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final iconTheme = IconTheme.of(context);
final tabsRouter = AutoTabsRouter.of(context); final tabsRouter = AutoTabsRouter.of(context);
useListenableSelector(tabsRouter, () => tabsRouter.activeIndex); useListenableSelector(tabsRouter, () => tabsRouter.activeIndex);
@@ -190,9 +192,7 @@ class _BottomNavBar extends HookConsumerWidget {
return SvgPicture.asset( return SvgPicture.asset(
'assets/tag_FILL0_wght400_GRAD0_opsz24.svg', 'assets/tag_FILL0_wght400_GRAD0_opsz24.svg',
colorFilter: ColorFilter.mode( colorFilter: ColorFilter.mode(
IconTheme.of(context).color!.withOpacity( iconTheme.color!.withOpacity(iconTheme.opacity ?? 1),
IconTheme.of(context).opacity ?? 1,
),
BlendMode.srcIn, BlendMode.srcIn,
), ),
height: 28, height: 28,

View File

@@ -53,4 +53,5 @@ final lastBottomNavStateServiceProvider =
); );
typedef _$LastBottomNavStateService = AsyncNotifier<void>; typedef _$LastBottomNavStateService = AsyncNotifier<void>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -249,6 +249,8 @@ class _Category extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final theme = Theme.of(context);
return MultiSliver( return MultiSliver(
children: [ children: [
SliverToBoxAdapter( SliverToBoxAdapter(
@@ -256,7 +258,7 @@ class _Category extends HookConsumerWidget {
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: Text( child: Text(
title, title,
style: Theme.of(context).textTheme.headlineMedium, style: theme.textTheme.headlineMedium,
), ),
), ),
), ),

View File

@@ -30,8 +30,6 @@ class _SystemHash {
} }
} }
typedef AlbumsCategoryListRef = AutoDisposeStreamProviderRef<List<Album>>;
/// See also [albumsCategoryList]. /// See also [albumsCategoryList].
@ProviderFor(albumsCategoryList) @ProviderFor(albumsCategoryList)
const albumsCategoryListProvider = AlbumsCategoryListFamily(); const albumsCategoryListProvider = AlbumsCategoryListFamily();
@@ -79,10 +77,10 @@ class AlbumsCategoryListProvider
extends AutoDisposeStreamProvider<List<Album>> { extends AutoDisposeStreamProvider<List<Album>> {
/// See also [albumsCategoryList]. /// See also [albumsCategoryList].
AlbumsCategoryListProvider( AlbumsCategoryListProvider(
this.opt, ListQuery opt,
) : super.internal( ) : this._internal(
(ref) => albumsCategoryList( (ref) => albumsCategoryList(
ref, ref as AlbumsCategoryListRef,
opt, opt,
), ),
from: albumsCategoryListProvider, from: albumsCategoryListProvider,
@@ -94,10 +92,44 @@ class AlbumsCategoryListProvider
dependencies: AlbumsCategoryListFamily._dependencies, dependencies: AlbumsCategoryListFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
AlbumsCategoryListFamily._allTransitiveDependencies, AlbumsCategoryListFamily._allTransitiveDependencies,
opt: opt,
); );
AlbumsCategoryListProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.opt,
}) : super.internal();
final ListQuery opt; final ListQuery opt;
@override
Override overrideWith(
Stream<List<Album>> Function(AlbumsCategoryListRef provider) create,
) {
return ProviderOverride(
origin: this,
override: AlbumsCategoryListProvider._internal(
(ref) => create(ref as AlbumsCategoryListRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
opt: opt,
),
);
}
@override
AutoDisposeStreamProviderElement<List<Album>> createElement() {
return _AlbumsCategoryListProviderElement(this);
}
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is AlbumsCategoryListProvider && other.opt == opt; return other is AlbumsCategoryListProvider && other.opt == opt;
@@ -111,4 +143,19 @@ class AlbumsCategoryListProvider
return _SystemHash.finish(hash); return _SystemHash.finish(hash);
} }
} }
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
mixin AlbumsCategoryListRef on AutoDisposeStreamProviderRef<List<Album>> {
/// The parameter `opt` of this provider.
ListQuery get opt;
}
class _AlbumsCategoryListProviderElement
extends AutoDisposeStreamProviderElement<List<Album>>
with AlbumsCategoryListRef {
_AlbumsCategoryListProviderElement(super.provider);
@override
ListQuery get opt => (origin as AlbumsCategoryListProvider).opt;
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -228,6 +228,8 @@ class _LibraryFilterFab extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final theme = Theme.of(context);
final tabsRouter = AutoTabsRouter.of(context); final tabsRouter = AutoTabsRouter.of(context);
final activeIndex = final activeIndex =
useListenableSelector(tabsRouter, () => tabsRouter.activeIndex); useListenableSelector(tabsRouter, () => tabsRouter.activeIndex);
@@ -242,7 +244,7 @@ class _LibraryFilterFab extends HookConsumerWidget {
end: 0, end: 0,
child: Icon( child: Icon(
Icons.circle, Icons.circle,
color: Theme.of(context).colorScheme.primaryContainer, color: theme.colorScheme.primaryContainer,
size: 11, size: 11,
), ),
), ),
@@ -449,6 +451,8 @@ class ListSortFilterOptions extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final theme = Theme.of(context);
final list = ref.watch(libraryListQueryProvider(index)); final list = ref.watch(libraryListQueryProvider(index));
return SliverList( return SliverList(
@@ -457,7 +461,7 @@ class ListSortFilterOptions extends HookConsumerWidget {
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text( child: Text(
'Sort by', 'Sort by',
style: Theme.of(context).textTheme.titleLarge, style: theme.textTheme.titleLarge,
), ),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
@@ -480,7 +484,7 @@ class ListSortFilterOptions extends HookConsumerWidget {
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text( child: Text(
'Filter', 'Filter',
style: Theme.of(context).textTheme.titleLarge, style: theme.textTheme.titleLarge,
), ),
), ),
for (var column in list.options.filterColumns) for (var column in list.options.filterColumns)

View File

@@ -60,8 +60,6 @@ class _SystemHash {
} }
} }
typedef LibraryListQueryRef = ProviderRef<LibraryListQuery>;
/// See also [libraryListQuery]. /// See also [libraryListQuery].
@ProviderFor(libraryListQuery) @ProviderFor(libraryListQuery)
const libraryListQueryProvider = LibraryListQueryFamily(); const libraryListQueryProvider = LibraryListQueryFamily();
@@ -108,10 +106,10 @@ class LibraryListQueryFamily extends Family<LibraryListQuery> {
class LibraryListQueryProvider extends Provider<LibraryListQuery> { class LibraryListQueryProvider extends Provider<LibraryListQuery> {
/// See also [libraryListQuery]. /// See also [libraryListQuery].
LibraryListQueryProvider( LibraryListQueryProvider(
this.index, int index,
) : super.internal( ) : this._internal(
(ref) => libraryListQuery( (ref) => libraryListQuery(
ref, ref as LibraryListQueryRef,
index, index,
), ),
from: libraryListQueryProvider, from: libraryListQueryProvider,
@@ -123,10 +121,44 @@ class LibraryListQueryProvider extends Provider<LibraryListQuery> {
dependencies: LibraryListQueryFamily._dependencies, dependencies: LibraryListQueryFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
LibraryListQueryFamily._allTransitiveDependencies, LibraryListQueryFamily._allTransitiveDependencies,
index: index,
); );
LibraryListQueryProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.index,
}) : super.internal();
final int index; final int index;
@override
Override overrideWith(
LibraryListQuery Function(LibraryListQueryRef provider) create,
) {
return ProviderOverride(
origin: this,
override: LibraryListQueryProvider._internal(
(ref) => create(ref as LibraryListQueryRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
index: index,
),
);
}
@override
ProviderElement<LibraryListQuery> createElement() {
return _LibraryListQueryProviderElement(this);
}
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is LibraryListQueryProvider && other.index == index; return other is LibraryListQueryProvider && other.index == index;
@@ -141,6 +173,19 @@ class LibraryListQueryProvider extends Provider<LibraryListQuery> {
} }
} }
mixin LibraryListQueryRef on ProviderRef<LibraryListQuery> {
/// The parameter `index` of this provider.
int get index;
}
class _LibraryListQueryProviderElement extends ProviderElement<LibraryListQuery>
with LibraryListQueryRef {
_LibraryListQueryProviderElement(super.provider);
@override
int get index => (origin as LibraryListQueryProvider).index;
}
String _$lastLibraryStateServiceHash() => String _$lastLibraryStateServiceHash() =>
r'a49e26b5dc0fcb0f697ec2def08e7336f64c4cb3'; r'a49e26b5dc0fcb0f697ec2def08e7336f64c4cb3';
@@ -173,4 +218,5 @@ final libraryListsProvider =
); );
typedef _$LibraryLists = Notifier<IList<LibraryListQuery>>; typedef _$LibraryLists = Notifier<IList<LibraryListQuery>>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -29,8 +29,6 @@ class _SystemHash {
} }
} }
typedef SongsListRef = AutoDisposeFutureProviderRef<List<Song>>;
/// See also [songsList]. /// See also [songsList].
@ProviderFor(songsList) @ProviderFor(songsList)
const songsListProvider = SongsListFamily(); const songsListProvider = SongsListFamily();
@@ -77,10 +75,10 @@ class SongsListFamily extends Family<AsyncValue<List<Song>>> {
class SongsListProvider extends AutoDisposeFutureProvider<List<Song>> { class SongsListProvider extends AutoDisposeFutureProvider<List<Song>> {
/// See also [songsList]. /// See also [songsList].
SongsListProvider( SongsListProvider(
this.opt, ListQuery opt,
) : super.internal( ) : this._internal(
(ref) => songsList( (ref) => songsList(
ref, ref as SongsListRef,
opt, opt,
), ),
from: songsListProvider, from: songsListProvider,
@@ -91,10 +89,44 @@ class SongsListProvider extends AutoDisposeFutureProvider<List<Song>> {
: _$songsListHash, : _$songsListHash,
dependencies: SongsListFamily._dependencies, dependencies: SongsListFamily._dependencies,
allTransitiveDependencies: SongsListFamily._allTransitiveDependencies, allTransitiveDependencies: SongsListFamily._allTransitiveDependencies,
opt: opt,
); );
SongsListProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.opt,
}) : super.internal();
final ListQuery opt; final ListQuery opt;
@override
Override overrideWith(
FutureOr<List<Song>> Function(SongsListRef provider) create,
) {
return ProviderOverride(
origin: this,
override: SongsListProvider._internal(
(ref) => create(ref as SongsListRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
opt: opt,
),
);
}
@override
AutoDisposeFutureProviderElement<List<Song>> createElement() {
return _SongsListProviderElement(this);
}
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is SongsListProvider && other.opt == opt; return other is SongsListProvider && other.opt == opt;
@@ -108,4 +140,18 @@ class SongsListProvider extends AutoDisposeFutureProvider<List<Song>> {
return _SystemHash.finish(hash); return _SystemHash.finish(hash);
} }
} }
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
mixin SongsListRef on AutoDisposeFutureProviderRef<List<Song>> {
/// The parameter `opt` of this provider.
ListQuery get opt;
}
class _SongsListProviderElement
extends AutoDisposeFutureProviderElement<List<Song>> with SongsListRef {
_SongsListProviderElement(super.provider);
@override
ListQuery get opt => (origin as SongsListProvider).opt;
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -55,13 +55,13 @@ class NowPlayingPage extends HookConsumerWidget {
], ],
), ),
), ),
body: Stack( body: const Stack(
children: [ children: [
const MediaItemGradient(), MediaItemGradient(),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8), padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
child: Column( child: Column(
children: const [ children: [
Expanded( Expanded(
child: Padding( child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16), padding: EdgeInsets.symmetric(horizontal: 16),
@@ -215,6 +215,8 @@ class _Progress extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final theme = Theme.of(context);
final colors = ref.watch(mediaItemThemeProvider).valueOrNull; final colors = ref.watch(mediaItemThemeProvider).valueOrNull;
final position = ref.watch(positionProvider); final position = ref.watch(positionProvider);
final duration = ref.watch(durationProvider); final duration = ref.watch(durationProvider);
@@ -229,8 +231,8 @@ class _Progress extends HookConsumerWidget {
value: changing.value ? changeValue.value : position.toDouble(), value: changing.value ? changeValue.value : position.toDouble(),
min: 0, min: 0,
max: max(duration.toDouble(), position.toDouble()), max: max(duration.toDouble(), position.toDouble()),
thumbColor: colors?.theme.colorScheme.onBackground, thumbColor: colors?.theme.colorScheme.surface,
activeColor: colors?.theme.colorScheme.onBackground, activeColor: colors?.theme.colorScheme.surface,
inactiveColor: colors?.theme.colorScheme.surface, inactiveColor: colors?.theme.colorScheme.surface,
onChanged: (value) { onChanged: (value) {
changeValue.value = value; changeValue.value = value;
@@ -246,7 +248,7 @@ class _Progress extends HookConsumerWidget {
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 24), padding: const EdgeInsets.symmetric(horizontal: 24),
child: DefaultTextStyle( child: DefaultTextStyle(
style: Theme.of(context).textTheme.titleMedium!, style: theme.textTheme.titleMedium!,
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@@ -354,7 +356,7 @@ class _Controls extends HookConsumerWidget {
final audio = ref.watch(audioControlProvider); final audio = ref.watch(audioControlProvider);
return IconTheme( return IconTheme(
data: IconThemeData(color: base.theme.colorScheme.onBackground), data: IconThemeData(color: base.theme.colorScheme.surface),
child: Column( child: Column(
children: [ children: [
SizedBox( SizedBox(

View File

@@ -131,11 +131,11 @@ class _SectionHeader extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final theme = Theme.of(context).textTheme; final theme = Theme.of(context);
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text(title, style: theme.headlineMedium), child: Text(title, style: theme.textTheme.headlineMedium),
); );
} }
} }

View File

@@ -35,4 +35,5 @@ final searchQueryProvider =
); );
typedef _$SearchQuery = AutoDisposeNotifier<String?>; typedef _$SearchQuery = AutoDisposeNotifier<String?>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -1,11 +1,16 @@
import 'dart:math';
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:path/path.dart' as p;
import 'package:share_plus/share_plus.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../../log.dart';
import '../../models/support.dart'; import '../../models/support.dart';
import '../../services/settings_service.dart'; import '../../services/settings_service.dart';
import '../../state/init.dart'; import '../../state/init.dart';
@@ -162,6 +167,54 @@ class _About extends HookConsumerWidget {
mode: LaunchMode.externalApplication, mode: LaunchMode.externalApplication,
), ),
), ),
const SizedBox(height: 12),
const _ShareLogsButton(),
],
);
}
}
class _ShareLogsButton extends StatelessWidget {
const _ShareLogsButton();
@override
Widget build(BuildContext context) {
final l = AppLocalizations.of(context);
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
OutlinedButton.icon(
icon: const Icon(Icons.share),
label: Text(l.settingsAboutShareLogs),
onPressed: () async {
final files = await logFiles();
if (files.isEmpty) return;
if (!context.mounted) return;
final value = await showDialog<String>(
context: context,
builder: (context) => MultipleChoiceDialog<String>(
title: l.settingsAboutChooseLog,
current: files.first.path,
options: files
.map((e) => MultiChoiceOption.string(
title: p.basename(e.path),
option: e.path,
))
.toIList(),
),
);
if (value == null) return;
Share.shareXFiles(
[XFile(value, mimeType: 'text/plain')],
subject: 'Logs from subtracks: ${String.fromCharCodes(
List.generate(8, (_) => Random().nextInt(26) + 65),
)}',
);
},
),
], ],
); );
} }

View File

@@ -8,9 +8,11 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../../database/database.dart'; import '../../database/database.dart';
import '../../log.dart';
import '../../models/settings.dart'; import '../../models/settings.dart';
import '../../services/settings_service.dart'; import '../../services/settings_service.dart';
import '../items.dart'; import '../items.dart';
import '../snackbars.dart';
class SourcePage extends HookConsumerWidget { class SourcePage extends HookConsumerWidget {
final int? id; final int? id;
@@ -41,9 +43,10 @@ class SourcePage extends HookConsumerWidget {
label: l.settingsServersFieldsAddress, label: l.settingsServersFieldsAddress,
initialValue: source?.address.toString(), initialValue: source?.address.toString(),
keyboardType: TextInputType.url, keyboardType: TextInputType.url,
autofillHints: const [AutofillHints.url],
required: true, required: true,
validator: (value, label) { validator: (value, label) {
if (Uri.tryParse(value!) == null) { if (!value!.contains(RegExp(r'https?:\/\/'))) {
return '$label must be a valid URL'; return '$label must be a valid URL';
} }
return null; return null;
@@ -52,17 +55,29 @@ class SourcePage extends HookConsumerWidget {
final username = LabeledTextField( final username = LabeledTextField(
label: l.settingsServersFieldsUsername, label: l.settingsServersFieldsUsername,
initialValue: source?.username, initialValue: source?.username,
autofillHints: const [AutofillHints.username],
required: true, required: true,
); );
final password = LabeledTextField( final password = LabeledTextField(
label: l.settingsServersFieldsPassword, label: l.settingsServersFieldsPassword,
initialValue: source?.password, initialValue: source?.password,
obscureText: true, obscureText: true,
autofillHints: const [AutofillHints.password],
required: true, required: true,
); );
return WillPopScope( final forcePlaintextPassword = useState(!(source?.useTokenAuth ?? true));
onWillPop: () async => !isSaving.value && !isDeleting.value, final forcePlaintextSwitch = SwitchListTile(
value: forcePlaintextPassword.value,
title: Text(l.settingsServersOptionsForcePlaintextPasswordTitle),
subtitle: forcePlaintextPassword.value
? Text(l.settingsServersOptionsForcePlaintextPasswordDescriptionOn)
: Text(l.settingsServersOptionsForcePlaintextPasswordDescriptionOff),
onChanged: (value) => forcePlaintextPassword.value = value,
);
return PopScope(
canPop: !isSaving.value && !isDeleting.value,
child: Scaffold( child: Scaffold(
appBar: AppBar(), appBar: AppBar(),
floatingActionButton: Row( floatingActionButton: Row(
@@ -128,6 +143,7 @@ class SourcePage extends HookConsumerWidget {
address: Uri.parse(address.value), address: Uri.parse(address.value),
username: username.value, username: username.value,
password: password.value, password: password.value,
useTokenAuth: !forcePlaintextPassword.value,
), ),
); );
} else { } else {
@@ -142,12 +158,15 @@ class SourcePage extends HookConsumerWidget {
features: IList(), features: IList(),
username: username.value, username: username.value,
password: password.value, password: password.value,
useTokenAuth: const Value(true), useTokenAuth:
Value(!forcePlaintextPassword.value),
), ),
); );
} }
} catch (err) { } catch (e, st) {
// TOOD: toast the error or whatever if (!context.mounted) return;
showErrorSnackbar(context, e.toString());
log.severe('Saving source', e, st);
error = true; error = true;
} finally { } finally {
isSaving.value = false; isSaving.value = false;
@@ -163,21 +182,25 @@ class SourcePage extends HookConsumerWidget {
), ),
body: Form( body: Form(
key: form, key: form,
child: Padding( child: AutofillGroup(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: ListView( child: ListView(
children: [ children: [
const SizedBox(height: 96 - kToolbarHeight), const SizedBox(height: 96 - kToolbarHeight),
Text( Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
source == null source == null
? l.settingsServersActionsAdd ? l.settingsServersActionsAdd
: l.settingsServersActionsEdit, : l.settingsServersActionsEdit,
style: theme.textTheme.displaySmall, style: theme.textTheme.displaySmall,
), ),
),
name, name,
address, address,
username, username,
password, password,
const SizedBox(height: 24),
forcePlaintextSwitch,
const FabPadding(), const FabPadding(),
], ],
), ),
@@ -194,6 +217,7 @@ class LabeledTextField extends HookConsumerWidget {
final bool obscureText; final bool obscureText;
final bool required; final bool required;
final TextInputType? keyboardType; final TextInputType? keyboardType;
final Iterable<String>? autofillHints;
final String? Function(String? value, String label)? validator; final String? Function(String? value, String label)? validator;
// ignore: prefer_const_constructors_in_immutables // ignore: prefer_const_constructors_in_immutables
@@ -204,6 +228,7 @@ class LabeledTextField extends HookConsumerWidget {
this.obscureText = false, this.obscureText = false,
this.keyboardType, this.keyboardType,
this.validator, this.validator,
this.autofillHints,
this.required = false, this.required = false,
}); });
@@ -224,18 +249,18 @@ class LabeledTextField extends HookConsumerWidget {
final theme = Theme.of(context); final theme = Theme.of(context);
_controller = useTextEditingController(text: initialValue); _controller = useTextEditingController(text: initialValue);
return Column( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
const SizedBox(height: 24), const SizedBox(height: 24),
Text( Text(label, style: theme.textTheme.titleMedium),
label,
style: theme.textTheme.titleMedium,
),
TextFormField( TextFormField(
controller: _controller, controller: _controller,
obscureText: obscureText, obscureText: obscureText,
keyboardType: keyboardType, keyboardType: keyboardType,
autofillHints: autofillHints,
validator: (value) { validator: (value) {
String? error; String? error;
@@ -253,6 +278,7 @@ class LabeledTextField extends HookConsumerWidget {
}, },
), ),
], ],
),
); );
} }
} }

14
lib/app/snackbars.dart Normal file
View File

@@ -0,0 +1,14 @@
import 'package:flutter/material.dart';
void showErrorSnackbar(BuildContext context, String message) {
final colors = Theme.of(context).colorScheme;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(message, style: TextStyle(color: colors.onErrorContainer)),
backgroundColor: colors.errorContainer,
showCloseIcon: true,
closeIconColor: colors.onErrorContainer,
behavior: SnackBarBehavior.floating,
duration: const Duration(seconds: 10),
));
}

View File

@@ -20,4 +20,5 @@ final imageCacheProvider = Provider<CacheManager>.internal(
); );
typedef ImageCacheRef = ProviderRef<CacheManager>; typedef ImageCacheRef = ProviderRef<CacheManager>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -9,14 +9,20 @@ import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../log.dart';
import '../models/music.dart'; import '../models/music.dart';
import '../models/query.dart'; import '../models/query.dart';
import '../models/settings.dart'; import '../models/settings.dart';
import '../models/support.dart'; import '../models/support.dart';
import 'converters.dart'; import 'converters.dart';
import 'error_logging_database.dart';
part 'database.g.dart'; part 'database.g.dart';
// don't exceed SQLITE_MAX_VARIABLE_NUMBER (32766 for version >= 3.32.0)
// https://www.sqlite.org/limits.html
const kSqliteMaxVariableNumber = 32766;
@DriftDatabase(include: {'tables.drift'}) @DriftDatabase(include: {'tables.drift'})
class SubtracksDatabase extends _$SubtracksDatabase { class SubtracksDatabase extends _$SubtracksDatabase {
SubtracksDatabase() : super(_openConnection()); SubtracksDatabase() : super(_openConnection());
@@ -169,13 +175,28 @@ class SubtracksDatabase extends _$SubtracksDatabase {
}); });
} }
Future<void> deleteArtistsNotIn(int sourceId, Iterable<String> ids) async { Future<void> deleteArtistsNotIn(int sourceId, Set<String> ids) {
return transaction(() async {
final allIds = (await (selectOnly(artists)
..addColumns([artists.id])
..where(artists.sourceId.equals(sourceId)))
.map((row) => row.read(artists.id))
.get())
.whereNotNull()
.toSet();
final downloadIds = (await artistIdsWithDownloadStatus(sourceId).get())
.whereNotNull()
.toSet();
final diff = allIds.difference(downloadIds).difference(ids);
for (var slice in diff.slices(kSqliteMaxVariableNumber)) {
await (delete(artists) await (delete(artists)
..where( ..where(
(tbl) => tbl.sourceId.equals(sourceId) & tbl.id.isNotIn(ids), (tbl) => tbl.sourceId.equals(sourceId) & tbl.id.isIn(slice)))
))
.go(); .go();
} }
});
}
Future<void> saveAlbums(Iterable<AlbumsCompanion> albums) async { Future<void> saveAlbums(Iterable<AlbumsCompanion> albums) async {
await batch((batch) { await batch((batch) {
@@ -183,16 +204,28 @@ class SubtracksDatabase extends _$SubtracksDatabase {
}); });
} }
Future<void> deleteAlbumsNotIn(int sourceId, Iterable<String> ids) async { Future<void> deleteAlbumsNotIn(int sourceId, Set<String> ids) {
final alsoKeep = (await albumIdsWithDownloaded(sourceId).get()).toSet(); return transaction(() async {
final allIds = (await (selectOnly(albums)
..addColumns([albums.id])
..where(albums.sourceId.equals(sourceId)))
.map((row) => row.read(albums.id))
.get())
.whereNotNull()
.toSet();
final downloadIds = (await albumIdsWithDownloadStatus(sourceId).get())
.whereNotNull()
.toSet();
ids = ids.toList()..addAll(alsoKeep); final diff = allIds.difference(downloadIds).difference(ids);
for (var slice in diff.slices(kSqliteMaxVariableNumber)) {
await (delete(albums) await (delete(albums)
..where( ..where(
(tbl) => tbl.sourceId.equals(sourceId) & tbl.id.isNotIn(ids), (tbl) => tbl.sourceId.equals(sourceId) & tbl.id.isIn(slice)))
))
.go(); .go();
} }
});
}
Future<void> savePlaylists( Future<void> savePlaylists(
Iterable<PlaylistWithSongsCompanion> playlistsWithSongs, Iterable<PlaylistWithSongsCompanion> playlistsWithSongs,
@@ -215,19 +248,32 @@ class SubtracksDatabase extends _$SubtracksDatabase {
}); });
} }
Future<void> deletePlaylistsNotIn(int sourceId, Iterable<String> ids) async { Future<void> deletePlaylistsNotIn(int sourceId, Set<String> ids) {
return transaction(() async {
final allIds = (await (selectOnly(playlists)
..addColumns([playlists.id])
..where(playlists.sourceId.equals(sourceId)))
.map((row) => row.read(playlists.id))
.get())
.whereNotNull()
.toSet();
final downloadIds = (await playlistIdsWithDownloadStatus(sourceId).get())
.whereNotNull()
.toSet();
final diff = allIds.difference(downloadIds).difference(ids);
for (var slice in diff.slices(kSqliteMaxVariableNumber)) {
await (delete(playlists) await (delete(playlists)
..where( ..where(
(tbl) => tbl.sourceId.equals(sourceId) & tbl.id.isNotIn(ids), (tbl) => tbl.sourceId.equals(sourceId) & tbl.id.isIn(slice)))
))
.go(); .go();
await (delete(playlistSongs) await (delete(playlistSongs)
..where( ..where((tbl) =>
(tbl) => tbl.sourceId.equals(sourceId) & tbl.playlistId.isIn(slice)))
tbl.sourceId.equals(sourceId) & tbl.playlistId.isNotIn(ids),
))
.go(); .go();
} }
});
}
Future<void> savePlaylistSongs( Future<void> savePlaylistSongs(
int sourceId, int sourceId,
@@ -250,30 +296,34 @@ class SubtracksDatabase extends _$SubtracksDatabase {
}); });
} }
Future<void> deleteSongsNotIn(int sourceId, Iterable<String> ids) async { Future<void> deleteSongsNotIn(int sourceId, Set<String> ids) {
await (delete(songs) return transaction(() async {
..where( final allIds = (await (selectOnly(songs)
(tbl) =>
tbl.sourceId.equals(sourceId) &
tbl.id.isNotIn(ids) &
tbl.downloadFilePath.isNull() &
tbl.downloadTaskId.isNull(),
))
.go();
final remainingIds = (await (selectOnly(songs)
..addColumns([songs.id]) ..addColumns([songs.id])
..where(songs.sourceId.equals(sourceId))) ..where(
songs.sourceId.equals(sourceId) &
songs.downloadFilePath.isNull() &
songs.downloadTaskId.isNull(),
))
.map((row) => row.read(songs.id)) .map((row) => row.read(songs.id))
.get()) .get())
.whereNotNull(); .whereNotNull()
.toSet();
final diff = allIds.difference(ids);
for (var slice in diff.slices(kSqliteMaxVariableNumber)) {
await (delete(songs)
..where(
(tbl) => tbl.sourceId.equals(sourceId) & tbl.id.isIn(slice)))
.go();
await (delete(playlistSongs) await (delete(playlistSongs)
..where( ..where(
(tbl) => (tbl) => tbl.sourceId.equals(sourceId) & tbl.songId.isIn(slice),
tbl.sourceId.equals(sourceId) &
tbl.songId.isNotIn(remainingIds),
)) ))
.go(); .go();
} }
});
}
Selectable<LastBottomNavStateData> getLastBottomNavState() { Selectable<LastBottomNavStateData> getLastBottomNavState() {
return select(lastBottomNavState)..where((tbl) => tbl.id.equals(1)); return select(lastBottomNavState)..where((tbl) => tbl.id.equals(1));
@@ -387,7 +437,11 @@ LazyDatabase _openConnection() {
final dbFolder = await getApplicationDocumentsDirectory(); final dbFolder = await getApplicationDocumentsDirectory();
final file = File(p.join(dbFolder.path, 'subtracks.sqlite')); final file = File(p.join(dbFolder.path, 'subtracks.sqlite'));
// return NativeDatabase.createInBackground(file, logStatements: true); // return NativeDatabase.createInBackground(file, logStatements: true);
return NativeDatabase.createInBackground(file);
return ErrorLoggingDatabase(
NativeDatabase.createInBackground(file),
(e, s) => log.severe('SQL error', e, s),
);
}); });
} }

View File

@@ -53,9 +53,10 @@ class Queue extends Table with TableInfo<Queue, QueueData> {
List<GeneratedColumn> get $columns => List<GeneratedColumn> get $columns =>
[index, sourceId, id, context, contextId, currentTrack]; [index, sourceId, id, context, contextId, currentTrack];
@override @override
String get aliasedName => _alias ?? 'queue'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'queue'; String get actualTableName => $name;
static const String $name = 'queue';
@override @override
VerificationContext validateIntegrity(Insertable<QueueData> instance, VerificationContext validateIntegrity(Insertable<QueueData> instance,
{bool isInserting = false}) { {bool isInserting = false}) {
@@ -144,8 +145,7 @@ class QueueData extends DataClass implements Insertable<QueueData> {
map['source_id'] = Variable<int>(sourceId); map['source_id'] = Variable<int>(sourceId);
map['id'] = Variable<String>(id); map['id'] = Variable<String>(id);
{ {
final converter = Queue.$convertercontext; map['context'] = Variable<String>(Queue.$convertercontext.toSql(context));
map['context'] = Variable<String>(converter.toSql(context));
} }
if (!nullToAbsent || contextId != null) { if (!nullToAbsent || contextId != null) {
map['context_id'] = Variable<String>(contextId); map['context_id'] = Variable<String>(contextId);
@@ -315,8 +315,8 @@ class QueueCompanion extends UpdateCompanion<QueueData> {
map['id'] = Variable<String>(id.value); map['id'] = Variable<String>(id.value);
} }
if (context.present) { if (context.present) {
final converter = Queue.$convertercontext; map['context'] =
map['context'] = Variable<String>(converter.toSql(context.value)); Variable<String>(Queue.$convertercontext.toSql(context.value));
} }
if (contextId.present) { if (contextId.present) {
map['context_id'] = Variable<String>(contextId.value); map['context_id'] = Variable<String>(contextId.value);
@@ -382,9 +382,10 @@ class LastAudioState extends Table
List<GeneratedColumn> get $columns => List<GeneratedColumn> get $columns =>
[id, queueMode, shuffleIndicies, repeat]; [id, queueMode, shuffleIndicies, repeat];
@override @override
String get aliasedName => _alias ?? 'last_audio_state'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'last_audio_state'; String get actualTableName => $name;
static const String $name = 'last_audio_state';
@override @override
VerificationContext validateIntegrity(Insertable<LastAudioStateData> instance, VerificationContext validateIntegrity(Insertable<LastAudioStateData> instance,
{bool isInserting = false}) { {bool isInserting = false}) {
@@ -452,17 +453,16 @@ class LastAudioStateData extends DataClass
final map = <String, Expression>{}; final map = <String, Expression>{};
map['id'] = Variable<int>(id); map['id'] = Variable<int>(id);
{ {
final converter = LastAudioState.$converterqueueMode; map['queue_mode'] =
map['queue_mode'] = Variable<int>(converter.toSql(queueMode)); Variable<int>(LastAudioState.$converterqueueMode.toSql(queueMode));
} }
if (!nullToAbsent || shuffleIndicies != null) { if (!nullToAbsent || shuffleIndicies != null) {
final converter = LastAudioState.$convertershuffleIndiciesn; map['shuffle_indicies'] = Variable<String>(
map['shuffle_indicies'] = LastAudioState.$convertershuffleIndiciesn.toSql(shuffleIndicies));
Variable<String>(converter.toSql(shuffleIndicies));
} }
{ {
final converter = LastAudioState.$converterrepeat; map['repeat'] =
map['repeat'] = Variable<int>(converter.toSql(repeat)); Variable<int>(LastAudioState.$converterrepeat.toSql(repeat));
} }
return map; return map;
} }
@@ -592,17 +592,17 @@ class LastAudioStateCompanion extends UpdateCompanion<LastAudioStateData> {
map['id'] = Variable<int>(id.value); map['id'] = Variable<int>(id.value);
} }
if (queueMode.present) { if (queueMode.present) {
final converter = LastAudioState.$converterqueueMode; map['queue_mode'] = Variable<int>(
map['queue_mode'] = Variable<int>(converter.toSql(queueMode.value)); LastAudioState.$converterqueueMode.toSql(queueMode.value));
} }
if (shuffleIndicies.present) { if (shuffleIndicies.present) {
final converter = LastAudioState.$convertershuffleIndiciesn; map['shuffle_indicies'] = Variable<String>(LastAudioState
map['shuffle_indicies'] = .$convertershuffleIndiciesn
Variable<String>(converter.toSql(shuffleIndicies.value)); .toSql(shuffleIndicies.value));
} }
if (repeat.present) { if (repeat.present) {
final converter = LastAudioState.$converterrepeat; map['repeat'] =
map['repeat'] = Variable<int>(converter.toSql(repeat.value)); Variable<int>(LastAudioState.$converterrepeat.toSql(repeat.value));
} }
return map; return map;
} }
@@ -640,9 +640,10 @@ class LastBottomNavState extends Table
@override @override
List<GeneratedColumn> get $columns => [id, tab]; List<GeneratedColumn> get $columns => [id, tab];
@override @override
String get aliasedName => _alias ?? 'last_bottom_nav_state'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'last_bottom_nav_state'; String get actualTableName => $name;
static const String $name = 'last_bottom_nav_state';
@override @override
VerificationContext validateIntegrity( VerificationContext validateIntegrity(
Insertable<LastBottomNavStateData> instance, Insertable<LastBottomNavStateData> instance,
@@ -849,9 +850,10 @@ class LastLibraryState extends Table
List<GeneratedColumn> get $columns => List<GeneratedColumn> get $columns =>
[id, tab, albumsList, artistsList, playlistsList, songsList]; [id, tab, albumsList, artistsList, playlistsList, songsList];
@override @override
String get aliasedName => _alias ?? 'last_library_state'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'last_library_state'; String get actualTableName => $name;
static const String $name = 'last_library_state';
@override @override
VerificationContext validateIntegrity( VerificationContext validateIntegrity(
Insertable<LastLibraryStateData> instance, Insertable<LastLibraryStateData> instance,
@@ -937,20 +939,20 @@ class LastLibraryStateData extends DataClass
map['id'] = Variable<int>(id); map['id'] = Variable<int>(id);
map['tab'] = Variable<String>(tab); map['tab'] = Variable<String>(tab);
{ {
final converter = LastLibraryState.$converteralbumsList; map['albums_list'] = Variable<String>(
map['albums_list'] = Variable<String>(converter.toSql(albumsList)); LastLibraryState.$converteralbumsList.toSql(albumsList));
} }
{ {
final converter = LastLibraryState.$converterartistsList; map['artists_list'] = Variable<String>(
map['artists_list'] = Variable<String>(converter.toSql(artistsList)); LastLibraryState.$converterartistsList.toSql(artistsList));
} }
{ {
final converter = LastLibraryState.$converterplaylistsList; map['playlists_list'] = Variable<String>(
map['playlists_list'] = Variable<String>(converter.toSql(playlistsList)); LastLibraryState.$converterplaylistsList.toSql(playlistsList));
} }
{ {
final converter = LastLibraryState.$convertersongsList; map['songs_list'] = Variable<String>(
map['songs_list'] = Variable<String>(converter.toSql(songsList)); LastLibraryState.$convertersongsList.toSql(songsList));
} }
return map; return map;
} }
@@ -1106,22 +1108,20 @@ class LastLibraryStateCompanion extends UpdateCompanion<LastLibraryStateData> {
map['tab'] = Variable<String>(tab.value); map['tab'] = Variable<String>(tab.value);
} }
if (albumsList.present) { if (albumsList.present) {
final converter = LastLibraryState.$converteralbumsList; map['albums_list'] = Variable<String>(
map['albums_list'] = Variable<String>(converter.toSql(albumsList.value)); LastLibraryState.$converteralbumsList.toSql(albumsList.value));
} }
if (artistsList.present) { if (artistsList.present) {
final converter = LastLibraryState.$converterartistsList; map['artists_list'] = Variable<String>(
map['artists_list'] = LastLibraryState.$converterartistsList.toSql(artistsList.value));
Variable<String>(converter.toSql(artistsList.value));
} }
if (playlistsList.present) { if (playlistsList.present) {
final converter = LastLibraryState.$converterplaylistsList; map['playlists_list'] = Variable<String>(
map['playlists_list'] = LastLibraryState.$converterplaylistsList.toSql(playlistsList.value));
Variable<String>(converter.toSql(playlistsList.value));
} }
if (songsList.present) { if (songsList.present) {
final converter = LastLibraryState.$convertersongsList; map['songs_list'] = Variable<String>(
map['songs_list'] = Variable<String>(converter.toSql(songsList.value)); LastLibraryState.$convertersongsList.toSql(songsList.value));
} }
return map; return map;
} }
@@ -1177,9 +1177,10 @@ class AppSettingsTable extends Table
List<GeneratedColumn> get $columns => List<GeneratedColumn> get $columns =>
[id, maxBitrateWifi, maxBitrateMobile, streamFormat]; [id, maxBitrateWifi, maxBitrateMobile, streamFormat];
@override @override
String get aliasedName => _alias ?? 'app_settings'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'app_settings'; String get actualTableName => $name;
static const String $name = 'app_settings';
@override @override
VerificationContext validateIntegrity(Insertable<AppSettings> instance, VerificationContext validateIntegrity(Insertable<AppSettings> instance,
{bool isInserting = false}) { {bool isInserting = false}) {
@@ -1359,9 +1360,10 @@ class Sources extends Table with TableInfo<Sources, Source> {
List<GeneratedColumn> get $columns => List<GeneratedColumn> get $columns =>
[id, name, address, isActive, createdAt]; [id, name, address, isActive, createdAt];
@override @override
String get aliasedName => _alias ?? 'sources'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'sources'; String get actualTableName => $name;
static const String $name = 'sources';
@override @override
VerificationContext validateIntegrity(Insertable<Source> instance, VerificationContext validateIntegrity(Insertable<Source> instance,
{bool isInserting = false}) { {bool isInserting = false}) {
@@ -1435,8 +1437,8 @@ class Source extends DataClass implements Insertable<Source> {
map['id'] = Variable<int>(id); map['id'] = Variable<int>(id);
map['name'] = Variable<String>(name); map['name'] = Variable<String>(name);
{ {
final converter = Sources.$converteraddress; map['address'] =
map['address'] = Variable<String>(converter.toSql(address)); Variable<String>(Sources.$converteraddress.toSql(address));
} }
if (!nullToAbsent || isActive != null) { if (!nullToAbsent || isActive != null) {
map['is_active'] = Variable<bool>(isActive); map['is_active'] = Variable<bool>(isActive);
@@ -1580,8 +1582,8 @@ class SourcesCompanion extends UpdateCompanion<Source> {
map['name'] = Variable<String>(name.value); map['name'] = Variable<String>(name.value);
} }
if (address.present) { if (address.present) {
final converter = Sources.$converteraddress; map['address'] =
map['address'] = Variable<String>(converter.toSql(address.value)); Variable<String>(Sources.$converteraddress.toSql(address.value));
} }
if (isActive.present) { if (isActive.present) {
map['is_active'] = Variable<bool>(isActive.value); map['is_active'] = Variable<bool>(isActive.value);
@@ -1653,9 +1655,10 @@ class SubsonicSources extends Table
List<GeneratedColumn> get $columns => List<GeneratedColumn> get $columns =>
[sourceId, features, username, password, useTokenAuth]; [sourceId, features, username, password, useTokenAuth];
@override @override
String get aliasedName => _alias ?? 'subsonic_sources'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'subsonic_sources'; String get actualTableName => $name;
static const String $name = 'subsonic_sources';
@override @override
VerificationContext validateIntegrity(Insertable<SubsonicSource> instance, VerificationContext validateIntegrity(Insertable<SubsonicSource> instance,
{bool isInserting = false}) { {bool isInserting = false}) {
@@ -1738,8 +1741,8 @@ class SubsonicSource extends DataClass implements Insertable<SubsonicSource> {
final map = <String, Expression>{}; final map = <String, Expression>{};
map['source_id'] = Variable<int>(sourceId); map['source_id'] = Variable<int>(sourceId);
{ {
final converter = SubsonicSources.$converterfeatures; map['features'] =
map['features'] = Variable<String>(converter.toSql(features)); Variable<String>(SubsonicSources.$converterfeatures.toSql(features));
} }
map['username'] = Variable<String>(username); map['username'] = Variable<String>(username);
map['password'] = Variable<String>(password); map['password'] = Variable<String>(password);
@@ -1879,8 +1882,8 @@ class SubsonicSourcesCompanion extends UpdateCompanion<SubsonicSource> {
map['source_id'] = Variable<int>(sourceId.value); map['source_id'] = Variable<int>(sourceId.value);
} }
if (features.present) { if (features.present) {
final converter = SubsonicSources.$converterfeatures; map['features'] = Variable<String>(
map['features'] = Variable<String>(converter.toSql(features.value)); SubsonicSources.$converterfeatures.toSql(features.value));
} }
if (username.present) { if (username.present) {
map['username'] = Variable<String>(username.value); map['username'] = Variable<String>(username.value);
@@ -1959,9 +1962,10 @@ class Artists extends Table with TableInfo<Artists, Artist> {
List<GeneratedColumn> get $columns => List<GeneratedColumn> get $columns =>
[sourceId, id, name, albumCount, starred, updated]; [sourceId, id, name, albumCount, starred, updated];
@override @override
String get aliasedName => _alias ?? 'artists'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'artists'; String get actualTableName => $name;
static const String $name = 'artists';
@override @override
VerificationContext validateIntegrity(Insertable<Artist> instance, VerificationContext validateIntegrity(Insertable<Artist> instance,
{bool isInserting = false}) { {bool isInserting = false}) {
@@ -2170,9 +2174,10 @@ class ArtistsFts extends Table
@override @override
List<GeneratedColumn> get $columns => [sourceId, name]; List<GeneratedColumn> get $columns => [sourceId, name];
@override @override
String get aliasedName => _alias ?? 'artists_fts'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'artists_fts'; String get actualTableName => $name;
static const String $name = 'artists_fts';
@override @override
VerificationContext validateIntegrity(Insertable<ArtistsFt> instance, VerificationContext validateIntegrity(Insertable<ArtistsFt> instance,
{bool isInserting = false}) { {bool isInserting = false}) {
@@ -2468,9 +2473,10 @@ class Albums extends Table with TableInfo<Albums, Album> {
updated updated
]; ];
@override @override
String get aliasedName => _alias ?? 'albums'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'albums'; String get actualTableName => $name;
static const String $name = 'albums';
@override @override
VerificationContext validateIntegrity(Insertable<Album> instance, VerificationContext validateIntegrity(Insertable<Album> instance,
{bool isInserting = false}) { {bool isInserting = false}) {
@@ -2837,9 +2843,10 @@ class AlbumsFts extends Table
@override @override
List<GeneratedColumn> get $columns => [sourceId, name]; List<GeneratedColumn> get $columns => [sourceId, name];
@override @override
String get aliasedName => _alias ?? 'albums_fts'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'albums_fts'; String get actualTableName => $name;
static const String $name = 'albums_fts';
@override @override
VerificationContext validateIntegrity(Insertable<AlbumsFt> instance, VerificationContext validateIntegrity(Insertable<AlbumsFt> instance,
{bool isInserting = false}) { {bool isInserting = false}) {
@@ -3072,9 +3079,10 @@ class Playlists extends Table with TableInfo<Playlists, Playlist> {
List<GeneratedColumn> get $columns => List<GeneratedColumn> get $columns =>
[sourceId, id, name, comment, coverArt, songCount, created, updated]; [sourceId, id, name, comment, coverArt, songCount, created, updated];
@override @override
String get aliasedName => _alias ?? 'playlists'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'playlists'; String get actualTableName => $name;
static const String $name = 'playlists';
@override @override
VerificationContext validateIntegrity(Insertable<Playlist> instance, VerificationContext validateIntegrity(Insertable<Playlist> instance,
{bool isInserting = false}) { {bool isInserting = false}) {
@@ -3340,9 +3348,10 @@ class PlaylistSongs extends Table with TableInfo<PlaylistSongs, PlaylistSong> {
List<GeneratedColumn> get $columns => List<GeneratedColumn> get $columns =>
[sourceId, playlistId, songId, position, updated]; [sourceId, playlistId, songId, position, updated];
@override @override
String get aliasedName => _alias ?? 'playlist_songs'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'playlist_songs'; String get actualTableName => $name;
static const String $name = 'playlist_songs';
@override @override
VerificationContext validateIntegrity(Insertable<PlaylistSong> instance, VerificationContext validateIntegrity(Insertable<PlaylistSong> instance,
{bool isInserting = false}) { {bool isInserting = false}) {
@@ -3632,9 +3641,10 @@ class PlaylistsFts extends Table
@override @override
List<GeneratedColumn> get $columns => [sourceId, name]; List<GeneratedColumn> get $columns => [sourceId, name];
@override @override
String get aliasedName => _alias ?? 'playlists_fts'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'playlists_fts'; String get actualTableName => $name;
static const String $name = 'playlists_fts';
@override @override
VerificationContext validateIntegrity(Insertable<PlaylistsFt> instance, VerificationContext validateIntegrity(Insertable<PlaylistsFt> instance,
{bool isInserting = false}) { {bool isInserting = false}) {
@@ -3936,9 +3946,10 @@ class Songs extends Table with TableInfo<Songs, Song> {
updated updated
]; ];
@override @override
String get aliasedName => _alias ?? 'songs'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'songs'; String get actualTableName => $name;
static const String $name = 'songs';
@override @override
VerificationContext validateIntegrity(Insertable<Song> instance, VerificationContext validateIntegrity(Insertable<Song> instance,
{bool isInserting = false}) { {bool isInserting = false}) {
@@ -4236,8 +4247,8 @@ class SongsCompanion extends UpdateCompanion<Song> {
map['artist'] = Variable<String>(artist.value); map['artist'] = Variable<String>(artist.value);
} }
if (duration.present) { if (duration.present) {
final converter = Songs.$converterdurationn; map['duration'] =
map['duration'] = Variable<int>(converter.toSql(duration.value)); Variable<int>(Songs.$converterdurationn.toSql(duration.value));
} }
if (track.present) { if (track.present) {
map['track'] = Variable<int>(track.value); map['track'] = Variable<int>(track.value);
@@ -4316,9 +4327,10 @@ class SongsFts extends Table
@override @override
List<GeneratedColumn> get $columns => [sourceId, title]; List<GeneratedColumn> get $columns => [sourceId, title];
@override @override
String get aliasedName => _alias ?? 'songs_fts'; String get aliasedName => _alias ?? actualTableName;
@override @override
String get actualTableName => 'songs_fts'; String get actualTableName => $name;
static const String $name = 'songs_fts';
@override @override
VerificationContext validateIntegrity(Insertable<SongsFt> instance, VerificationContext validateIntegrity(Insertable<SongsFt> instance,
{bool isInserting = false}) { {bool isInserting = false}) {
@@ -4596,7 +4608,7 @@ abstract class _$SubtracksDatabase extends GeneratedDatabase {
)); ));
} }
Selectable<String> albumIdsWithDownloaded(int sourceId) { Selectable<String> albumIdsWithDownloadStatus(int sourceId) {
return customSelect( return customSelect(
'SELECT albums.id FROM albums JOIN songs ON songs.source_id = albums.source_id AND songs.album_id = albums.id WHERE albums.source_id = ?1 AND(songs.download_file_path IS NOT NULL OR songs.download_task_id IS NOT NULL)GROUP BY albums.id', 'SELECT albums.id FROM albums JOIN songs ON songs.source_id = albums.source_id AND songs.album_id = albums.id WHERE albums.source_id = ?1 AND(songs.download_file_path IS NOT NULL OR songs.download_task_id IS NOT NULL)GROUP BY albums.id',
variables: [ variables: [
@@ -4608,6 +4620,32 @@ abstract class _$SubtracksDatabase extends GeneratedDatabase {
}).map((QueryRow row) => row.read<String>('id')); }).map((QueryRow row) => row.read<String>('id'));
} }
Selectable<String> artistIdsWithDownloadStatus(int sourceId) {
return customSelect(
'SELECT artists.id FROM artists LEFT JOIN albums ON artists.source_id = albums.source_id AND artists.id = albums.artist_id LEFT JOIN songs ON albums.source_id = songs.source_id AND albums.id = songs.album_id WHERE artists.source_id = ?1 AND(songs.download_file_path IS NOT NULL OR songs.download_task_id IS NOT NULL)GROUP BY artists.id',
variables: [
Variable<int>(sourceId)
],
readsFrom: {
artists,
albums,
songs,
}).map((QueryRow row) => row.read<String>('id'));
}
Selectable<String> playlistIdsWithDownloadStatus(int sourceId) {
return customSelect(
'SELECT playlists.id FROM playlists LEFT JOIN playlist_songs ON playlist_songs.source_id = playlists.source_id AND playlist_songs.playlist_id = playlists.id LEFT JOIN songs ON playlist_songs.source_id = songs.source_id AND playlist_songs.song_id = songs.id WHERE playlists.source_id = ?1 AND(songs.download_file_path IS NOT NULL OR songs.download_task_id IS NOT NULL)GROUP BY playlists.id',
variables: [
Variable<int>(sourceId)
],
readsFrom: {
playlists,
playlistSongs,
songs,
}).map((QueryRow row) => row.read<String>('id'));
}
Selectable<int> searchArtists(String query, int limit, int offset) { Selectable<int> searchArtists(String query, int limit, int offset) {
return customSelect( return customSelect(
'SELECT "rowid" FROM artists_fts WHERE artists_fts MATCH ?1 ORDER BY rank LIMIT ?2 OFFSET ?3', 'SELECT "rowid" FROM artists_fts WHERE artists_fts MATCH ?1 ORDER BY rank LIMIT ?2 OFFSET ?3',
@@ -5544,4 +5582,5 @@ final databaseProvider = Provider<SubtracksDatabase>.internal(
); );
typedef DatabaseRef = ProviderRef<SubtracksDatabase>; typedef DatabaseRef = ProviderRef<SubtracksDatabase>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -0,0 +1,94 @@
import 'dart:async';
import 'package:drift/drift.dart';
import 'package:drift/isolate.dart';
/// https://github.com/simolus3/drift/issues/2326#issuecomment-1445138730
class ErrorLoggingDatabase implements QueryExecutor {
final QueryExecutor inner;
final void Function(Object, StackTrace) onError;
ErrorLoggingDatabase(this.inner, this.onError);
Future<T> _handleErrors<T>(Future<T> Function() body) {
return Future.sync(body)
.onError<DriftWrappedException>((error, stackTrace) {
onError(error, error.trace ?? stackTrace);
throw error;
}).onError<DriftRemoteException>((error, stackTrace) {
onError(error, error.remoteStackTrace ?? stackTrace);
throw error;
});
}
@override
TransactionExecutor beginTransaction() {
return _ErrorLoggingTransactionExecutor(inner.beginTransaction(), onError);
}
@override
Future<void> close() {
return _handleErrors(inner.close);
}
@override
SqlDialect get dialect => inner.dialect;
@override
Future<bool> ensureOpen(QueryExecutorUser user) {
return _handleErrors(() => inner.ensureOpen(user));
}
@override
Future<void> runBatched(BatchedStatements statements) {
return _handleErrors(() => inner.runBatched(statements));
}
@override
Future<void> runCustom(String statement, [List<Object?>? args]) {
return _handleErrors(() => inner.runCustom(statement, args));
}
@override
Future<int> runDelete(String statement, List<Object?> args) {
return _handleErrors(() => inner.runDelete(statement, args));
}
@override
Future<int> runInsert(String statement, List<Object?> args) {
return _handleErrors(() => inner.runInsert(statement, args));
}
@override
Future<List<Map<String, Object?>>> runSelect(
String statement, List<Object?> args) {
return _handleErrors(() => inner.runSelect(statement, args));
}
@override
Future<int> runUpdate(String statement, List<Object?> args) {
return _handleErrors(() => inner.runUpdate(statement, args));
}
}
class _ErrorLoggingTransactionExecutor extends ErrorLoggingDatabase
implements TransactionExecutor {
final TransactionExecutor transaction;
_ErrorLoggingTransactionExecutor(
this.transaction, void Function(Object, StackTrace) onError)
: super(transaction, onError);
@override
Future<void> rollback() {
return _handleErrors(transaction.rollback);
}
@override
Future<void> send() {
return _handleErrors(transaction.send);
}
@override
bool get supportsNestedTransactions => transaction.supportsNestedTransactions;
}

View File

@@ -244,7 +244,7 @@ allSubsonicSources WITH SubsonicSettings:
FROM sources FROM sources
JOIN subsonic_sources ON subsonic_sources.source_id = sources.id; JOIN subsonic_sources ON subsonic_sources.source_id = sources.id;
albumIdsWithDownloaded: albumIdsWithDownloadStatus:
SELECT albums.id SELECT albums.id
FROM albums FROM albums
JOIN songs on songs.source_id = albums.source_id AND songs.album_id = albums.id JOIN songs on songs.source_id = albums.source_id AND songs.album_id = albums.id
@@ -253,6 +253,26 @@ albumIdsWithDownloaded:
AND (songs.download_file_path IS NOT NULL OR songs.download_task_id IS NOT NULL) AND (songs.download_file_path IS NOT NULL OR songs.download_task_id IS NOT NULL)
GROUP BY albums.id; GROUP BY albums.id;
artistIdsWithDownloadStatus:
SELECT artists.id
FROM artists
LEFT JOIN albums ON artists.source_id = albums.source_id AND artists.id = albums.artist_id
LEFT JOIN songs ON albums.source_id = songs.source_id AND albums.id = songs.album_id
WHERE
artists.source_id = :source_id
AND (songs.download_file_path IS NOT NULL OR songs.download_task_id IS NOT NULL)
GROUP BY artists.id;
playlistIdsWithDownloadStatus:
SELECT playlists.id
FROM playlists
LEFT JOIN playlist_songs ON playlist_songs.source_id = playlists.source_id AND playlist_songs.playlist_id = playlists.id
LEFT JOIN songs ON playlist_songs.source_id = songs.source_id AND playlist_songs.song_id = songs.id
WHERE
playlists.source_id = :source_id
AND (songs.download_file_path IS NOT NULL OR songs.download_task_id IS NOT NULL)
GROUP BY playlists.id;
searchArtists: searchArtists:
SELECT rowid SELECT rowid
FROM artists_fts FROM artists_fts

View File

@@ -1,7 +1,8 @@
import 'package:flutter/foundation.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../log.dart';
part 'client.g.dart'; part 'client.g.dart';
const Map<String, String> subtracksHeaders = { const Map<String, String> subtracksHeaders = {
@@ -14,8 +15,14 @@ class SubtracksHttpClient extends BaseClient {
@override @override
Future<StreamedResponse> send(BaseRequest request) { Future<StreamedResponse> send(BaseRequest request) {
request.headers.addAll(subtracksHeaders); request.headers.addAll(subtracksHeaders);
if (kDebugMode) print('${request.method} ${request.url}'); log.info('${request.method} ${request.url}');
try {
return request.send(); return request.send();
} catch (e, st) {
log.severe('HTTP client: ${request.method} ${request.url}', e, st);
rethrow;
}
} }
} }

View File

@@ -20,4 +20,5 @@ final httpClientProvider = Provider<BaseClient>.internal(
); );
typedef HttpClientRef = ProviderRef<BaseClient>; typedef HttpClientRef = ProviderRef<BaseClient>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -73,17 +73,17 @@
}, },
"resourcesSortByAdded": "Nedávno přidané", "resourcesSortByAdded": "Nedávno přidané",
"@resourcesSortByAdded": {}, "@resourcesSortByAdded": {},
"resourcesSortByArtist": "Podle umělce", "resourcesSortByArtist": "Umělce",
"@resourcesSortByArtist": {}, "@resourcesSortByArtist": {},
"resourcesSortByFrequentlyPlayed": "Často přehrávané", "resourcesSortByFrequentlyPlayed": "Často přehrávané",
"@resourcesSortByFrequentlyPlayed": {}, "@resourcesSortByFrequentlyPlayed": {},
"resourcesSortByName": "Podle názvu", "resourcesSortByName": "Názvu",
"@resourcesSortByName": {}, "@resourcesSortByName": {},
"resourcesSortByRandom": "Náhodně", "resourcesSortByRandom": "Náhodně",
"@resourcesSortByRandom": {}, "@resourcesSortByRandom": {},
"resourcesSortByRecentlyPlayed": "Často přehrávané", "resourcesSortByRecentlyPlayed": "Často přehrávané",
"@resourcesSortByRecentlyPlayed": {}, "@resourcesSortByRecentlyPlayed": {},
"resourcesSortByYear": "Podle roku", "resourcesSortByYear": "Roku",
"@resourcesSortByYear": {}, "@resourcesSortByYear": {},
"searchHeaderTitle": "Hledat: {query}", "searchHeaderTitle": "Hledat: {query}",
"@searchHeaderTitle": { "@searchHeaderTitle": {
@@ -162,5 +162,65 @@
"settingsServersOptionsForcePlaintextPasswordDescriptionOn": "Posílat heslo v prostém textu (zastaralé, ujistěte se, že je vaše připojení zabezpečené!)", "settingsServersOptionsForcePlaintextPasswordDescriptionOn": "Posílat heslo v prostém textu (zastaralé, ujistěte se, že je vaše připojení zabezpečené!)",
"@settingsServersOptionsForcePlaintextPasswordDescriptionOn": {}, "@settingsServersOptionsForcePlaintextPasswordDescriptionOn": {},
"settingsServersOptionsForcePlaintextPasswordTitle": "Vynutit heslo ve formátu prostého textu", "settingsServersOptionsForcePlaintextPasswordTitle": "Vynutit heslo ve formátu prostého textu",
"@settingsServersOptionsForcePlaintextPasswordTitle": {} "@settingsServersOptionsForcePlaintextPasswordTitle": {},
"actionsDownloadDelete": "Smazat stažené",
"@actionsDownloadDelete": {},
"actionsOk": "OK",
"@actionsOk": {},
"actionsCancel": "Zrušit",
"@actionsCancel": {},
"actionsDownload": "Stáhnout",
"@actionsDownload": {},
"controlsShuffle": "Náhodně",
"@controlsShuffle": {},
"resourcesFilterAlbum": "Album",
"@resourcesFilterAlbum": {},
"resourcesFilterArtist": "Umělec",
"@resourcesFilterArtist": {},
"resourcesFilterYear": "Rok",
"@resourcesFilterYear": {},
"resourcesFilterOwner": "Majitele",
"@resourcesFilterOwner": {},
"resourcesSongListDeleteAllTitle": "Smazat stažené?",
"@resourcesSongListDeleteAllTitle": {},
"resourcesSongListDeleteAllContent": "Toto odstraní všechny stažené soubory s hudbou.",
"@resourcesSongListDeleteAllContent": {},
"resourcesSortByUpdated": "Naposledy upravené",
"@resourcesSortByUpdated": {},
"resourcesSortByAlbum": "Alba",
"@resourcesSortByAlbum": {},
"resourcesSortByAlbumCount": "Počtu alb",
"@resourcesSortByAlbumCount": {},
"resourcesSortByTitle": "Názvu",
"@resourcesSortByTitle": {},
"settingsAboutActionsLicenses": "Licence",
"@settingsAboutActionsLicenses": {},
"settingsAboutActionsProjectHomepage": "Stránka projektu",
"@settingsAboutActionsProjectHomepage": {},
"settingsAboutActionsSupport": "Podpořit vývojáře 💜",
"@settingsAboutActionsSupport": {},
"settingsAboutVersion": "verze {version}",
"@settingsAboutVersion": {
"placeholders": {
"version": {
"type": "String"
}
}
},
"settingsNetworkOptionsStreamFormat": "Preferovaný formát pro streamování",
"@settingsNetworkOptionsStreamFormat": {},
"settingsNetworkOptionsStreamFormatServerDefault": "Použít nastavení serveru",
"@settingsNetworkOptionsStreamFormatServerDefault": {},
"settingsResetActionsClearImageCache": "Smazat mezipaměť obrázků",
"@settingsResetActionsClearImageCache": {},
"settingsResetName": "Resetovat",
"@settingsResetName": {},
"settingsServersFieldsName": "Jméno",
"@settingsServersFieldsName": {},
"settingsAboutName": "O aplikaci",
"@settingsAboutName": {},
"actionsDownloadCancel": "Zrušit stahování",
"@actionsDownloadCancel": {},
"actionsDelete": "Smazat",
"@actionsDelete": {}
} }

View File

@@ -192,5 +192,85 @@
"settingsServersOptionsForcePlaintextPasswordDescriptionOn": "Passwort als Klartext senden (Veraltet, stellen Sie sicher, dass Ihre Verbindung sicher ist!)", "settingsServersOptionsForcePlaintextPasswordDescriptionOn": "Passwort als Klartext senden (Veraltet, stellen Sie sicher, dass Ihre Verbindung sicher ist!)",
"@settingsServersOptionsForcePlaintextPasswordDescriptionOn": {}, "@settingsServersOptionsForcePlaintextPasswordDescriptionOn": {},
"settingsServersOptionsForcePlaintextPasswordTitle": "Erzwinge Klartextpasswort", "settingsServersOptionsForcePlaintextPasswordTitle": "Erzwinge Klartextpasswort",
"@settingsServersOptionsForcePlaintextPasswordTitle": {} "@settingsServersOptionsForcePlaintextPasswordTitle": {},
"actionsDelete": "Löschen",
"@actionsDelete": {},
"actionsDownload": "Herunterladen",
"@actionsDownload": {},
"actionsDownloadCancel": "Download abbrechen",
"@actionsDownloadCancel": {},
"controlsShuffle": "Zufall",
"@controlsShuffle": {},
"actionsCancel": "Abbrechen",
"@actionsCancel": {},
"actionsDownloadDelete": "Heruntergeladene Inhalte löschen",
"@actionsDownloadDelete": {},
"actionsOk": "OK",
"@actionsOk": {},
"resourcesAlbumCount": "{count,plural, =1{{count} Album} other{{count} Alben}}",
"@resourcesAlbumCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"resourcesFilterAlbum": "Album",
"@resourcesFilterAlbum": {},
"resourcesArtistCount": "{count,plural, =1{{count} Künstler} other{{count} Künstler}}",
"@resourcesArtistCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"resourcesFilterArtist": "Künstler",
"@resourcesFilterArtist": {},
"resourcesFilterOwner": "Besitzer",
"@resourcesFilterOwner": {},
"resourcesFilterYear": "Jahr",
"@resourcesFilterYear": {},
"resourcesPlaylistCount": "{count,plural, =1{{count} Playlist} other{{count} Playlists}}",
"@resourcesPlaylistCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"resourcesSongCount": "{count,plural, =1{{count} Song} other{{count} Songs}}",
"@resourcesSongCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"resourcesSongListDeleteAllContent": "Hierdurch werden alle heruntergeladenen Inhalte entfernt.",
"@resourcesSongListDeleteAllContent": {},
"resourcesSortByAlbum": "Album",
"@resourcesSortByAlbum": {},
"resourcesSortByAlbumCount": "Albenanzahl",
"@resourcesSortByAlbumCount": {},
"resourcesSortByTitle": "Titel",
"@resourcesSortByTitle": {},
"resourcesSortByUpdated": "Kürzlich hinzugefügt",
"@resourcesSortByUpdated": {},
"settingsAboutActionsSupport": "Den Entwickler unterstützen",
"@settingsAboutActionsSupport": {},
"settingsNetworkOptionsOfflineMode": "Offline Modus",
"@settingsNetworkOptionsOfflineMode": {},
"settingsNetworkOptionsOfflineModeOff": "Nutze das Internet um Musik zu synchronisieren.",
"@settingsNetworkOptionsOfflineModeOff": {},
"settingsNetworkOptionsOfflineModeOn": "Nutze nicht das Internet um Musik zu synchronisieren.",
"@settingsNetworkOptionsOfflineModeOn": {},
"settingsNetworkOptionsStreamFormat": "Bevorzugtes Streaming-Format",
"@settingsNetworkOptionsStreamFormat": {},
"settingsServersFieldsName": "Name",
"@settingsServersFieldsName": {},
"resourcesSongListDeleteAllTitle": "Downloads löschen?",
"@resourcesSongListDeleteAllTitle": {},
"settingsNetworkOptionsStreamFormatServerDefault": "Server-Standard verwenden",
"@settingsNetworkOptionsStreamFormatServerDefault": {}
} }

View File

@@ -173,6 +173,10 @@
"@settingsAboutActionsSupport": {}, "@settingsAboutActionsSupport": {},
"settingsAboutName": "About", "settingsAboutName": "About",
"@settingsAboutName": {}, "@settingsAboutName": {},
"settingsAboutShareLogs": "Share logs",
"@settingsAboutShareLogs": {},
"settingsAboutChooseLog": "Choose a log file",
"@settingsAboutChooseLog": {},
"settingsAboutVersion": "version {version}", "settingsAboutVersion": "version {version}",
"@settingsAboutVersion": { "@settingsAboutVersion": {
"placeholders": { "placeholders": {

View File

@@ -1,7 +1,7 @@
{ {
"actionsStar": "Estrella", "actionsStar": "Favorito",
"@actionsStar": {}, "@actionsStar": {},
"actionsUnstar": "Retirar estrella", "actionsUnstar": "Retirar favorito",
"@actionsUnstar": {}, "@actionsUnstar": {},
"messagesNothingHere": "Nada aquí…", "messagesNothingHere": "Nada aquí…",
"@messagesNothingHere": {}, "@messagesNothingHere": {},
@@ -192,5 +192,19 @@
"settingsServersOptionsForcePlaintextPasswordDescriptionOn": "Enviar contraseña en texto plano (¡legado, asegúrese de que su conexión sea segura!)", "settingsServersOptionsForcePlaintextPasswordDescriptionOn": "Enviar contraseña en texto plano (¡legado, asegúrese de que su conexión sea segura!)",
"@settingsServersOptionsForcePlaintextPasswordDescriptionOn": {}, "@settingsServersOptionsForcePlaintextPasswordDescriptionOn": {},
"settingsServersOptionsForcePlaintextPasswordTitle": "Forzar contraseña de texto sin formato", "settingsServersOptionsForcePlaintextPasswordTitle": "Forzar contraseña de texto sin formato",
"@settingsServersOptionsForcePlaintextPasswordTitle": {} "@settingsServersOptionsForcePlaintextPasswordTitle": {},
"actionsDelete": "Borrar",
"@actionsDelete": {},
"actionsOk": "Ok",
"@actionsOk": {},
"actionsDownload": "Descargar",
"@actionsDownload": {},
"actionsDownloadCancel": "Anular descargar",
"@actionsDownloadCancel": {},
"controlsShuffle": "Reproducir aleatoriamente",
"@controlsShuffle": {},
"actionsCancel": "Cancelar",
"@actionsCancel": {},
"actionsDownloadDelete": "Eliminar descargado",
"@actionsDownloadDelete": {}
} }

View File

@@ -192,5 +192,89 @@
"settingsServersOptionsForcePlaintextPasswordDescriptionOn": "Enviar contrasinal en texto plano (herdado, pon coidado en que a conexión sexa segura!)", "settingsServersOptionsForcePlaintextPasswordDescriptionOn": "Enviar contrasinal en texto plano (herdado, pon coidado en que a conexión sexa segura!)",
"@settingsServersOptionsForcePlaintextPasswordDescriptionOn": {}, "@settingsServersOptionsForcePlaintextPasswordDescriptionOn": {},
"settingsServersOptionsForcePlaintextPasswordTitle": "Forzar contrasinal en texto plano", "settingsServersOptionsForcePlaintextPasswordTitle": "Forzar contrasinal en texto plano",
"@settingsServersOptionsForcePlaintextPasswordTitle": {} "@settingsServersOptionsForcePlaintextPasswordTitle": {},
"actionsCancel": "Cancelar",
"@actionsCancel": {},
"actionsDelete": "Eliminar",
"@actionsDelete": {},
"actionsDownload": "Descargar",
"@actionsDownload": {},
"actionsDownloadCancel": "Cancelar a descarga",
"@actionsDownloadCancel": {},
"actionsDownloadDelete": "Eliminar o descargado",
"@actionsDownloadDelete": {},
"actionsOk": "OK",
"@actionsOk": {},
"controlsShuffle": "Barallar",
"@controlsShuffle": {},
"resourcesAlbumCount": "{count,plural, =1{{count} álbum} other{{count} álbums}}",
"@resourcesAlbumCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"resourcesArtistCount": "{count,plural, =1{{count} artista} other{{count} artistas}}",
"@resourcesArtistCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"resourcesFilterAlbum": "Álbum",
"@resourcesFilterAlbum": {},
"resourcesFilterArtist": "Artista",
"@resourcesFilterArtist": {},
"resourcesFilterOwner": "Dono",
"@resourcesFilterOwner": {},
"resourcesFilterYear": "Ano",
"@resourcesFilterYear": {},
"resourcesPlaylistCount": "{count,plural, =1{{count} lista} other{{count} listas}}",
"@resourcesPlaylistCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"resourcesSongCount": "{count,plural, =1{{count} canción} other{{count} cancións}}",
"@resourcesSongCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"resourcesSongListDeleteAllContent": "Vas eliminar todas as cancións descargadas.",
"@resourcesSongListDeleteAllContent": {},
"resourcesSongListDeleteAllTitle": "Eliminar descargas?",
"@resourcesSongListDeleteAllTitle": {},
"resourcesSortByAlbum": "Álbum",
"@resourcesSortByAlbum": {},
"resourcesSortByAlbumCount": "Número de álbums",
"@resourcesSortByAlbumCount": {},
"settingsAboutActionsSupport": "Axuda ao desenvolvemento 💜",
"@settingsAboutActionsSupport": {},
"settingsNetworkOptionsOfflineMode": "Modo sen conexión",
"@settingsNetworkOptionsOfflineMode": {},
"settingsNetworkOptionsOfflineModeOff": "Usa internet para sincr. música.",
"@settingsNetworkOptionsOfflineModeOff": {},
"settingsNetworkOptionsOfflineModeOn": "Non usar internet para sincr. ou reproducir música.",
"@settingsNetworkOptionsOfflineModeOn": {},
"settingsNetworkOptionsStreamFormat": "Modo de reprodución preferido",
"@settingsNetworkOptionsStreamFormat": {},
"settingsNetworkOptionsStreamFormatServerDefault": "Usar por defecto do servidor",
"@settingsNetworkOptionsStreamFormatServerDefault": {},
"settingsServersFieldsName": "Nome",
"@settingsServersFieldsName": {},
"resourcesSortByTitle": "Título",
"@resourcesSortByTitle": {},
"resourcesSortByUpdated": "Actualizado recentemente",
"@resourcesSortByUpdated": {},
"settingsAboutShareLogs": "Compartir rexistros",
"@settingsAboutShareLogs": {},
"settingsAboutChooseLog": "Escolle un ficheiro de rexistro",
"@settingsAboutChooseLog": {}
} }

View File

@@ -192,5 +192,39 @@
"settingsServersOptionsForcePlaintextPasswordDescriptionOn": "Enviar senha em texto simples (antigo, certifique-se que a sua ligação é segura!)", "settingsServersOptionsForcePlaintextPasswordDescriptionOn": "Enviar senha em texto simples (antigo, certifique-se que a sua ligação é segura!)",
"@settingsServersOptionsForcePlaintextPasswordDescriptionOn": {}, "@settingsServersOptionsForcePlaintextPasswordDescriptionOn": {},
"settingsServersOptionsForcePlaintextPasswordTitle": "Forçar password em texto simples", "settingsServersOptionsForcePlaintextPasswordTitle": "Forçar password em texto simples",
"@settingsServersOptionsForcePlaintextPasswordTitle": {} "@settingsServersOptionsForcePlaintextPasswordTitle": {},
"actionsCancel": "Cancelar",
"@actionsCancel": {},
"actionsDelete": "Apagar",
"@actionsDelete": {},
"actionsDownload": "Descarregar",
"@actionsDownload": {},
"actionsDownloadCancel": "Cancelar descarga",
"@actionsDownloadCancel": {},
"actionsDownloadDelete": "Apagar descarga",
"@actionsDownloadDelete": {},
"resourcesFilterAlbum": "Álbum",
"@resourcesFilterAlbum": {},
"resourcesFilterArtist": "Artista",
"@resourcesFilterArtist": {},
"resourcesFilterYear": "Ano",
"@resourcesFilterYear": {},
"resourcesSortByAlbum": "Álbum",
"@resourcesSortByAlbum": {},
"settingsAboutActionsSupport": "Apoie o programador 💜",
"@settingsAboutActionsSupport": {},
"settingsNetworkOptionsOfflineMode": "Modo offline",
"@settingsNetworkOptionsOfflineMode": {},
"settingsNetworkOptionsOfflineModeOff": "Usar a internet para sincronizar música.",
"@settingsNetworkOptionsOfflineModeOff": {},
"settingsNetworkOptionsOfflineModeOn": "Não usar a internet para sincronizar ou tocar música.",
"@settingsNetworkOptionsOfflineModeOn": {},
"settingsNetworkOptionsStreamFormat": "Formato preferido de streaming",
"@settingsNetworkOptionsStreamFormat": {},
"resourcesSortByTitle": "Título",
"@resourcesSortByTitle": {},
"actionsOk": "OK",
"@actionsOk": {},
"controlsShuffle": "Aleatório",
"@controlsShuffle": {}
} }

View File

@@ -73,7 +73,7 @@
}, },
"resourcesSortByAdded": "Недавно добавленные", "resourcesSortByAdded": "Недавно добавленные",
"@resourcesSortByAdded": {}, "@resourcesSortByAdded": {},
"resourcesSortByArtist": "По исполнителю", "resourcesSortByArtist": "По исполнителям",
"@resourcesSortByArtist": {}, "@resourcesSortByArtist": {},
"resourcesSortByFrequentlyPlayed": "Часто проигрываемые", "resourcesSortByFrequentlyPlayed": "Часто проигрываемые",
"@resourcesSortByFrequentlyPlayed": {}, "@resourcesSortByFrequentlyPlayed": {},
@@ -192,5 +192,89 @@
"settingsServersOptionsForcePlaintextPasswordDescriptionOn": "Отправить пароль в виде текста (устарело, убедитесь, что ваше соединение безопасно!)", "settingsServersOptionsForcePlaintextPasswordDescriptionOn": "Отправить пароль в виде текста (устарело, убедитесь, что ваше соединение безопасно!)",
"@settingsServersOptionsForcePlaintextPasswordDescriptionOn": {}, "@settingsServersOptionsForcePlaintextPasswordDescriptionOn": {},
"settingsServersOptionsForcePlaintextPasswordTitle": "Принудительно использовать текстовой пароль", "settingsServersOptionsForcePlaintextPasswordTitle": "Принудительно использовать текстовой пароль",
"@settingsServersOptionsForcePlaintextPasswordTitle": {} "@settingsServersOptionsForcePlaintextPasswordTitle": {},
"settingsAboutShareLogs": "Поделиться журналами",
"@settingsAboutShareLogs": {},
"settingsAboutChooseLog": "Выбрать файл журнала",
"@settingsAboutChooseLog": {},
"settingsNetworkOptionsStreamFormatServerDefault": "Использовать сервер по умолчанию",
"@settingsNetworkOptionsStreamFormatServerDefault": {},
"actionsDownload": "Скачать",
"@actionsDownload": {},
"actionsDownloadCancel": "Отменить загрузку",
"@actionsDownloadCancel": {},
"actionsCancel": "Отменить",
"@actionsCancel": {},
"resourcesSongCount": "{count,plural, =1{{count} трек} other{{count} треки}}",
"@resourcesSongCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"resourcesSortByAlbum": "По альбомам",
"@resourcesSortByAlbum": {},
"resourcesSortByTitle": "По заголовку",
"@resourcesSortByTitle": {},
"resourcesSortByUpdated": "По недавно обновленному",
"@resourcesSortByUpdated": {},
"resourcesSortByAlbumCount": "По количеству альбомов",
"@resourcesSortByAlbumCount": {},
"settingsNetworkOptionsOfflineMode": "Автономный режим",
"@settingsNetworkOptionsOfflineMode": {},
"settingsNetworkOptionsOfflineModeOff": "Использовать интернет для синхронизации музыки.",
"@settingsNetworkOptionsOfflineModeOff": {},
"settingsServersFieldsName": "Имя",
"@settingsServersFieldsName": {},
"actionsDelete": "Удалить",
"@actionsDelete": {},
"actionsDownloadDelete": "Удалить загруженное",
"@actionsDownloadDelete": {},
"actionsOk": "ОК",
"@actionsOk": {},
"controlsShuffle": "Перемешать",
"@controlsShuffle": {},
"resourcesFilterArtist": "По исполнителю",
"@resourcesFilterArtist": {},
"resourcesFilterAlbum": "По альбомам",
"@resourcesFilterAlbum": {},
"resourcesFilterYear": "По годам",
"@resourcesFilterYear": {},
"resourcesFilterOwner": "По владельцу",
"@resourcesFilterOwner": {},
"resourcesSongListDeleteAllContent": "Это удалит все загруженные файлы песен.",
"@resourcesSongListDeleteAllContent": {},
"settingsNetworkOptionsStreamFormat": "Предпочтительный формат потока",
"@settingsNetworkOptionsStreamFormat": {},
"resourcesSongListDeleteAllTitle": "Удалить загрузки?",
"@resourcesSongListDeleteAllTitle": {},
"settingsNetworkOptionsOfflineModeOn": "Не использовать интернет для синхронизации или воспроизведения музыки.",
"@settingsNetworkOptionsOfflineModeOn": {},
"settingsAboutActionsSupport": "Поддержать разработчика",
"@settingsAboutActionsSupport": {},
"resourcesArtistCount": "{count,plural, =1{{count} исполнитель} other{{count} исполнители}}",
"@resourcesArtistCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"resourcesPlaylistCount": "{count,plural, =1{{count} плейлист} other{{count} плейлисты}}",
"@resourcesPlaylistCount": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"resourcesAlbumCount": "{count,plural, =1{{count} альбом} other{{count} альбомы}}",
"@resourcesAlbumCount": {
"placeholders": {
"count": {
"type": "int"
}
}
}
} }

View File

@@ -192,5 +192,39 @@
"settingsServersOptionsForcePlaintextPasswordDescriptionOn": "密码以明文发送(不推荐,注意链接安全!)", "settingsServersOptionsForcePlaintextPasswordDescriptionOn": "密码以明文发送(不推荐,注意链接安全!)",
"@settingsServersOptionsForcePlaintextPasswordDescriptionOn": {}, "@settingsServersOptionsForcePlaintextPasswordDescriptionOn": {},
"settingsServersOptionsForcePlaintextPasswordTitle": "强制使用明文密码", "settingsServersOptionsForcePlaintextPasswordTitle": "强制使用明文密码",
"@settingsServersOptionsForcePlaintextPasswordTitle": {} "@settingsServersOptionsForcePlaintextPasswordTitle": {},
"actionsDownload": "下载",
"@actionsDownload": {},
"actionsDownloadCancel": "取消下载",
"@actionsDownloadCancel": {},
"actionsDownloadDelete": "删除已下载",
"@actionsDownloadDelete": {},
"actionsOk": "确定",
"@actionsOk": {},
"resourcesFilterArtist": "歌手",
"@resourcesFilterArtist": {},
"resourcesFilterOwner": "所有者",
"@resourcesFilterOwner": {},
"resourcesSongListDeleteAllTitle": "删除下载?",
"@resourcesSongListDeleteAllTitle": {},
"resourcesSortByAlbum": "专辑",
"@resourcesSortByAlbum": {},
"resourcesSortByAlbumCount": "专辑数量",
"@resourcesSortByAlbumCount": {},
"resourcesSortByUpdated": "最近添加",
"@resourcesSortByUpdated": {},
"settingsAboutActionsSupport": "支持开发者",
"@settingsAboutActionsSupport": {},
"resourcesFilterAlbum": "专辑",
"@resourcesFilterAlbum": {},
"resourcesSortByTitle": "标题",
"@resourcesSortByTitle": {},
"actionsCancel": "取消",
"@actionsCancel": {},
"actionsDelete": "删除",
"@actionsDelete": {},
"resourcesFilterYear": "年份",
"@resourcesFilterYear": {},
"resourcesSongListDeleteAllContent": "该操作会删除所有已下载的歌曲文件。",
"@resourcesSongListDeleteAllContent": {}
} }

209
lib/log.dart Normal file
View File

@@ -0,0 +1,209 @@
// import 'dart:convert';
import 'dart:io';
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
class AnsiColor {
/// ANSI Control Sequence Introducer, signals the terminal for new settings.
static const ansiEsc = '\x1B[';
/// Reset all colors and options for current SGRs to terminal defaults.
static const ansiDefault = '${ansiEsc}0m';
final int? fg;
final int? bg;
final bool color;
AnsiColor.none()
: fg = null,
bg = null,
color = false;
AnsiColor.fg(this.fg)
: bg = null,
color = true;
AnsiColor.bg(this.bg)
: fg = null,
color = true;
@override
String toString() {
if (fg != null) {
return '${ansiEsc}38;5;${fg}m';
} else if (bg != null) {
return '${ansiEsc}48;5;${bg}m';
} else {
return '';
}
}
String call(String msg) {
if (color) {
// ignore: unnecessary_brace_in_string_interps
return '${this}$msg$ansiDefault';
} else {
return msg;
}
}
AnsiColor toFg() => AnsiColor.fg(bg);
AnsiColor toBg() => AnsiColor.bg(fg);
/// Defaults the terminal's foreground color without altering the background.
String get resetForeground => color ? '${ansiEsc}39m' : '';
/// Defaults the terminal's background color without altering the foreground.
String get resetBackground => color ? '${ansiEsc}49m' : '';
static int grey(double level) => 232 + (level.clamp(0.0, 1.0) * 23).round();
}
final levelColors = {
Level.FINEST: AnsiColor.fg(AnsiColor.grey(0.5)),
Level.FINER: AnsiColor.fg(AnsiColor.grey(0.5)),
Level.FINE: AnsiColor.fg(AnsiColor.grey(0.5)),
Level.CONFIG: AnsiColor.fg(81),
Level.INFO: AnsiColor.fg(12),
Level.WARNING: AnsiColor.fg(208),
Level.SEVERE: AnsiColor.fg(196),
Level.SHOUT: AnsiColor.fg(199),
};
class LogData {
final String? message;
final Object? data;
const LogData(this.message, this.data);
}
String _format(
LogRecord event, {
bool color = false,
bool time = true,
bool level = true,
bool redact = true,
}) {
var message = '';
if (time) message += '${event.time.toIso8601String()} ';
if (level) message += '${event.level.name} ';
final object = event.object;
if (object is LogData) {
message += '${object.message}';
message += '\n${object.data}';
} else if (object != null) {
message += 'Object';
message += '\n$object';
} else {
message += event.message;
}
if (event.error != null) {
message += '\n${event.error}';
}
if (redact) {
message = _redactUrl(message);
}
if (event.stackTrace != null) {
message += '\n${event.stackTrace}';
}
return color
? message.split('\n').map((e) => levelColors[event.level]!(e)).join('\n')
: message;
}
String _redactUrl(String message) {
if (!_queryReplace('u').hasMatch(message)) {
return message;
}
message = _redactParam(message, 'u');
message = _redactParam(message, 'p');
message = _redactParam(message, 's');
message = _redactParam(message, 't');
return message;
}
RegExp _queryReplace(String key) => RegExp('$key=([^&|\\n|\\t\\s]+)');
String _redactParam(String url, String key) =>
url.replaceAll(_queryReplace(key), '$key=REDACTED');
Future<Directory> logDirectory() async {
return Directory(
p.join((await getApplicationDocumentsDirectory()).path, 'logs'),
);
}
Future<List<File>> logFiles() async {
final dir = await logDirectory();
return dir.listSync().whereType<File>().toList()
..sort(
(a, b) => b.statSync().modified.compareTo(a.statSync().modified),
);
}
File _currentLogFile(String logDir) {
final now = DateTime.now();
return File(p.join(logDir, '${now.year}-${now.month}-${now.day}.txt'));
}
Future<void> _printFile(String event, String logDir) async {
final file = _currentLogFile(logDir);
if (!event.endsWith('\n')) {
event += '\n';
}
await file.writeAsString(event, mode: FileMode.writeOnlyAppend, flush: true);
}
void _printDebug(LogRecord event) {
// ignore: avoid_print
print(_format(event, color: true, time: false, level: false, redact: false));
}
Future<void> _printRelease(LogRecord event, String logDir) async {
await _printFile(
_format(event, color: false, time: true, level: true, redact: true),
logDir,
);
}
final log = Logger('default');
Future<void> initLogging() async {
final dir = (await logDirectory())..create();
final file = _currentLogFile(dir.path);
if (!(await file.exists())) {
await file.create();
}
final files = await logFiles();
if (files.length > 7) {
for (var file in files.slice(7)) {
await file.delete();
}
}
Logger.root.level = kDebugMode ? Level.ALL : Level.INFO;
Logger.root.onRecord.asyncMap((event) async {
if (kDebugMode) {
_printDebug(event);
} else {
await _printRelease(event, dir.path);
}
}).listen((_) {}, cancelOnError: false);
}

View File

@@ -4,6 +4,7 @@ import 'package:stack_trace/stack_trace.dart' as stack_trace;
import 'package:worker_manager/worker_manager.dart'; import 'package:worker_manager/worker_manager.dart';
import 'app/app.dart'; import 'app/app.dart';
import 'log.dart';
void main() async { void main() async {
// TOOD: probably remove before live // TOOD: probably remove before live
@@ -18,5 +19,8 @@ void main() async {
await Executor().warmUp(); await Executor().warmUp();
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
await initLogging();
runApp(const ProviderScope(child: MyApp())); runApp(const ProviderScope(child: MyApp()));
} }

View File

@@ -12,7 +12,7 @@ part of 'music.dart';
T _$identity<T>(T value) => value; T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError( final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc /// @nodoc
mixin _$SourceId { mixin _$SourceId {
@@ -62,21 +62,22 @@ class _$SourceIdCopyWithImpl<$Res, $Val extends SourceId>
} }
/// @nodoc /// @nodoc
abstract class _$$_SourceIdCopyWith<$Res> implements $SourceIdCopyWith<$Res> { abstract class _$$SourceIdImplCopyWith<$Res>
factory _$$_SourceIdCopyWith( implements $SourceIdCopyWith<$Res> {
_$_SourceId value, $Res Function(_$_SourceId) then) = factory _$$SourceIdImplCopyWith(
__$$_SourceIdCopyWithImpl<$Res>; _$SourceIdImpl value, $Res Function(_$SourceIdImpl) then) =
__$$SourceIdImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call({int sourceId, String id}); $Res call({int sourceId, String id});
} }
/// @nodoc /// @nodoc
class __$$_SourceIdCopyWithImpl<$Res> class __$$SourceIdImplCopyWithImpl<$Res>
extends _$SourceIdCopyWithImpl<$Res, _$_SourceId> extends _$SourceIdCopyWithImpl<$Res, _$SourceIdImpl>
implements _$$_SourceIdCopyWith<$Res> { implements _$$SourceIdImplCopyWith<$Res> {
__$$_SourceIdCopyWithImpl( __$$SourceIdImplCopyWithImpl(
_$_SourceId _value, $Res Function(_$_SourceId) _then) _$SourceIdImpl _value, $Res Function(_$SourceIdImpl) _then)
: super(_value, _then); : super(_value, _then);
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@@ -85,7 +86,7 @@ class __$$_SourceIdCopyWithImpl<$Res>
Object? sourceId = null, Object? sourceId = null,
Object? id = null, Object? id = null,
}) { }) {
return _then(_$_SourceId( return _then(_$SourceIdImpl(
sourceId: null == sourceId sourceId: null == sourceId
? _value.sourceId ? _value.sourceId
: sourceId // ignore: cast_nullable_to_non_nullable : sourceId // ignore: cast_nullable_to_non_nullable
@@ -100,8 +101,8 @@ class __$$_SourceIdCopyWithImpl<$Res>
/// @nodoc /// @nodoc
class _$_SourceId with DiagnosticableTreeMixin implements _SourceId { class _$SourceIdImpl with DiagnosticableTreeMixin implements _SourceId {
const _$_SourceId({required this.sourceId, required this.id}); const _$SourceIdImpl({required this.sourceId, required this.id});
@override @override
final int sourceId; final int sourceId;
@@ -123,10 +124,10 @@ class _$_SourceId with DiagnosticableTreeMixin implements _SourceId {
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$_SourceId && other is _$SourceIdImpl &&
(identical(other.sourceId, sourceId) || (identical(other.sourceId, sourceId) ||
other.sourceId == sourceId) && other.sourceId == sourceId) &&
(identical(other.id, id) || other.id == id)); (identical(other.id, id) || other.id == id));
@@ -138,13 +139,13 @@ class _$_SourceId with DiagnosticableTreeMixin implements _SourceId {
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$_SourceIdCopyWith<_$_SourceId> get copyWith => _$$SourceIdImplCopyWith<_$SourceIdImpl> get copyWith =>
__$$_SourceIdCopyWithImpl<_$_SourceId>(this, _$identity); __$$SourceIdImplCopyWithImpl<_$SourceIdImpl>(this, _$identity);
} }
abstract class _SourceId implements SourceId { abstract class _SourceId implements SourceId {
const factory _SourceId( const factory _SourceId(
{required final int sourceId, required final String id}) = _$_SourceId; {required final int sourceId, required final String id}) = _$SourceIdImpl;
@override @override
int get sourceId; int get sourceId;
@@ -152,7 +153,7 @@ abstract class _SourceId implements SourceId {
String get id; String get id;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$_SourceIdCopyWith<_$_SourceId> get copyWith => _$$SourceIdImplCopyWith<_$SourceIdImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
@@ -205,22 +206,22 @@ class _$SourceIdSetCopyWithImpl<$Res, $Val extends SourceIdSet>
} }
/// @nodoc /// @nodoc
abstract class _$$_SourceIdSetCopyWith<$Res> abstract class _$$SourceIdSetImplCopyWith<$Res>
implements $SourceIdSetCopyWith<$Res> { implements $SourceIdSetCopyWith<$Res> {
factory _$$_SourceIdSetCopyWith( factory _$$SourceIdSetImplCopyWith(
_$_SourceIdSet value, $Res Function(_$_SourceIdSet) then) = _$SourceIdSetImpl value, $Res Function(_$SourceIdSetImpl) then) =
__$$_SourceIdSetCopyWithImpl<$Res>; __$$SourceIdSetImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call({int sourceId, ISet<String> ids}); $Res call({int sourceId, ISet<String> ids});
} }
/// @nodoc /// @nodoc
class __$$_SourceIdSetCopyWithImpl<$Res> class __$$SourceIdSetImplCopyWithImpl<$Res>
extends _$SourceIdSetCopyWithImpl<$Res, _$_SourceIdSet> extends _$SourceIdSetCopyWithImpl<$Res, _$SourceIdSetImpl>
implements _$$_SourceIdSetCopyWith<$Res> { implements _$$SourceIdSetImplCopyWith<$Res> {
__$$_SourceIdSetCopyWithImpl( __$$SourceIdSetImplCopyWithImpl(
_$_SourceIdSet _value, $Res Function(_$_SourceIdSet) _then) _$SourceIdSetImpl _value, $Res Function(_$SourceIdSetImpl) _then)
: super(_value, _then); : super(_value, _then);
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@@ -229,7 +230,7 @@ class __$$_SourceIdSetCopyWithImpl<$Res>
Object? sourceId = null, Object? sourceId = null,
Object? ids = null, Object? ids = null,
}) { }) {
return _then(_$_SourceIdSet( return _then(_$SourceIdSetImpl(
sourceId: null == sourceId sourceId: null == sourceId
? _value.sourceId ? _value.sourceId
: sourceId // ignore: cast_nullable_to_non_nullable : sourceId // ignore: cast_nullable_to_non_nullable
@@ -244,8 +245,8 @@ class __$$_SourceIdSetCopyWithImpl<$Res>
/// @nodoc /// @nodoc
class _$_SourceIdSet with DiagnosticableTreeMixin implements _SourceIdSet { class _$SourceIdSetImpl with DiagnosticableTreeMixin implements _SourceIdSet {
const _$_SourceIdSet({required this.sourceId, required this.ids}); const _$SourceIdSetImpl({required this.sourceId, required this.ids});
@override @override
final int sourceId; final int sourceId;
@@ -267,10 +268,10 @@ class _$_SourceIdSet with DiagnosticableTreeMixin implements _SourceIdSet {
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$_SourceIdSet && other is _$SourceIdSetImpl &&
(identical(other.sourceId, sourceId) || (identical(other.sourceId, sourceId) ||
other.sourceId == sourceId) && other.sourceId == sourceId) &&
const DeepCollectionEquality().equals(other.ids, ids)); const DeepCollectionEquality().equals(other.ids, ids));
@@ -283,14 +284,14 @@ class _$_SourceIdSet with DiagnosticableTreeMixin implements _SourceIdSet {
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$_SourceIdSetCopyWith<_$_SourceIdSet> get copyWith => _$$SourceIdSetImplCopyWith<_$SourceIdSetImpl> get copyWith =>
__$$_SourceIdSetCopyWithImpl<_$_SourceIdSet>(this, _$identity); __$$SourceIdSetImplCopyWithImpl<_$SourceIdSetImpl>(this, _$identity);
} }
abstract class _SourceIdSet implements SourceIdSet { abstract class _SourceIdSet implements SourceIdSet {
const factory _SourceIdSet( const factory _SourceIdSet(
{required final int sourceId, {required final int sourceId,
required final ISet<String> ids}) = _$_SourceIdSet; required final ISet<String> ids}) = _$SourceIdSetImpl;
@override @override
int get sourceId; int get sourceId;
@@ -298,7 +299,7 @@ abstract class _SourceIdSet implements SourceIdSet {
ISet<String> get ids; ISet<String> get ids;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$_SourceIdSetCopyWith<_$_SourceIdSet> get copyWith => _$$SourceIdSetImplCopyWith<_$SourceIdSetImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
@@ -372,9 +373,10 @@ class _$ArtistCopyWithImpl<$Res, $Val extends Artist>
} }
/// @nodoc /// @nodoc
abstract class _$$_ArtistCopyWith<$Res> implements $ArtistCopyWith<$Res> { abstract class _$$ArtistImplCopyWith<$Res> implements $ArtistCopyWith<$Res> {
factory _$$_ArtistCopyWith(_$_Artist value, $Res Function(_$_Artist) then) = factory _$$ArtistImplCopyWith(
__$$_ArtistCopyWithImpl<$Res>; _$ArtistImpl value, $Res Function(_$ArtistImpl) then) =
__$$ArtistImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call( $Res call(
@@ -386,10 +388,11 @@ abstract class _$$_ArtistCopyWith<$Res> implements $ArtistCopyWith<$Res> {
} }
/// @nodoc /// @nodoc
class __$$_ArtistCopyWithImpl<$Res> class __$$ArtistImplCopyWithImpl<$Res>
extends _$ArtistCopyWithImpl<$Res, _$_Artist> extends _$ArtistCopyWithImpl<$Res, _$ArtistImpl>
implements _$$_ArtistCopyWith<$Res> { implements _$$ArtistImplCopyWith<$Res> {
__$$_ArtistCopyWithImpl(_$_Artist _value, $Res Function(_$_Artist) _then) __$$ArtistImplCopyWithImpl(
_$ArtistImpl _value, $Res Function(_$ArtistImpl) _then)
: super(_value, _then); : super(_value, _then);
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@@ -401,7 +404,7 @@ class __$$_ArtistCopyWithImpl<$Res>
Object? albumCount = null, Object? albumCount = null,
Object? starred = freezed, Object? starred = freezed,
}) { }) {
return _then(_$_Artist( return _then(_$ArtistImpl(
sourceId: null == sourceId sourceId: null == sourceId
? _value.sourceId ? _value.sourceId
: sourceId // ignore: cast_nullable_to_non_nullable : sourceId // ignore: cast_nullable_to_non_nullable
@@ -428,8 +431,8 @@ class __$$_ArtistCopyWithImpl<$Res>
/// @nodoc /// @nodoc
class _$_Artist with DiagnosticableTreeMixin implements _Artist { class _$ArtistImpl with DiagnosticableTreeMixin implements _Artist {
const _$_Artist( const _$ArtistImpl(
{required this.sourceId, {required this.sourceId,
required this.id, required this.id,
required this.name, required this.name,
@@ -465,10 +468,10 @@ class _$_Artist with DiagnosticableTreeMixin implements _Artist {
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$_Artist && other is _$ArtistImpl &&
(identical(other.sourceId, sourceId) || (identical(other.sourceId, sourceId) ||
other.sourceId == sourceId) && other.sourceId == sourceId) &&
(identical(other.id, id) || other.id == id) && (identical(other.id, id) || other.id == id) &&
@@ -485,8 +488,8 @@ class _$_Artist with DiagnosticableTreeMixin implements _Artist {
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$_ArtistCopyWith<_$_Artist> get copyWith => _$$ArtistImplCopyWith<_$ArtistImpl> get copyWith =>
__$$_ArtistCopyWithImpl<_$_Artist>(this, _$identity); __$$ArtistImplCopyWithImpl<_$ArtistImpl>(this, _$identity);
} }
abstract class _Artist implements Artist { abstract class _Artist implements Artist {
@@ -495,7 +498,7 @@ abstract class _Artist implements Artist {
required final String id, required final String id,
required final String name, required final String name,
required final int albumCount, required final int albumCount,
final DateTime? starred}) = _$_Artist; final DateTime? starred}) = _$ArtistImpl;
@override @override
int get sourceId; int get sourceId;
@@ -509,7 +512,7 @@ abstract class _Artist implements Artist {
DateTime? get starred; DateTime? get starred;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$_ArtistCopyWith<_$_Artist> get copyWith => _$$ArtistImplCopyWith<_$ArtistImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
@@ -648,9 +651,10 @@ class _$AlbumCopyWithImpl<$Res, $Val extends Album>
} }
/// @nodoc /// @nodoc
abstract class _$$_AlbumCopyWith<$Res> implements $AlbumCopyWith<$Res> { abstract class _$$AlbumImplCopyWith<$Res> implements $AlbumCopyWith<$Res> {
factory _$$_AlbumCopyWith(_$_Album value, $Res Function(_$_Album) then) = factory _$$AlbumImplCopyWith(
__$$_AlbumCopyWithImpl<$Res>; _$AlbumImpl value, $Res Function(_$AlbumImpl) then) =
__$$AlbumImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call( $Res call(
@@ -671,9 +675,11 @@ abstract class _$$_AlbumCopyWith<$Res> implements $AlbumCopyWith<$Res> {
} }
/// @nodoc /// @nodoc
class __$$_AlbumCopyWithImpl<$Res> extends _$AlbumCopyWithImpl<$Res, _$_Album> class __$$AlbumImplCopyWithImpl<$Res>
implements _$$_AlbumCopyWith<$Res> { extends _$AlbumCopyWithImpl<$Res, _$AlbumImpl>
__$$_AlbumCopyWithImpl(_$_Album _value, $Res Function(_$_Album) _then) implements _$$AlbumImplCopyWith<$Res> {
__$$AlbumImplCopyWithImpl(
_$AlbumImpl _value, $Res Function(_$AlbumImpl) _then)
: super(_value, _then); : super(_value, _then);
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@@ -694,7 +700,7 @@ class __$$_AlbumCopyWithImpl<$Res> extends _$AlbumCopyWithImpl<$Res, _$_Album>
Object? frequentRank = freezed, Object? frequentRank = freezed,
Object? recentRank = freezed, Object? recentRank = freezed,
}) { }) {
return _then(_$_Album( return _then(_$AlbumImpl(
sourceId: null == sourceId sourceId: null == sourceId
? _value.sourceId ? _value.sourceId
: sourceId // ignore: cast_nullable_to_non_nullable : sourceId // ignore: cast_nullable_to_non_nullable
@@ -757,8 +763,8 @@ class __$$_AlbumCopyWithImpl<$Res> extends _$AlbumCopyWithImpl<$Res, _$_Album>
/// @nodoc /// @nodoc
class _$_Album with DiagnosticableTreeMixin implements _Album { class _$AlbumImpl with DiagnosticableTreeMixin implements _Album {
const _$_Album( const _$AlbumImpl(
{required this.sourceId, {required this.sourceId,
required this.id, required this.id,
required this.name, required this.name,
@@ -833,10 +839,10 @@ class _$_Album with DiagnosticableTreeMixin implements _Album {
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$_Album && other is _$AlbumImpl &&
(identical(other.sourceId, sourceId) || (identical(other.sourceId, sourceId) ||
other.sourceId == sourceId) && other.sourceId == sourceId) &&
(identical(other.id, id) || other.id == id) && (identical(other.id, id) || other.id == id) &&
@@ -882,8 +888,8 @@ class _$_Album with DiagnosticableTreeMixin implements _Album {
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$_AlbumCopyWith<_$_Album> get copyWith => _$$AlbumImplCopyWith<_$AlbumImpl> get copyWith =>
__$$_AlbumCopyWithImpl<_$_Album>(this, _$identity); __$$AlbumImplCopyWithImpl<_$AlbumImpl>(this, _$identity);
} }
abstract class _Album implements Album { abstract class _Album implements Album {
@@ -901,7 +907,7 @@ abstract class _Album implements Album {
required final int songCount, required final int songCount,
final bool isDeleted, final bool isDeleted,
final int? frequentRank, final int? frequentRank,
final int? recentRank}) = _$_Album; final int? recentRank}) = _$AlbumImpl;
@override @override
int get sourceId; int get sourceId;
@@ -933,7 +939,7 @@ abstract class _Album implements Album {
int? get recentRank; int? get recentRank;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$_AlbumCopyWith<_$_Album> get copyWith => _$$AlbumImplCopyWith<_$AlbumImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
@@ -1022,10 +1028,11 @@ class _$PlaylistCopyWithImpl<$Res, $Val extends Playlist>
} }
/// @nodoc /// @nodoc
abstract class _$$_PlaylistCopyWith<$Res> implements $PlaylistCopyWith<$Res> { abstract class _$$PlaylistImplCopyWith<$Res>
factory _$$_PlaylistCopyWith( implements $PlaylistCopyWith<$Res> {
_$_Playlist value, $Res Function(_$_Playlist) then) = factory _$$PlaylistImplCopyWith(
__$$_PlaylistCopyWithImpl<$Res>; _$PlaylistImpl value, $Res Function(_$PlaylistImpl) then) =
__$$PlaylistImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call( $Res call(
@@ -1039,11 +1046,11 @@ abstract class _$$_PlaylistCopyWith<$Res> implements $PlaylistCopyWith<$Res> {
} }
/// @nodoc /// @nodoc
class __$$_PlaylistCopyWithImpl<$Res> class __$$PlaylistImplCopyWithImpl<$Res>
extends _$PlaylistCopyWithImpl<$Res, _$_Playlist> extends _$PlaylistCopyWithImpl<$Res, _$PlaylistImpl>
implements _$$_PlaylistCopyWith<$Res> { implements _$$PlaylistImplCopyWith<$Res> {
__$$_PlaylistCopyWithImpl( __$$PlaylistImplCopyWithImpl(
_$_Playlist _value, $Res Function(_$_Playlist) _then) _$PlaylistImpl _value, $Res Function(_$PlaylistImpl) _then)
: super(_value, _then); : super(_value, _then);
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@@ -1057,7 +1064,7 @@ class __$$_PlaylistCopyWithImpl<$Res>
Object? songCount = null, Object? songCount = null,
Object? created = null, Object? created = null,
}) { }) {
return _then(_$_Playlist( return _then(_$PlaylistImpl(
sourceId: null == sourceId sourceId: null == sourceId
? _value.sourceId ? _value.sourceId
: sourceId // ignore: cast_nullable_to_non_nullable : sourceId // ignore: cast_nullable_to_non_nullable
@@ -1092,8 +1099,8 @@ class __$$_PlaylistCopyWithImpl<$Res>
/// @nodoc /// @nodoc
class _$_Playlist with DiagnosticableTreeMixin implements _Playlist { class _$PlaylistImpl with DiagnosticableTreeMixin implements _Playlist {
const _$_Playlist( const _$PlaylistImpl(
{required this.sourceId, {required this.sourceId,
required this.id, required this.id,
required this.name, required this.name,
@@ -1137,10 +1144,10 @@ class _$_Playlist with DiagnosticableTreeMixin implements _Playlist {
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$_Playlist && other is _$PlaylistImpl &&
(identical(other.sourceId, sourceId) || (identical(other.sourceId, sourceId) ||
other.sourceId == sourceId) && other.sourceId == sourceId) &&
(identical(other.id, id) || other.id == id) && (identical(other.id, id) || other.id == id) &&
@@ -1160,8 +1167,8 @@ class _$_Playlist with DiagnosticableTreeMixin implements _Playlist {
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$_PlaylistCopyWith<_$_Playlist> get copyWith => _$$PlaylistImplCopyWith<_$PlaylistImpl> get copyWith =>
__$$_PlaylistCopyWithImpl<_$_Playlist>(this, _$identity); __$$PlaylistImplCopyWithImpl<_$PlaylistImpl>(this, _$identity);
} }
abstract class _Playlist implements Playlist { abstract class _Playlist implements Playlist {
@@ -1172,7 +1179,7 @@ abstract class _Playlist implements Playlist {
final String? comment, final String? comment,
final String? coverArt, final String? coverArt,
required final int songCount, required final int songCount,
required final DateTime created}) = _$_Playlist; required final DateTime created}) = _$PlaylistImpl;
@override @override
int get sourceId; int get sourceId;
@@ -1190,7 +1197,7 @@ abstract class _Playlist implements Playlist {
DateTime get created; DateTime get created;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$_PlaylistCopyWith<_$_Playlist> get copyWith => _$$PlaylistImplCopyWith<_$PlaylistImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
@@ -1334,9 +1341,10 @@ class _$SongCopyWithImpl<$Res, $Val extends Song>
} }
/// @nodoc /// @nodoc
abstract class _$$_SongCopyWith<$Res> implements $SongCopyWith<$Res> { abstract class _$$SongImplCopyWith<$Res> implements $SongCopyWith<$Res> {
factory _$$_SongCopyWith(_$_Song value, $Res Function(_$_Song) then) = factory _$$SongImplCopyWith(
__$$_SongCopyWithImpl<$Res>; _$SongImpl value, $Res Function(_$SongImpl) then) =
__$$SongImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call( $Res call(
@@ -1358,9 +1366,10 @@ abstract class _$$_SongCopyWith<$Res> implements $SongCopyWith<$Res> {
} }
/// @nodoc /// @nodoc
class __$$_SongCopyWithImpl<$Res> extends _$SongCopyWithImpl<$Res, _$_Song> class __$$SongImplCopyWithImpl<$Res>
implements _$$_SongCopyWith<$Res> { extends _$SongCopyWithImpl<$Res, _$SongImpl>
__$$_SongCopyWithImpl(_$_Song _value, $Res Function(_$_Song) _then) implements _$$SongImplCopyWith<$Res> {
__$$SongImplCopyWithImpl(_$SongImpl _value, $Res Function(_$SongImpl) _then)
: super(_value, _then); : super(_value, _then);
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@@ -1382,7 +1391,7 @@ class __$$_SongCopyWithImpl<$Res> extends _$SongCopyWithImpl<$Res, _$_Song>
Object? downloadFilePath = freezed, Object? downloadFilePath = freezed,
Object? isDeleted = null, Object? isDeleted = null,
}) { }) {
return _then(_$_Song( return _then(_$SongImpl(
sourceId: null == sourceId sourceId: null == sourceId
? _value.sourceId ? _value.sourceId
: sourceId // ignore: cast_nullable_to_non_nullable : sourceId // ignore: cast_nullable_to_non_nullable
@@ -1449,8 +1458,8 @@ class __$$_SongCopyWithImpl<$Res> extends _$SongCopyWithImpl<$Res, _$_Song>
/// @nodoc /// @nodoc
class _$_Song with DiagnosticableTreeMixin implements _Song { class _$SongImpl with DiagnosticableTreeMixin implements _Song {
const _$_Song( const _$SongImpl(
{required this.sourceId, {required this.sourceId,
required this.id, required this.id,
this.albumId, this.albumId,
@@ -1527,10 +1536,10 @@ class _$_Song with DiagnosticableTreeMixin implements _Song {
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$_Song && other is _$SongImpl &&
(identical(other.sourceId, sourceId) || (identical(other.sourceId, sourceId) ||
other.sourceId == sourceId) && other.sourceId == sourceId) &&
(identical(other.id, id) || other.id == id) && (identical(other.id, id) || other.id == id) &&
@@ -1576,8 +1585,8 @@ class _$_Song with DiagnosticableTreeMixin implements _Song {
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$_SongCopyWith<_$_Song> get copyWith => _$$SongImplCopyWith<_$SongImpl> get copyWith =>
__$$_SongCopyWithImpl<_$_Song>(this, _$identity); __$$SongImplCopyWithImpl<_$SongImpl>(this, _$identity);
} }
abstract class _Song implements Song { abstract class _Song implements Song {
@@ -1596,7 +1605,7 @@ abstract class _Song implements Song {
final String? genre, final String? genre,
final String? downloadTaskId, final String? downloadTaskId,
final String? downloadFilePath, final String? downloadFilePath,
final bool isDeleted}) = _$_Song; final bool isDeleted}) = _$SongImpl;
@override @override
int get sourceId; int get sourceId;
@@ -1630,7 +1639,8 @@ abstract class _Song implements Song {
bool get isDeleted; bool get isDeleted;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$_SongCopyWith<_$_Song> get copyWith => throw _privateConstructorUsedError; _$$SongImplCopyWith<_$SongImpl> get copyWith =>
throw _privateConstructorUsedError;
} }
/// @nodoc /// @nodoc
@@ -1698,11 +1708,11 @@ class _$SearchResultsCopyWithImpl<$Res, $Val extends SearchResults>
} }
/// @nodoc /// @nodoc
abstract class _$$_SearchResultsCopyWith<$Res> abstract class _$$SearchResultsImplCopyWith<$Res>
implements $SearchResultsCopyWith<$Res> { implements $SearchResultsCopyWith<$Res> {
factory _$$_SearchResultsCopyWith( factory _$$SearchResultsImplCopyWith(
_$_SearchResults value, $Res Function(_$_SearchResults) then) = _$SearchResultsImpl value, $Res Function(_$SearchResultsImpl) then) =
__$$_SearchResultsCopyWithImpl<$Res>; __$$SearchResultsImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call( $Res call(
@@ -1713,11 +1723,11 @@ abstract class _$$_SearchResultsCopyWith<$Res>
} }
/// @nodoc /// @nodoc
class __$$_SearchResultsCopyWithImpl<$Res> class __$$SearchResultsImplCopyWithImpl<$Res>
extends _$SearchResultsCopyWithImpl<$Res, _$_SearchResults> extends _$SearchResultsCopyWithImpl<$Res, _$SearchResultsImpl>
implements _$$_SearchResultsCopyWith<$Res> { implements _$$SearchResultsImplCopyWith<$Res> {
__$$_SearchResultsCopyWithImpl( __$$SearchResultsImplCopyWithImpl(
_$_SearchResults _value, $Res Function(_$_SearchResults) _then) _$SearchResultsImpl _value, $Res Function(_$SearchResultsImpl) _then)
: super(_value, _then); : super(_value, _then);
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@@ -1728,7 +1738,7 @@ class __$$_SearchResultsCopyWithImpl<$Res>
Object? albums = null, Object? albums = null,
Object? artists = null, Object? artists = null,
}) { }) {
return _then(_$_SearchResults( return _then(_$SearchResultsImpl(
query: freezed == query query: freezed == query
? _value.query ? _value.query
: query // ignore: cast_nullable_to_non_nullable : query // ignore: cast_nullable_to_non_nullable
@@ -1751,8 +1761,10 @@ class __$$_SearchResultsCopyWithImpl<$Res>
/// @nodoc /// @nodoc
class _$_SearchResults with DiagnosticableTreeMixin implements _SearchResults { class _$SearchResultsImpl
const _$_SearchResults( with DiagnosticableTreeMixin
implements _SearchResults {
const _$SearchResultsImpl(
{this.query, {this.query,
this.songs = const IListConst([]), this.songs = const IListConst([]),
this.albums = const IListConst([]), this.albums = const IListConst([]),
@@ -1787,10 +1799,10 @@ class _$_SearchResults with DiagnosticableTreeMixin implements _SearchResults {
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$_SearchResults && other is _$SearchResultsImpl &&
(identical(other.query, query) || other.query == query) && (identical(other.query, query) || other.query == query) &&
const DeepCollectionEquality().equals(other.songs, songs) && const DeepCollectionEquality().equals(other.songs, songs) &&
const DeepCollectionEquality().equals(other.albums, albums) && const DeepCollectionEquality().equals(other.albums, albums) &&
@@ -1808,8 +1820,8 @@ class _$_SearchResults with DiagnosticableTreeMixin implements _SearchResults {
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$_SearchResultsCopyWith<_$_SearchResults> get copyWith => _$$SearchResultsImplCopyWith<_$SearchResultsImpl> get copyWith =>
__$$_SearchResultsCopyWithImpl<_$_SearchResults>(this, _$identity); __$$SearchResultsImplCopyWithImpl<_$SearchResultsImpl>(this, _$identity);
} }
abstract class _SearchResults implements SearchResults { abstract class _SearchResults implements SearchResults {
@@ -1817,7 +1829,7 @@ abstract class _SearchResults implements SearchResults {
{final String? query, {final String? query,
final IList<Song> songs, final IList<Song> songs,
final IList<Album> albums, final IList<Album> albums,
final IList<Artist> artists}) = _$_SearchResults; final IList<Artist> artists}) = _$SearchResultsImpl;
@override @override
String? get query; String? get query;
@@ -1829,6 +1841,6 @@ abstract class _SearchResults implements SearchResults {
IList<Artist> get artists; IList<Artist> get artists;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$_SearchResultsCopyWith<_$_SearchResults> get copyWith => _$$SearchResultsImplCopyWith<_$SearchResultsImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -6,25 +6,26 @@ part of 'query.dart';
// JsonSerializableGenerator // JsonSerializableGenerator
// ************************************************************************** // **************************************************************************
_$_Pagination _$$_PaginationFromJson(Map<String, dynamic> json) => _$PaginationImpl _$$PaginationImplFromJson(Map<String, dynamic> json) =>
_$_Pagination( _$PaginationImpl(
limit: json['limit'] as int, limit: (json['limit'] as num).toInt(),
offset: json['offset'] as int? ?? 0, offset: (json['offset'] as num?)?.toInt() ?? 0,
); );
Map<String, dynamic> _$$_PaginationToJson(_$_Pagination instance) => Map<String, dynamic> _$$PaginationImplToJson(_$PaginationImpl instance) =>
<String, dynamic>{ <String, dynamic>{
'limit': instance.limit, 'limit': instance.limit,
'offset': instance.offset, 'offset': instance.offset,
}; };
_$_SortBy _$$_SortByFromJson(Map<String, dynamic> json) => _$_SortBy( _$SortByImpl _$$SortByImplFromJson(Map<String, dynamic> json) => _$SortByImpl(
column: json['column'] as String, column: json['column'] as String,
dir: $enumDecodeNullable(_$SortDirectionEnumMap, json['dir']) ?? dir: $enumDecodeNullable(_$SortDirectionEnumMap, json['dir']) ??
SortDirection.asc, SortDirection.asc,
); );
Map<String, dynamic> _$$_SortByToJson(_$_SortBy instance) => <String, dynamic>{ Map<String, dynamic> _$$SortByImplToJson(_$SortByImpl instance) =>
<String, dynamic>{
'column': instance.column, 'column': instance.column,
'dir': _$SortDirectionEnumMap[instance.dir]!, 'dir': _$SortDirectionEnumMap[instance.dir]!,
}; };
@@ -34,15 +35,17 @@ const _$SortDirectionEnumMap = {
SortDirection.desc: 'desc', SortDirection.desc: 'desc',
}; };
_$_FilterWithEquals _$$_FilterWithEqualsFromJson(Map<String, dynamic> json) => _$FilterWithEqualsImpl _$$FilterWithEqualsImplFromJson(
_$_FilterWithEquals( Map<String, dynamic> json) =>
_$FilterWithEqualsImpl(
column: json['column'] as String, column: json['column'] as String,
value: json['value'] as String, value: json['value'] as String,
invert: json['invert'] as bool? ?? false, invert: json['invert'] as bool? ?? false,
$type: json['runtimeType'] as String?, $type: json['runtimeType'] as String?,
); );
Map<String, dynamic> _$$_FilterWithEqualsToJson(_$_FilterWithEquals instance) => Map<String, dynamic> _$$FilterWithEqualsImplToJson(
_$FilterWithEqualsImpl instance) =>
<String, dynamic>{ <String, dynamic>{
'column': instance.column, 'column': instance.column,
'value': instance.value, 'value': instance.value,
@@ -50,17 +53,17 @@ Map<String, dynamic> _$$_FilterWithEqualsToJson(_$_FilterWithEquals instance) =>
'runtimeType': instance.$type, 'runtimeType': instance.$type,
}; };
_$_FilterWithGreaterThan _$$_FilterWithGreaterThanFromJson( _$FilterWithGreaterThanImpl _$$FilterWithGreaterThanImplFromJson(
Map<String, dynamic> json) => Map<String, dynamic> json) =>
_$_FilterWithGreaterThan( _$FilterWithGreaterThanImpl(
column: json['column'] as String, column: json['column'] as String,
value: json['value'] as String, value: json['value'] as String,
orEquals: json['orEquals'] as bool? ?? false, orEquals: json['orEquals'] as bool? ?? false,
$type: json['runtimeType'] as String?, $type: json['runtimeType'] as String?,
); );
Map<String, dynamic> _$$_FilterWithGreaterThanToJson( Map<String, dynamic> _$$FilterWithGreaterThanImplToJson(
_$_FilterWithGreaterThan instance) => _$FilterWithGreaterThanImpl instance) =>
<String, dynamic>{ <String, dynamic>{
'column': instance.column, 'column': instance.column,
'value': instance.value, 'value': instance.value,
@@ -68,31 +71,33 @@ Map<String, dynamic> _$$_FilterWithGreaterThanToJson(
'runtimeType': instance.$type, 'runtimeType': instance.$type,
}; };
_$_FilterWithIsNull _$$_FilterWithIsNullFromJson(Map<String, dynamic> json) => _$FilterWithIsNullImpl _$$FilterWithIsNullImplFromJson(
_$_FilterWithIsNull( Map<String, dynamic> json) =>
_$FilterWithIsNullImpl(
column: json['column'] as String, column: json['column'] as String,
invert: json['invert'] as bool? ?? false, invert: json['invert'] as bool? ?? false,
$type: json['runtimeType'] as String?, $type: json['runtimeType'] as String?,
); );
Map<String, dynamic> _$$_FilterWithIsNullToJson(_$_FilterWithIsNull instance) => Map<String, dynamic> _$$FilterWithIsNullImplToJson(
_$FilterWithIsNullImpl instance) =>
<String, dynamic>{ <String, dynamic>{
'column': instance.column, 'column': instance.column,
'invert': instance.invert, 'invert': instance.invert,
'runtimeType': instance.$type, 'runtimeType': instance.$type,
}; };
_$_FilterWithBetweenInt _$$_FilterWithBetweenIntFromJson( _$FilterWithBetweenIntImpl _$$FilterWithBetweenIntImplFromJson(
Map<String, dynamic> json) => Map<String, dynamic> json) =>
_$_FilterWithBetweenInt( _$FilterWithBetweenIntImpl(
column: json['column'] as String, column: json['column'] as String,
from: json['from'] as int, from: (json['from'] as num).toInt(),
to: json['to'] as int, to: (json['to'] as num).toInt(),
$type: json['runtimeType'] as String?, $type: json['runtimeType'] as String?,
); );
Map<String, dynamic> _$$_FilterWithBetweenIntToJson( Map<String, dynamic> _$$FilterWithBetweenIntImplToJson(
_$_FilterWithBetweenInt instance) => _$FilterWithBetweenIntImpl instance) =>
<String, dynamic>{ <String, dynamic>{
'column': instance.column, 'column': instance.column,
'from': instance.from, 'from': instance.from,
@@ -100,8 +105,8 @@ Map<String, dynamic> _$$_FilterWithBetweenIntToJson(
'runtimeType': instance.$type, 'runtimeType': instance.$type,
}; };
_$_FilterWithIsIn _$$_FilterWithIsInFromJson(Map<String, dynamic> json) => _$FilterWithIsInImpl _$$FilterWithIsInImplFromJson(Map<String, dynamic> json) =>
_$_FilterWithIsIn( _$FilterWithIsInImpl(
column: json['column'] as String, column: json['column'] as String,
invert: json['invert'] as bool? ?? false, invert: json['invert'] as bool? ?? false,
values: json['values'] == null values: json['values'] == null
@@ -110,7 +115,8 @@ _$_FilterWithIsIn _$$_FilterWithIsInFromJson(Map<String, dynamic> json) =>
$type: json['runtimeType'] as String?, $type: json['runtimeType'] as String?,
); );
Map<String, dynamic> _$$_FilterWithIsInToJson(_$_FilterWithIsIn instance) => Map<String, dynamic> _$$FilterWithIsInImplToJson(
_$FilterWithIsInImpl instance) =>
<String, dynamic>{ <String, dynamic>{
'column': instance.column, 'column': instance.column,
'invert': instance.invert, 'invert': instance.invert,
@@ -120,7 +126,8 @@ Map<String, dynamic> _$$_FilterWithIsInToJson(_$_FilterWithIsIn instance) =>
'runtimeType': instance.$type, 'runtimeType': instance.$type,
}; };
_$_ListQuery _$$_ListQueryFromJson(Map<String, dynamic> json) => _$_ListQuery( _$ListQueryImpl _$$ListQueryImplFromJson(Map<String, dynamic> json) =>
_$ListQueryImpl(
page: json['page'] == null page: json['page'] == null
? const Pagination(limit: -1, offset: 0) ? const Pagination(limit: -1, offset: 0)
: Pagination.fromJson(json['page'] as Map<String, dynamic>), : Pagination.fromJson(json['page'] as Map<String, dynamic>),
@@ -133,7 +140,7 @@ _$_ListQuery _$$_ListQueryFromJson(Map<String, dynamic> json) => _$_ListQuery(
(value) => FilterWith.fromJson(value as Map<String, dynamic>)), (value) => FilterWith.fromJson(value as Map<String, dynamic>)),
); );
Map<String, dynamic> _$$_ListQueryToJson(_$_ListQuery instance) => Map<String, dynamic> _$$ListQueryImplToJson(_$ListQueryImpl instance) =>
<String, dynamic>{ <String, dynamic>{
'page': instance.page, 'page': instance.page,
'sort': instance.sort, 'sort': instance.sort,

View File

@@ -12,7 +12,7 @@ part of 'settings.dart';
T _$identity<T>(T value) => value; T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError( final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc /// @nodoc
mixin _$Settings { mixin _$Settings {
@@ -81,10 +81,11 @@ class _$SettingsCopyWithImpl<$Res, $Val extends Settings>
} }
/// @nodoc /// @nodoc
abstract class _$$_SettingsCopyWith<$Res> implements $SettingsCopyWith<$Res> { abstract class _$$SettingsImplCopyWith<$Res>
factory _$$_SettingsCopyWith( implements $SettingsCopyWith<$Res> {
_$_Settings value, $Res Function(_$_Settings) then) = factory _$$SettingsImplCopyWith(
__$$_SettingsCopyWithImpl<$Res>; _$SettingsImpl value, $Res Function(_$SettingsImpl) then) =
__$$SettingsImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call( $Res call(
@@ -97,11 +98,11 @@ abstract class _$$_SettingsCopyWith<$Res> implements $SettingsCopyWith<$Res> {
} }
/// @nodoc /// @nodoc
class __$$_SettingsCopyWithImpl<$Res> class __$$SettingsImplCopyWithImpl<$Res>
extends _$SettingsCopyWithImpl<$Res, _$_Settings> extends _$SettingsCopyWithImpl<$Res, _$SettingsImpl>
implements _$$_SettingsCopyWith<$Res> { implements _$$SettingsImplCopyWith<$Res> {
__$$_SettingsCopyWithImpl( __$$SettingsImplCopyWithImpl(
_$_Settings _value, $Res Function(_$_Settings) _then) _$SettingsImpl _value, $Res Function(_$SettingsImpl) _then)
: super(_value, _then); : super(_value, _then);
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@@ -111,7 +112,7 @@ class __$$_SettingsCopyWithImpl<$Res>
Object? activeSource = freezed, Object? activeSource = freezed,
Object? app = null, Object? app = null,
}) { }) {
return _then(_$_Settings( return _then(_$SettingsImpl(
sources: null == sources sources: null == sources
? _value.sources ? _value.sources
: sources // ignore: cast_nullable_to_non_nullable : sources // ignore: cast_nullable_to_non_nullable
@@ -130,8 +131,8 @@ class __$$_SettingsCopyWithImpl<$Res>
/// @nodoc /// @nodoc
class _$_Settings implements _Settings { class _$SettingsImpl implements _Settings {
const _$_Settings( const _$SettingsImpl(
{this.sources = const IListConst([]), {this.sources = const IListConst([]),
this.activeSource, this.activeSource,
this.app = const AppSettings()}); this.app = const AppSettings()});
@@ -151,10 +152,10 @@ class _$_Settings implements _Settings {
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$_Settings && other is _$SettingsImpl &&
const DeepCollectionEquality().equals(other.sources, sources) && const DeepCollectionEquality().equals(other.sources, sources) &&
(identical(other.activeSource, activeSource) || (identical(other.activeSource, activeSource) ||
other.activeSource == activeSource) && other.activeSource == activeSource) &&
@@ -168,15 +169,15 @@ class _$_Settings implements _Settings {
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$_SettingsCopyWith<_$_Settings> get copyWith => _$$SettingsImplCopyWith<_$SettingsImpl> get copyWith =>
__$$_SettingsCopyWithImpl<_$_Settings>(this, _$identity); __$$SettingsImplCopyWithImpl<_$SettingsImpl>(this, _$identity);
} }
abstract class _Settings implements Settings { abstract class _Settings implements Settings {
const factory _Settings( const factory _Settings(
{final IList<SourceSettings> sources, {final IList<SourceSettings> sources,
final SourceSettings? activeSource, final SourceSettings? activeSource,
final AppSettings app}) = _$_Settings; final AppSettings app}) = _$SettingsImpl;
@override @override
IList<SourceSettings> get sources; IList<SourceSettings> get sources;
@@ -186,7 +187,7 @@ abstract class _Settings implements Settings {
AppSettings get app; AppSettings get app;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$_SettingsCopyWith<_$_Settings> get copyWith => _$$SettingsImplCopyWith<_$SettingsImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
@@ -245,22 +246,22 @@ class _$AppSettingsCopyWithImpl<$Res, $Val extends AppSettings>
} }
/// @nodoc /// @nodoc
abstract class _$$_AppSettingsCopyWith<$Res> abstract class _$$AppSettingsImplCopyWith<$Res>
implements $AppSettingsCopyWith<$Res> { implements $AppSettingsCopyWith<$Res> {
factory _$$_AppSettingsCopyWith( factory _$$AppSettingsImplCopyWith(
_$_AppSettings value, $Res Function(_$_AppSettings) then) = _$AppSettingsImpl value, $Res Function(_$AppSettingsImpl) then) =
__$$_AppSettingsCopyWithImpl<$Res>; __$$AppSettingsImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call({int maxBitrateWifi, int maxBitrateMobile, String? streamFormat}); $Res call({int maxBitrateWifi, int maxBitrateMobile, String? streamFormat});
} }
/// @nodoc /// @nodoc
class __$$_AppSettingsCopyWithImpl<$Res> class __$$AppSettingsImplCopyWithImpl<$Res>
extends _$AppSettingsCopyWithImpl<$Res, _$_AppSettings> extends _$AppSettingsCopyWithImpl<$Res, _$AppSettingsImpl>
implements _$$_AppSettingsCopyWith<$Res> { implements _$$AppSettingsImplCopyWith<$Res> {
__$$_AppSettingsCopyWithImpl( __$$AppSettingsImplCopyWithImpl(
_$_AppSettings _value, $Res Function(_$_AppSettings) _then) _$AppSettingsImpl _value, $Res Function(_$AppSettingsImpl) _then)
: super(_value, _then); : super(_value, _then);
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@@ -270,7 +271,7 @@ class __$$_AppSettingsCopyWithImpl<$Res>
Object? maxBitrateMobile = null, Object? maxBitrateMobile = null,
Object? streamFormat = freezed, Object? streamFormat = freezed,
}) { }) {
return _then(_$_AppSettings( return _then(_$AppSettingsImpl(
maxBitrateWifi: null == maxBitrateWifi maxBitrateWifi: null == maxBitrateWifi
? _value.maxBitrateWifi ? _value.maxBitrateWifi
: maxBitrateWifi // ignore: cast_nullable_to_non_nullable : maxBitrateWifi // ignore: cast_nullable_to_non_nullable
@@ -289,8 +290,8 @@ class __$$_AppSettingsCopyWithImpl<$Res>
/// @nodoc /// @nodoc
class _$_AppSettings extends _AppSettings { class _$AppSettingsImpl extends _AppSettings {
const _$_AppSettings( const _$AppSettingsImpl(
{this.maxBitrateWifi = 0, {this.maxBitrateWifi = 0,
this.maxBitrateMobile = 192, this.maxBitrateMobile = 192,
this.streamFormat = 'mp3'}) this.streamFormat = 'mp3'})
@@ -312,10 +313,10 @@ class _$_AppSettings extends _AppSettings {
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$_AppSettings && other is _$AppSettingsImpl &&
(identical(other.maxBitrateWifi, maxBitrateWifi) || (identical(other.maxBitrateWifi, maxBitrateWifi) ||
other.maxBitrateWifi == maxBitrateWifi) && other.maxBitrateWifi == maxBitrateWifi) &&
(identical(other.maxBitrateMobile, maxBitrateMobile) || (identical(other.maxBitrateMobile, maxBitrateMobile) ||
@@ -331,15 +332,15 @@ class _$_AppSettings extends _AppSettings {
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$_AppSettingsCopyWith<_$_AppSettings> get copyWith => _$$AppSettingsImplCopyWith<_$AppSettingsImpl> get copyWith =>
__$$_AppSettingsCopyWithImpl<_$_AppSettings>(this, _$identity); __$$AppSettingsImplCopyWithImpl<_$AppSettingsImpl>(this, _$identity);
} }
abstract class _AppSettings extends AppSettings { abstract class _AppSettings extends AppSettings {
const factory _AppSettings( const factory _AppSettings(
{final int maxBitrateWifi, {final int maxBitrateWifi,
final int maxBitrateMobile, final int maxBitrateMobile,
final String? streamFormat}) = _$_AppSettings; final String? streamFormat}) = _$AppSettingsImpl;
const _AppSettings._() : super._(); const _AppSettings._() : super._();
@override @override
@@ -350,7 +351,7 @@ abstract class _AppSettings extends AppSettings {
String? get streamFormat; String? get streamFormat;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$_AppSettingsCopyWith<_$_AppSettings> get copyWith => _$$AppSettingsImplCopyWith<_$AppSettingsImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
@@ -454,11 +455,11 @@ class _$SubsonicSettingsCopyWithImpl<$Res, $Val extends SubsonicSettings>
} }
/// @nodoc /// @nodoc
abstract class _$$_SubsonicSettingsCopyWith<$Res> abstract class _$$SubsonicSettingsImplCopyWith<$Res>
implements $SubsonicSettingsCopyWith<$Res> { implements $SubsonicSettingsCopyWith<$Res> {
factory _$$_SubsonicSettingsCopyWith( factory _$$SubsonicSettingsImplCopyWith(_$SubsonicSettingsImpl value,
_$_SubsonicSettings value, $Res Function(_$_SubsonicSettings) then) = $Res Function(_$SubsonicSettingsImpl) then) =
__$$_SubsonicSettingsCopyWithImpl<$Res>; __$$SubsonicSettingsImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call( $Res call(
@@ -474,11 +475,11 @@ abstract class _$$_SubsonicSettingsCopyWith<$Res>
} }
/// @nodoc /// @nodoc
class __$$_SubsonicSettingsCopyWithImpl<$Res> class __$$SubsonicSettingsImplCopyWithImpl<$Res>
extends _$SubsonicSettingsCopyWithImpl<$Res, _$_SubsonicSettings> extends _$SubsonicSettingsCopyWithImpl<$Res, _$SubsonicSettingsImpl>
implements _$$_SubsonicSettingsCopyWith<$Res> { implements _$$SubsonicSettingsImplCopyWith<$Res> {
__$$_SubsonicSettingsCopyWithImpl( __$$SubsonicSettingsImplCopyWithImpl(_$SubsonicSettingsImpl _value,
_$_SubsonicSettings _value, $Res Function(_$_SubsonicSettings) _then) $Res Function(_$SubsonicSettingsImpl) _then)
: super(_value, _then); : super(_value, _then);
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@@ -494,7 +495,7 @@ class __$$_SubsonicSettingsCopyWithImpl<$Res>
Object? password = null, Object? password = null,
Object? useTokenAuth = null, Object? useTokenAuth = null,
}) { }) {
return _then(_$_SubsonicSettings( return _then(_$SubsonicSettingsImpl(
id: null == id id: null == id
? _value.id ? _value.id
: id // ignore: cast_nullable_to_non_nullable : id // ignore: cast_nullable_to_non_nullable
@@ -537,8 +538,8 @@ class __$$_SubsonicSettingsCopyWithImpl<$Res>
/// @nodoc /// @nodoc
class _$_SubsonicSettings extends _SubsonicSettings { class _$SubsonicSettingsImpl extends _SubsonicSettings {
const _$_SubsonicSettings( const _$SubsonicSettingsImpl(
{required this.id, {required this.id,
this.features = const IListConst([]), this.features = const IListConst([]),
required this.name, required this.name,
@@ -577,10 +578,10 @@ class _$_SubsonicSettings extends _SubsonicSettings {
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$_SubsonicSettings && other is _$SubsonicSettingsImpl &&
(identical(other.id, id) || other.id == id) && (identical(other.id, id) || other.id == id) &&
const DeepCollectionEquality().equals(other.features, features) && const DeepCollectionEquality().equals(other.features, features) &&
(identical(other.name, name) || other.name == name) && (identical(other.name, name) || other.name == name) &&
@@ -613,8 +614,9 @@ class _$_SubsonicSettings extends _SubsonicSettings {
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$_SubsonicSettingsCopyWith<_$_SubsonicSettings> get copyWith => _$$SubsonicSettingsImplCopyWith<_$SubsonicSettingsImpl> get copyWith =>
__$$_SubsonicSettingsCopyWithImpl<_$_SubsonicSettings>(this, _$identity); __$$SubsonicSettingsImplCopyWithImpl<_$SubsonicSettingsImpl>(
this, _$identity);
} }
abstract class _SubsonicSettings extends SubsonicSettings { abstract class _SubsonicSettings extends SubsonicSettings {
@@ -627,7 +629,7 @@ abstract class _SubsonicSettings extends SubsonicSettings {
required final DateTime createdAt, required final DateTime createdAt,
required final String username, required final String username,
required final String password, required final String password,
final bool useTokenAuth}) = _$_SubsonicSettings; final bool useTokenAuth}) = _$SubsonicSettingsImpl;
const _SubsonicSettings._() : super._(); const _SubsonicSettings._() : super._();
@override @override
@@ -650,7 +652,7 @@ abstract class _SubsonicSettings extends SubsonicSettings {
bool get useTokenAuth; bool get useTokenAuth;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$_SubsonicSettingsCopyWith<_$_SubsonicSettings> get copyWith => _$$SubsonicSettingsImplCopyWith<_$SubsonicSettingsImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
@@ -714,11 +716,12 @@ class _$SubsonicSourceSettingsCopyWithImpl<$Res,
} }
/// @nodoc /// @nodoc
abstract class _$$_SubsonicSourceSettingsCopyWith<$Res> abstract class _$$SubsonicSourceSettingsImplCopyWith<$Res>
implements $SubsonicSourceSettingsCopyWith<$Res> { implements $SubsonicSourceSettingsCopyWith<$Res> {
factory _$$_SubsonicSourceSettingsCopyWith(_$_SubsonicSourceSettings value, factory _$$SubsonicSourceSettingsImplCopyWith(
$Res Function(_$_SubsonicSourceSettings) then) = _$SubsonicSourceSettingsImpl value,
__$$_SubsonicSourceSettingsCopyWithImpl<$Res>; $Res Function(_$SubsonicSourceSettingsImpl) then) =
__$$SubsonicSourceSettingsImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call({SourceSettings source, SubsonicSettings subsonic}); $Res call({SourceSettings source, SubsonicSettings subsonic});
@@ -728,12 +731,13 @@ abstract class _$$_SubsonicSourceSettingsCopyWith<$Res>
} }
/// @nodoc /// @nodoc
class __$$_SubsonicSourceSettingsCopyWithImpl<$Res> class __$$SubsonicSourceSettingsImplCopyWithImpl<$Res>
extends _$SubsonicSourceSettingsCopyWithImpl<$Res, extends _$SubsonicSourceSettingsCopyWithImpl<$Res,
_$_SubsonicSourceSettings> _$SubsonicSourceSettingsImpl>
implements _$$_SubsonicSourceSettingsCopyWith<$Res> { implements _$$SubsonicSourceSettingsImplCopyWith<$Res> {
__$$_SubsonicSourceSettingsCopyWithImpl(_$_SubsonicSourceSettings _value, __$$SubsonicSourceSettingsImplCopyWithImpl(
$Res Function(_$_SubsonicSourceSettings) _then) _$SubsonicSourceSettingsImpl _value,
$Res Function(_$SubsonicSourceSettingsImpl) _then)
: super(_value, _then); : super(_value, _then);
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@@ -742,7 +746,7 @@ class __$$_SubsonicSourceSettingsCopyWithImpl<$Res>
Object? source = null, Object? source = null,
Object? subsonic = null, Object? subsonic = null,
}) { }) {
return _then(_$_SubsonicSourceSettings( return _then(_$SubsonicSourceSettingsImpl(
source: null == source source: null == source
? _value.source ? _value.source
: source // ignore: cast_nullable_to_non_nullable : source // ignore: cast_nullable_to_non_nullable
@@ -757,8 +761,8 @@ class __$$_SubsonicSourceSettingsCopyWithImpl<$Res>
/// @nodoc /// @nodoc
class _$_SubsonicSourceSettings extends _SubsonicSourceSettings { class _$SubsonicSourceSettingsImpl extends _SubsonicSourceSettings {
const _$_SubsonicSourceSettings( const _$SubsonicSourceSettingsImpl(
{required this.source, required this.subsonic}) {required this.source, required this.subsonic})
: super._(); : super._();
@@ -773,10 +777,10 @@ class _$_SubsonicSourceSettings extends _SubsonicSourceSettings {
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$_SubsonicSourceSettings && other is _$SubsonicSourceSettingsImpl &&
(identical(other.source, source) || other.source == source) && (identical(other.source, source) || other.source == source) &&
(identical(other.subsonic, subsonic) || (identical(other.subsonic, subsonic) ||
other.subsonic == subsonic)); other.subsonic == subsonic));
@@ -788,15 +792,15 @@ class _$_SubsonicSourceSettings extends _SubsonicSourceSettings {
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$_SubsonicSourceSettingsCopyWith<_$_SubsonicSourceSettings> get copyWith => _$$SubsonicSourceSettingsImplCopyWith<_$SubsonicSourceSettingsImpl>
__$$_SubsonicSourceSettingsCopyWithImpl<_$_SubsonicSourceSettings>( get copyWith => __$$SubsonicSourceSettingsImplCopyWithImpl<
this, _$identity); _$SubsonicSourceSettingsImpl>(this, _$identity);
} }
abstract class _SubsonicSourceSettings extends SubsonicSourceSettings { abstract class _SubsonicSourceSettings extends SubsonicSourceSettings {
const factory _SubsonicSourceSettings( const factory _SubsonicSourceSettings(
{required final SourceSettings source, {required final SourceSettings source,
required final SubsonicSettings subsonic}) = _$_SubsonicSourceSettings; required final SubsonicSettings subsonic}) = _$SubsonicSourceSettingsImpl;
const _SubsonicSourceSettings._() : super._(); const _SubsonicSourceSettings._() : super._();
@override @override
@@ -805,6 +809,6 @@ abstract class _SubsonicSourceSettings extends SubsonicSourceSettings {
SubsonicSettings get subsonic; SubsonicSettings get subsonic;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$_SubsonicSourceSettingsCopyWith<_$_SubsonicSourceSettings> get copyWith => _$$SubsonicSourceSettingsImplCopyWith<_$SubsonicSourceSettingsImpl>
throw _privateConstructorUsedError; get copyWith => throw _privateConstructorUsedError;
} }

View File

@@ -68,7 +68,8 @@ enum QueueContextType {
album('album'), album('album'),
playlist('playlist'), playlist('playlist'),
library('library'), library('library'),
genre('genre'); genre('genre'),
artist('artist');
const QueueContextType(this.value); const QueueContextType(this.value);
final String value; final String value;

File diff suppressed because it is too large Load Diff

View File

@@ -6,15 +6,16 @@ part of 'support.dart';
// JsonSerializableGenerator // JsonSerializableGenerator
// ************************************************************************** // **************************************************************************
_$_QueueItemState _$$_QueueItemStateFromJson(Map<String, dynamic> json) => _$QueueItemStateImpl _$$QueueItemStateImplFromJson(Map<String, dynamic> json) =>
_$_QueueItemState( _$QueueItemStateImpl(
id: json['id'] as String, id: json['id'] as String,
contextType: $enumDecode(_$QueueContextTypeEnumMap, json['contextType']), contextType: $enumDecode(_$QueueContextTypeEnumMap, json['contextType']),
contextId: json['contextId'] as String?, contextId: json['contextId'] as String?,
contextTitle: json['contextTitle'] as String?, contextTitle: json['contextTitle'] as String?,
); );
Map<String, dynamic> _$$_QueueItemStateToJson(_$_QueueItemState instance) => Map<String, dynamic> _$$QueueItemStateImplToJson(
_$QueueItemStateImpl instance) =>
<String, dynamic>{ <String, dynamic>{
'id': instance.id, 'id': instance.id,
'contextType': _$QueueContextTypeEnumMap[instance.contextType]!, 'contextType': _$QueueContextTypeEnumMap[instance.contextType]!,
@@ -28,11 +29,12 @@ const _$QueueContextTypeEnumMap = {
QueueContextType.playlist: 'playlist', QueueContextType.playlist: 'playlist',
QueueContextType.library: 'library', QueueContextType.library: 'library',
QueueContextType.genre: 'genre', QueueContextType.genre: 'genre',
QueueContextType.artist: 'artist',
}; };
_$_MediaItemData _$$_MediaItemDataFromJson(Map<String, dynamic> json) => _$MediaItemDataImpl _$$MediaItemDataImplFromJson(Map<String, dynamic> json) =>
_$_MediaItemData( _$MediaItemDataImpl(
sourceId: json['sourceId'] as int, sourceId: (json['sourceId'] as num).toInt(),
albumId: json['albumId'] as String?, albumId: json['albumId'] as String?,
artCache: artCache:
_$JsonConverterFromJson<Map<String, dynamic>, MediaItemArtCache>( _$JsonConverterFromJson<Map<String, dynamic>, MediaItemArtCache>(
@@ -41,7 +43,7 @@ _$_MediaItemData _$$_MediaItemDataFromJson(Map<String, dynamic> json) =>
contextId: json['contextId'] as String?, contextId: json['contextId'] as String?,
); );
Map<String, dynamic> _$$_MediaItemDataToJson(_$_MediaItemData instance) => Map<String, dynamic> _$$MediaItemDataImplToJson(_$MediaItemDataImpl instance) =>
<String, dynamic>{ <String, dynamic>{
'sourceId': instance.sourceId, 'sourceId': instance.sourceId,
'albumId': instance.albumId, 'albumId': instance.albumId,
@@ -64,16 +66,17 @@ Json? _$JsonConverterToJson<Json, Value>(
) => ) =>
value == null ? null : toJson(value); value == null ? null : toJson(value);
_$_MediaItemArtCache _$$_MediaItemArtCacheFromJson(Map<String, dynamic> json) => _$MediaItemArtCacheImpl _$$MediaItemArtCacheImplFromJson(
_$_MediaItemArtCache( Map<String, dynamic> json) =>
_$MediaItemArtCacheImpl(
fullArtUri: Uri.parse(json['fullArtUri'] as String), fullArtUri: Uri.parse(json['fullArtUri'] as String),
fullArtCacheKey: json['fullArtCacheKey'] as String, fullArtCacheKey: json['fullArtCacheKey'] as String,
thumbnailArtUri: Uri.parse(json['thumbnailArtUri'] as String), thumbnailArtUri: Uri.parse(json['thumbnailArtUri'] as String),
thumbnailArtCacheKey: json['thumbnailArtCacheKey'] as String, thumbnailArtCacheKey: json['thumbnailArtCacheKey'] as String,
); );
Map<String, dynamic> _$$_MediaItemArtCacheToJson( Map<String, dynamic> _$$MediaItemArtCacheImplToJson(
_$_MediaItemArtCache instance) => _$MediaItemArtCacheImpl instance) =>
<String, dynamic>{ <String, dynamic>{
'fullArtUri': instance.fullArtUri.toString(), 'fullArtUri': instance.fullArtUri.toString(),
'fullArtCacheKey': instance.fullArtCacheKey, 'fullArtCacheKey': instance.fullArtCacheKey,

View File

@@ -4,7 +4,6 @@ import 'dart:math';
import 'package:audio_service/audio_service.dart'; import 'package:audio_service/audio_service.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:drift/drift.dart' show Value; import 'package:drift/drift.dart' show Value;
import 'package:flutter/foundation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:just_audio/just_audio.dart'; import 'package:just_audio/just_audio.dart';
import 'package:pool/pool.dart'; import 'package:pool/pool.dart';
@@ -14,6 +13,7 @@ import 'package:synchronized/synchronized.dart';
import '../cache/image_cache.dart'; import '../cache/image_cache.dart';
import '../database/database.dart'; import '../database/database.dart';
import '../log.dart';
import '../models/music.dart'; import '../models/music.dart';
import '../models/query.dart'; import '../models/query.dart';
import '../models/support.dart'; import '../models/support.dart';
@@ -122,6 +122,10 @@ class AudioControl extends BaseAudioHandler with QueueHandler, SeekHandler {
)); ));
}); });
_player.playbackEventStream.doOnError((e, st) async {
log.warning('playbackEventStream', e, st);
});
shuffleIndicies.listen((value) { shuffleIndicies.listen((value) {
playbackState.add(playbackState.value.copyWith( playbackState.add(playbackState.value.copyWith(
shuffleMode: value != null shuffleMode: value != null
@@ -137,7 +141,7 @@ class AudioControl extends BaseAudioHandler with QueueHandler, SeekHandler {
_player.processingStateStream.listen((event) async { _player.processingStateStream.listen((event) async {
if (event == ProcessingState.completed) { if (event == ProcessingState.completed) {
if (_audioSource.length > 0) { if (_audioSource.length > 0) {
yell('completed'); log.fine('completed');
await stop(); await stop();
await seek(Duration.zero); await seek(Duration.zero);
} }
@@ -386,7 +390,7 @@ class AudioControl extends BaseAudioHandler with QueueHandler, SeekHandler {
mediaItem.add(slice.current!.mediaItem); mediaItem.add(slice.current!.mediaItem);
queue.add(list.map((e) => e.mediaItem).toList()); queue.add(list.map((e) => e.mediaItem).toList());
yell('addAll'); log.fine('addAll');
await _audioSource.addAll(list.map((e) => e.audioSource).toList()); await _audioSource.addAll(list.map((e) => e.audioSource).toList());
await _player.seek(Duration.zero, index: list.indexOf(slice.current!)); await _player.seek(Duration.zero, index: list.indexOf(slice.current!));
} }
@@ -410,7 +414,7 @@ class AudioControl extends BaseAudioHandler with QueueHandler, SeekHandler {
final sourceNeedsPrev = sourceIndex == 0; final sourceNeedsPrev = sourceIndex == 0;
if (sourceNeedsNext && slice.next != null) { if (sourceNeedsNext && slice.next != null) {
yell('add'); log.fine('add');
await _audioSource.add(slice.next!.audioSource); await _audioSource.add(slice.next!.audioSource);
} }
if (sourceNeedsPrev && slice.prev != null) { if (sourceNeedsPrev && slice.prev != null) {
@@ -497,7 +501,7 @@ class AudioControl extends BaseAudioHandler with QueueHandler, SeekHandler {
} }
Future<void> _insertFirstAudioSource(AudioSource source) { Future<void> _insertFirstAudioSource(AudioSource source) {
yell('insert'); log.fine('insert');
final wait = _audioSource.insert(0, source); final wait = _audioSource.insert(0, source);
_currentIndexIgnore.add(1); _currentIndexIgnore.add(1);
return wait; return wait;
@@ -505,20 +509,20 @@ class AudioControl extends BaseAudioHandler with QueueHandler, SeekHandler {
Future<void> _pruneAudioSources(int keepIndex) async { Future<void> _pruneAudioSources(int keepIndex) async {
if (keepIndex > 0) { if (keepIndex > 0) {
yell('removeRange 0'); log.fine('removeRange 0');
final wait = _audioSource.removeRange(0, keepIndex); final wait = _audioSource.removeRange(0, keepIndex);
_currentIndexIgnore.add(0); _currentIndexIgnore.add(0);
await wait; await wait;
} }
if (_audioSource.length > 1) { if (_audioSource.length > 1) {
yell('removeRange 1'); log.fine('removeRange 1');
await _audioSource.removeRange(1, _audioSource.length); await _audioSource.removeRange(1, _audioSource.length);
} }
} }
Future<void> _clearAudioSource([bool clearMetadata = false]) async { Future<void> _clearAudioSource([bool clearMetadata = false]) async {
// await _player.stop(); // await _player.stop();
yell('_clearAudioSource'); log.fine('_clearAudioSource');
await _audioSource.clear(); await _audioSource.clear();
if (clearMetadata) { if (clearMetadata) {
@@ -697,11 +701,3 @@ class AudioControl extends BaseAudioHandler with QueueHandler, SeekHandler {
} }
} }
} }
void yell(String msg) {
if (kDebugMode) {
print('=================================================================<');
print(msg);
print('=================================================================>');
}
}

View File

@@ -35,4 +35,5 @@ final audioControlProvider = Provider<AudioControl>.internal(
); );
typedef AudioControlRef = ProviderRef<AudioControl>; typedef AudioControlRef = ProviderRef<AudioControl>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -20,4 +20,5 @@ final cacheServiceProvider = Provider<CacheService>.internal(
); );
typedef CacheServiceRef = ProviderRef<CacheService>; typedef CacheServiceRef = ProviderRef<CacheService>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -214,7 +214,7 @@ class DownloadService extends _$DownloadService {
Future<void> deleteAll(int sourceId) async { Future<void> deleteAll(int sourceId) async {
final db = ref.read(databaseProvider); final db = ref.read(databaseProvider);
final albumIds = await db.albumIdsWithDownloaded(sourceId).get(); final albumIds = await db.albumIdsWithDownloadStatus(sourceId).get();
for (var id in albumIds) { for (var id in albumIds) {
await deleteAlbum(await (db.albumById(sourceId, id)).getSingle()); await deleteAlbum(await (db.albumById(sourceId, id)).getSingle());
} }
@@ -534,7 +534,7 @@ class DownloadService extends _$DownloadService {
_port.asyncMap((dynamic data) async { _port.asyncMap((dynamic data) async {
final taskId = (data as List<dynamic>)[0] as String; final taskId = (data as List<dynamic>)[0] as String;
final status = DownloadTaskStatus(data[1] as int); final status = DownloadTaskStatus.fromInt(data[1] as int);
final progress = data[2] as int; final progress = data[2] as int;
var download = state.downloads.firstWhereOrNull( var download = state.downloads.firstWhereOrNull(
@@ -579,11 +579,11 @@ class DownloadService extends _$DownloadService {
@pragma('vm:entry-point') @pragma('vm:entry-point')
static void downloadCallback( static void downloadCallback(
String id, String id,
DownloadTaskStatus status, int status,
int progress, int progress,
) { ) {
IsolateNameServer.lookupPortByName('downloader_send_port')?.send( IsolateNameServer.lookupPortByName('downloader_send_port')?.send(
[id, status.value, progress], [id, status, progress],
); );
} }
} }

View File

@@ -12,7 +12,7 @@ part of 'download_service.dart';
T _$identity<T>(T value) => value; T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError( final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc /// @nodoc
mixin _$DownloadState { mixin _$DownloadState {
@@ -86,11 +86,11 @@ class _$DownloadStateCopyWithImpl<$Res, $Val extends DownloadState>
} }
/// @nodoc /// @nodoc
abstract class _$$_DownloadStateCopyWith<$Res> abstract class _$$DownloadStateImplCopyWith<$Res>
implements $DownloadStateCopyWith<$Res> { implements $DownloadStateCopyWith<$Res> {
factory _$$_DownloadStateCopyWith( factory _$$DownloadStateImplCopyWith(
_$_DownloadState value, $Res Function(_$_DownloadState) then) = _$DownloadStateImpl value, $Res Function(_$DownloadStateImpl) then) =
__$$_DownloadStateCopyWithImpl<$Res>; __$$DownloadStateImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call( $Res call(
@@ -102,11 +102,11 @@ abstract class _$$_DownloadStateCopyWith<$Res>
} }
/// @nodoc /// @nodoc
class __$$_DownloadStateCopyWithImpl<$Res> class __$$DownloadStateImplCopyWithImpl<$Res>
extends _$DownloadStateCopyWithImpl<$Res, _$_DownloadState> extends _$DownloadStateCopyWithImpl<$Res, _$DownloadStateImpl>
implements _$$_DownloadStateCopyWith<$Res> { implements _$$DownloadStateImplCopyWith<$Res> {
__$$_DownloadStateCopyWithImpl( __$$DownloadStateImplCopyWithImpl(
_$_DownloadState _value, $Res Function(_$_DownloadState) _then) _$DownloadStateImpl _value, $Res Function(_$DownloadStateImpl) _then)
: super(_value, _then); : super(_value, _then);
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@@ -118,7 +118,7 @@ class __$$_DownloadStateCopyWithImpl<$Res>
Object? listCancels = null, Object? listCancels = null,
Object? saveDir = null, Object? saveDir = null,
}) { }) {
return _then(_$_DownloadState( return _then(_$DownloadStateImpl(
downloads: null == downloads downloads: null == downloads
? _value.downloads ? _value.downloads
: downloads // ignore: cast_nullable_to_non_nullable : downloads // ignore: cast_nullable_to_non_nullable
@@ -145,8 +145,8 @@ class __$$_DownloadStateCopyWithImpl<$Res>
/// @nodoc /// @nodoc
class _$_DownloadState implements _DownloadState { class _$DownloadStateImpl implements _DownloadState {
const _$_DownloadState( const _$DownloadStateImpl(
{this.downloads = const IListConst([]), {this.downloads = const IListConst([]),
this.deletes = const IListConst([]), this.deletes = const IListConst([]),
this.listDownloads = const IListConst([]), this.listDownloads = const IListConst([]),
@@ -174,10 +174,10 @@ class _$_DownloadState implements _DownloadState {
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$_DownloadState && other is _$DownloadStateImpl &&
const DeepCollectionEquality().equals(other.downloads, downloads) && const DeepCollectionEquality().equals(other.downloads, downloads) &&
const DeepCollectionEquality().equals(other.deletes, deletes) && const DeepCollectionEquality().equals(other.deletes, deletes) &&
const DeepCollectionEquality() const DeepCollectionEquality()
@@ -199,8 +199,8 @@ class _$_DownloadState implements _DownloadState {
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$_DownloadStateCopyWith<_$_DownloadState> get copyWith => _$$DownloadStateImplCopyWith<_$DownloadStateImpl> get copyWith =>
__$$_DownloadStateCopyWithImpl<_$_DownloadState>(this, _$identity); __$$DownloadStateImplCopyWithImpl<_$DownloadStateImpl>(this, _$identity);
} }
abstract class _DownloadState implements DownloadState { abstract class _DownloadState implements DownloadState {
@@ -209,7 +209,7 @@ abstract class _DownloadState implements DownloadState {
final IList<SourceId> deletes, final IList<SourceId> deletes,
final IList<SourceId> listDownloads, final IList<SourceId> listDownloads,
final IList<SourceId> listCancels, final IList<SourceId> listCancels,
required final String saveDir}) = _$_DownloadState; required final String saveDir}) = _$DownloadStateImpl;
@override @override
IList<Download> get downloads; IList<Download> get downloads;
@@ -223,7 +223,7 @@ abstract class _DownloadState implements DownloadState {
String get saveDir; String get saveDir;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$_DownloadStateCopyWith<_$_DownloadState> get copyWith => _$$DownloadStateImplCopyWith<_$DownloadStateImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
@@ -319,10 +319,11 @@ class _$DownloadCopyWithImpl<$Res, $Val extends Download>
} }
/// @nodoc /// @nodoc
abstract class _$$_DownloadCopyWith<$Res> implements $DownloadCopyWith<$Res> { abstract class _$$DownloadImplCopyWith<$Res>
factory _$$_DownloadCopyWith( implements $DownloadCopyWith<$Res> {
_$_Download value, $Res Function(_$_Download) then) = factory _$$DownloadImplCopyWith(
__$$_DownloadCopyWithImpl<$Res>; _$DownloadImpl value, $Res Function(_$DownloadImpl) then) =
__$$DownloadImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call( $Res call(
@@ -337,11 +338,11 @@ abstract class _$$_DownloadCopyWith<$Res> implements $DownloadCopyWith<$Res> {
} }
/// @nodoc /// @nodoc
class __$$_DownloadCopyWithImpl<$Res> class __$$DownloadImplCopyWithImpl<$Res>
extends _$DownloadCopyWithImpl<$Res, _$_Download> extends _$DownloadCopyWithImpl<$Res, _$DownloadImpl>
implements _$$_DownloadCopyWith<$Res> { implements _$$DownloadImplCopyWith<$Res> {
__$$_DownloadCopyWithImpl( __$$DownloadImplCopyWithImpl(
_$_Download _value, $Res Function(_$_Download) _then) _$DownloadImpl _value, $Res Function(_$DownloadImpl) _then)
: super(_value, _then); : super(_value, _then);
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@@ -356,7 +357,7 @@ class __$$_DownloadCopyWithImpl<$Res>
Object? timeCreated = null, Object? timeCreated = null,
Object? allowCellular = null, Object? allowCellular = null,
}) { }) {
return _then(_$_Download( return _then(_$DownloadImpl(
taskId: null == taskId taskId: null == taskId
? _value.taskId ? _value.taskId
: taskId // ignore: cast_nullable_to_non_nullable : taskId // ignore: cast_nullable_to_non_nullable
@@ -395,8 +396,8 @@ class __$$_DownloadCopyWithImpl<$Res>
/// @nodoc /// @nodoc
class _$_Download extends _Download { class _$DownloadImpl extends _Download {
const _$_Download( const _$DownloadImpl(
{required this.taskId, {required this.taskId,
required this.status, required this.status,
required this.progress, required this.progress,
@@ -430,10 +431,10 @@ class _$_Download extends _Download {
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$_Download && other is _$DownloadImpl &&
(identical(other.taskId, taskId) || other.taskId == taskId) && (identical(other.taskId, taskId) || other.taskId == taskId) &&
(identical(other.status, status) || other.status == status) && (identical(other.status, status) || other.status == status) &&
(identical(other.progress, progress) || (identical(other.progress, progress) ||
@@ -456,8 +457,8 @@ class _$_Download extends _Download {
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$_DownloadCopyWith<_$_Download> get copyWith => _$$DownloadImplCopyWith<_$DownloadImpl> get copyWith =>
__$$_DownloadCopyWithImpl<_$_Download>(this, _$identity); __$$DownloadImplCopyWithImpl<_$DownloadImpl>(this, _$identity);
} }
abstract class _Download extends Download { abstract class _Download extends Download {
@@ -469,7 +470,7 @@ abstract class _Download extends Download {
required final String? filename, required final String? filename,
required final String savedDir, required final String savedDir,
required final int timeCreated, required final int timeCreated,
required final bool allowCellular}) = _$_Download; required final bool allowCellular}) = _$DownloadImpl;
const _Download._() : super._(); const _Download._() : super._();
@override @override
@@ -490,6 +491,6 @@ abstract class _Download extends Download {
bool get allowCellular; bool get allowCellular;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$_DownloadCopyWith<_$_Download> get copyWith => _$$DownloadImplCopyWith<_$DownloadImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }

View File

@@ -6,7 +6,7 @@ part of 'download_service.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$downloadServiceHash() => r'92e963b5c070f4d1edb0cd81899b16393c2b9a70'; String _$downloadServiceHash() => r'd2aeed2c026de4dc7fa26b2331244b49e7e9f003';
/// See also [DownloadService]. /// See also [DownloadService].
@ProviderFor(DownloadService) @ProviderFor(DownloadService)
@@ -22,4 +22,5 @@ final downloadServiceProvider =
); );
typedef _$DownloadService = Notifier<DownloadState>; typedef _$DownloadService = Notifier<DownloadState>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -46,13 +46,15 @@ class SettingsService extends _$SettingsService {
features: IList(), features: IList(),
username: subsonic.username.value, username: subsonic.username.value,
password: subsonic.password.value, password: subsonic.password.value,
useTokenAuth: true, useTokenAuth: subsonic.useTokenAuth.value,
isActive: true, isActive: true,
createdAt: DateTime.now(), createdAt: DateTime.now(),
), ),
ref.read(httpClientProvider), ref.read(httpClientProvider),
); );
await client.test();
final features = IList([ final features = IList([
if (await client.testFeature(SubsonicFeature.emptyQuerySearch)) if (await client.testFeature(SubsonicFeature.emptyQuerySearch))
SubsonicFeature.emptyQuerySearch, SubsonicFeature.emptyQuerySearch,
@@ -66,6 +68,10 @@ class SettingsService extends _$SettingsService {
} }
Future<void> updateSource(SubsonicSettings source) async { Future<void> updateSource(SubsonicSettings source) async {
final client = SubsonicClient(source, ref.read(httpClientProvider));
await client.test();
await _db.updateSource(source); await _db.updateSource(source);
await init(); await init();
} }

View File

@@ -6,7 +6,7 @@ part of 'settings_service.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$settingsServiceHash() => r'85f2bd5eedc3f791fe03a6707748bc95277c6aaf'; String _$settingsServiceHash() => r'b53814d7d06c5d0a7ac82f447ac510e59a9598f0';
/// See also [SettingsService]. /// See also [SettingsService].
@ProviderFor(SettingsService) @ProviderFor(SettingsService)
@@ -22,4 +22,5 @@ final settingsServiceProvider =
); );
typedef _$SettingsService = Notifier<Settings>; typedef _$SettingsService = Notifier<Settings>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -31,7 +31,7 @@ class SyncService extends _$SyncService {
final source = ref.read(musicSourceProvider); final source = ref.read(musicSourceProvider);
final db = ref.read(databaseProvider); final db = ref.read(databaseProvider);
final ids = <String>[]; final ids = <String>{};
await for (var artists in source.allArtists()) { await for (var artists in source.allArtists()) {
ids.addAll(artists.map((e) => e.id.value)); ids.addAll(artists.map((e) => e.id.value));
await db.saveArtists(artists); await db.saveArtists(artists);
@@ -44,7 +44,7 @@ class SyncService extends _$SyncService {
final source = ref.read(musicSourceProvider); final source = ref.read(musicSourceProvider);
final db = ref.read(databaseProvider); final db = ref.read(databaseProvider);
final ids = <String>[]; final ids = <String>{};
await for (var albums in source.allAlbums()) { await for (var albums in source.allAlbums()) {
ids.addAll(albums.map((e) => e.id.value)); ids.addAll(albums.map((e) => e.id.value));
await db.saveAlbums(albums); await db.saveAlbums(albums);
@@ -57,7 +57,7 @@ class SyncService extends _$SyncService {
final source = ref.read(musicSourceProvider); final source = ref.read(musicSourceProvider);
final db = ref.read(databaseProvider); final db = ref.read(databaseProvider);
final ids = <String>[]; final ids = <String>{};
await for (var playlists in source.allPlaylists()) { await for (var playlists in source.allPlaylists()) {
ids.addAll(playlists.map((e) => e.playist.id.value)); ids.addAll(playlists.map((e) => e.playist.id.value));
await db.savePlaylists(playlists); await db.savePlaylists(playlists);
@@ -70,7 +70,7 @@ class SyncService extends _$SyncService {
final source = ref.read(musicSourceProvider); final source = ref.read(musicSourceProvider);
final db = ref.read(databaseProvider); final db = ref.read(databaseProvider);
final ids = <String>[]; final ids = <String>{};
await for (var songs in source.allSongs()) { await for (var songs in source.allSongs()) {
ids.addAll(songs.map((e) => e.id.value)); ids.addAll(songs.map((e) => e.id.value));
await db.saveSongs(songs); await db.saveSongs(songs);

View File

@@ -6,7 +6,7 @@ part of 'sync_service.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$syncServiceHash() => r'2b8da374c3143bc56f17115440d57bc70468a17e'; String _$syncServiceHash() => r'58ebee4e6f055b64ee6789ae43d63c0e15c679e0';
/// See also [SyncService]. /// See also [SyncService].
@ProviderFor(SyncService) @ProviderFor(SyncService)
@@ -20,4 +20,5 @@ final syncServiceProvider = NotifierProvider<SyncService, DateTime>.internal(
); );
typedef _$SyncService = Notifier<DateTime>; typedef _$SyncService = Notifier<DateTime>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -1,6 +1,8 @@
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:rxdart/rxdart.dart';
import '../database/database.dart'; import '../database/database.dart';
import '../log.dart';
import '../state/settings.dart'; import '../state/settings.dart';
abstract class BaseMusicSource { abstract class BaseMusicSource {
@@ -40,25 +42,33 @@ class MusicSource implements BaseMusicSource {
@override @override
Stream<Iterable<AlbumsCompanion>> allAlbums() { Stream<Iterable<AlbumsCompanion>> allAlbums() {
_testOnline(); _testOnline();
return _source.allAlbums(); return _source
.allAlbums()
.doOnError((e, st) => log.severe('allAlbums', e, st));
} }
@override @override
Stream<Iterable<ArtistsCompanion>> allArtists() { Stream<Iterable<ArtistsCompanion>> allArtists() {
_testOnline(); _testOnline();
return _source.allArtists(); return _source
.allArtists()
.doOnError((e, st) => log.severe('allArtists', e, st));
} }
@override @override
Stream<Iterable<PlaylistWithSongsCompanion>> allPlaylists() { Stream<Iterable<PlaylistWithSongsCompanion>> allPlaylists() {
_testOnline(); _testOnline();
return _source.allPlaylists(); return _source
.allPlaylists()
.doOnError((e, st) => log.severe('allPlaylists', e, st));
} }
@override @override
Stream<Iterable<SongsCompanion>> allSongs() { Stream<Iterable<SongsCompanion>> allSongs() {
_testOnline(); _testOnline();
return _source.allSongs(); return _source
.allSongs()
.doOnError((e, st) => log.severe('allSongs', e, st));
} }
@override @override
@@ -82,10 +92,4 @@ class MusicSource implements BaseMusicSource {
@override @override
Uri streamUri(String songId) => _source.streamUri(songId); Uri streamUri(String songId) => _source.streamUri(songId);
@override
bool operator ==(other) => other is BaseMusicSource && (other.id == id);
@override
int get hashCode => id;
} }

View File

@@ -6,6 +6,7 @@ import 'package:crypto/crypto.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:xml/xml.dart'; import 'package:xml/xml.dart';
import '../../log.dart';
import '../../models/settings.dart'; import '../../models/settings.dart';
import 'xml.dart'; import 'xml.dart';
@@ -89,12 +90,16 @@ class SubsonicClient {
final subsonicResponse = final subsonicResponse =
SubsonicResponse(XmlDocument.parse(utf8.decode(res.bodyBytes))); SubsonicResponse(XmlDocument.parse(utf8.decode(res.bodyBytes)));
if (subsonicResponse.status == Status.failed) { if (subsonicResponse.status == Status.failed) {
throw SubsonicException(subsonicResponse.xml); final error = SubsonicException(subsonicResponse.xml);
log.severe('Subsonic error', error);
throw error;
} }
return subsonicResponse; return subsonicResponse;
} }
Future<void> test() => get('ping');
Future<bool> testFeature(SubsonicFeature feature) async { Future<bool> testFeature(SubsonicFeature feature) async {
switch (feature) { switch (feature) {
case SubsonicFeature.emptyQuerySearch: case SubsonicFeature.emptyQuerySearch:

View File

@@ -144,7 +144,7 @@ class SubsonicSource implements MusicSource {
return Uri.tryParse(res.xml return Uri.tryParse(res.xml
.getElement('artistInfo2') .getElement('artistInfo2')
?.getElement(thumbnail ? 'smallImageUrl' : 'largeImageUrl') ?.getElement(thumbnail ? 'smallImageUrl' : 'largeImageUrl')
?.text ?? ?.value ??
''); '');
} }

View File

@@ -226,4 +226,5 @@ final lastAudioStateServiceProvider =
); );
typedef _$LastAudioStateService = AsyncNotifier<void>; typedef _$LastAudioStateService = AsyncNotifier<void>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -94,4 +94,5 @@ final initProvider = FutureProvider<void>.internal(
); );
typedef InitRef = FutureProviderRef<void>; typedef InitRef = FutureProviderRef<void>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

File diff suppressed because it is too large Load Diff

View File

@@ -76,4 +76,5 @@ final offlineModeProvider = NotifierProvider<OfflineMode, bool>.internal(
); );
typedef _$OfflineMode = Notifier<bool>; typedef _$OfflineMode = Notifier<bool>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View File

@@ -87,7 +87,6 @@ ColorTheme _colorTheme(_ColorThemeRef ref, Palette palette) {
final colorScheme = ColorScheme.fromSeed( final colorScheme = ColorScheme.fromSeed(
brightness: Brightness.dark, brightness: Brightness.dark,
seedColor: background?.color ?? Colors.purple[800]!, seedColor: background?.color ?? Colors.purple[800]!,
background: background?.color,
primaryContainer: primary?.color, primaryContainer: primary?.color,
onPrimaryContainer: primary?.bodyTextColor, onPrimaryContainer: primary?.bodyTextColor,
secondaryContainer: secondary?.color, secondaryContainer: secondary?.color,
@@ -96,8 +95,8 @@ ColorTheme _colorTheme(_ColorThemeRef ref, Palette palette) {
surfaceTint: vibrant?.color, surfaceTint: vibrant?.color,
); );
final hsv = HSVColor.fromColor(colorScheme.background); final hsv = HSVColor.fromColor(colorScheme.surface);
final hsl = HSLColor.fromColor(colorScheme.background); final hsl = HSLColor.fromColor(colorScheme.surface);
return base.copyWith( return base.copyWith(
theme: ThemeData( theme: ThemeData(
@@ -106,7 +105,7 @@ ColorTheme _colorTheme(_ColorThemeRef ref, Palette palette) {
brightness: base.theme.brightness, brightness: base.theme.brightness,
cardTheme: base.theme.cardTheme, cardTheme: base.theme.cardTheme,
), ),
gradientHigh: colorScheme.background, gradientHigh: colorScheme.surface,
darkBackground: hsv.withValue(kDarkBackgroundValue).toColor(), darkBackground: hsv.withValue(kDarkBackgroundValue).toColor(),
darkerBackground: hsl.withLightness(kDarkerBackgroundLightness).toColor(), darkerBackground: hsl.withLightness(kDarkerBackgroundLightness).toColor(),
onDarkerBackground: onDarkerBackground:
@@ -128,13 +127,13 @@ ColorTheme baseTheme(BaseThemeRef ref) {
), ),
); );
final hsv = HSVColor.fromColor(theme.colorScheme.background); final hsv = HSVColor.fromColor(theme.colorScheme.surface);
final hsl = HSLColor.fromColor(theme.colorScheme.background); final hsl = HSLColor.fromColor(theme.colorScheme.surface);
return ColorTheme( return ColorTheme(
theme: theme, theme: theme,
gradientHigh: theme.colorScheme.background, gradientHigh: theme.colorScheme.surface,
gradientLow: HSLColor.fromColor(theme.colorScheme.background) gradientLow: HSLColor.fromColor(theme.colorScheme.surface)
.withLightness(0.06) .withLightness(0.06)
.toColor(), .toColor(),
darkBackground: hsv.withValue(kDarkBackgroundValue).toColor(), darkBackground: hsv.withValue(kDarkBackgroundValue).toColor(),

View File

@@ -6,7 +6,7 @@ part of 'theme.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$colorThemeHash() => r'f5cc23cb5e2af379c02ae4b9756df72f9f6da5e6'; String _$colorThemeHash() => r'37d4eb17395341800b67f4f257c2cc49bf3dc91b';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {
@@ -29,8 +29,6 @@ class _SystemHash {
} }
} }
typedef _ColorThemeRef = AutoDisposeProviderRef<ColorTheme>;
/// See also [_colorTheme]. /// See also [_colorTheme].
@ProviderFor(_colorTheme) @ProviderFor(_colorTheme)
const _colorThemeProvider = _ColorThemeFamily(); const _colorThemeProvider = _ColorThemeFamily();
@@ -77,10 +75,10 @@ class _ColorThemeFamily extends Family<ColorTheme> {
class _ColorThemeProvider extends AutoDisposeProvider<ColorTheme> { class _ColorThemeProvider extends AutoDisposeProvider<ColorTheme> {
/// See also [_colorTheme]. /// See also [_colorTheme].
_ColorThemeProvider( _ColorThemeProvider(
this.palette, Palette palette,
) : super.internal( ) : this._internal(
(ref) => _colorTheme( (ref) => _colorTheme(
ref, ref as _ColorThemeRef,
palette, palette,
), ),
from: _colorThemeProvider, from: _colorThemeProvider,
@@ -92,10 +90,44 @@ class _ColorThemeProvider extends AutoDisposeProvider<ColorTheme> {
dependencies: _ColorThemeFamily._dependencies, dependencies: _ColorThemeFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
_ColorThemeFamily._allTransitiveDependencies, _ColorThemeFamily._allTransitiveDependencies,
palette: palette,
); );
_ColorThemeProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.palette,
}) : super.internal();
final Palette palette; final Palette palette;
@override
Override overrideWith(
ColorTheme Function(_ColorThemeRef provider) create,
) {
return ProviderOverride(
origin: this,
override: _ColorThemeProvider._internal(
(ref) => create(ref as _ColorThemeRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
palette: palette,
),
);
}
@override
AutoDisposeProviderElement<ColorTheme> createElement() {
return _ColorThemeProviderElement(this);
}
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is _ColorThemeProvider && other.palette == palette; return other is _ColorThemeProvider && other.palette == palette;
@@ -110,7 +142,20 @@ class _ColorThemeProvider extends AutoDisposeProvider<ColorTheme> {
} }
} }
String _$baseThemeHash() => r'317a5ef77def208357a54b7938ef3d91666fce70'; mixin _ColorThemeRef on AutoDisposeProviderRef<ColorTheme> {
/// The parameter `palette` of this provider.
Palette get palette;
}
class _ColorThemeProviderElement extends AutoDisposeProviderElement<ColorTheme>
with _ColorThemeRef {
_ColorThemeProviderElement(super.provider);
@override
Palette get palette => (origin as _ColorThemeProvider).palette;
}
String _$baseThemeHash() => r'489ea7dcf66a57e6eda300c75d8af5fcaef85e8e';
/// See also [baseTheme]. /// See also [baseTheme].
@ProviderFor(baseTheme) @ProviderFor(baseTheme)
@@ -125,7 +170,6 @@ final baseThemeProvider = AutoDisposeProvider<ColorTheme>.internal(
typedef BaseThemeRef = AutoDisposeProviderRef<ColorTheme>; typedef BaseThemeRef = AutoDisposeProviderRef<ColorTheme>;
String _$albumArtPaletteHash() => r'8130b954ee3c67f53207593d4ed3dfbffb00c95d'; String _$albumArtPaletteHash() => r'8130b954ee3c67f53207593d4ed3dfbffb00c95d';
typedef AlbumArtPaletteRef = AutoDisposeFutureProviderRef<Palette>;
/// See also [albumArtPalette]. /// See also [albumArtPalette].
@ProviderFor(albumArtPalette) @ProviderFor(albumArtPalette)
@@ -173,10 +217,10 @@ class AlbumArtPaletteFamily extends Family<AsyncValue<Palette>> {
class AlbumArtPaletteProvider extends AutoDisposeFutureProvider<Palette> { class AlbumArtPaletteProvider extends AutoDisposeFutureProvider<Palette> {
/// See also [albumArtPalette]. /// See also [albumArtPalette].
AlbumArtPaletteProvider( AlbumArtPaletteProvider(
this.id, String id,
) : super.internal( ) : this._internal(
(ref) => albumArtPalette( (ref) => albumArtPalette(
ref, ref as AlbumArtPaletteRef,
id, id,
), ),
from: albumArtPaletteProvider, from: albumArtPaletteProvider,
@@ -188,10 +232,44 @@ class AlbumArtPaletteProvider extends AutoDisposeFutureProvider<Palette> {
dependencies: AlbumArtPaletteFamily._dependencies, dependencies: AlbumArtPaletteFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
AlbumArtPaletteFamily._allTransitiveDependencies, AlbumArtPaletteFamily._allTransitiveDependencies,
id: id,
); );
AlbumArtPaletteProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.id,
}) : super.internal();
final String id; final String id;
@override
Override overrideWith(
FutureOr<Palette> Function(AlbumArtPaletteRef provider) create,
) {
return ProviderOverride(
origin: this,
override: AlbumArtPaletteProvider._internal(
(ref) => create(ref as AlbumArtPaletteRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
id: id,
),
);
}
@override
AutoDisposeFutureProviderElement<Palette> createElement() {
return _AlbumArtPaletteProviderElement(this);
}
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is AlbumArtPaletteProvider && other.id == id; return other is AlbumArtPaletteProvider && other.id == id;
@@ -206,9 +284,21 @@ class AlbumArtPaletteProvider extends AutoDisposeFutureProvider<Palette> {
} }
} }
mixin AlbumArtPaletteRef on AutoDisposeFutureProviderRef<Palette> {
/// The parameter `id` of this provider.
String get id;
}
class _AlbumArtPaletteProviderElement
extends AutoDisposeFutureProviderElement<Palette> with AlbumArtPaletteRef {
_AlbumArtPaletteProviderElement(super.provider);
@override
String get id => (origin as AlbumArtPaletteProvider).id;
}
String _$playlistArtPaletteHash() => String _$playlistArtPaletteHash() =>
r'6bc015688f354ea8d91dde86e2a7191ef1ef6496'; r'6bc015688f354ea8d91dde86e2a7191ef1ef6496';
typedef PlaylistArtPaletteRef = AutoDisposeFutureProviderRef<Palette>;
/// See also [playlistArtPalette]. /// See also [playlistArtPalette].
@ProviderFor(playlistArtPalette) @ProviderFor(playlistArtPalette)
@@ -256,10 +346,10 @@ class PlaylistArtPaletteFamily extends Family<AsyncValue<Palette>> {
class PlaylistArtPaletteProvider extends AutoDisposeFutureProvider<Palette> { class PlaylistArtPaletteProvider extends AutoDisposeFutureProvider<Palette> {
/// See also [playlistArtPalette]. /// See also [playlistArtPalette].
PlaylistArtPaletteProvider( PlaylistArtPaletteProvider(
this.id, String id,
) : super.internal( ) : this._internal(
(ref) => playlistArtPalette( (ref) => playlistArtPalette(
ref, ref as PlaylistArtPaletteRef,
id, id,
), ),
from: playlistArtPaletteProvider, from: playlistArtPaletteProvider,
@@ -271,10 +361,44 @@ class PlaylistArtPaletteProvider extends AutoDisposeFutureProvider<Palette> {
dependencies: PlaylistArtPaletteFamily._dependencies, dependencies: PlaylistArtPaletteFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
PlaylistArtPaletteFamily._allTransitiveDependencies, PlaylistArtPaletteFamily._allTransitiveDependencies,
id: id,
); );
PlaylistArtPaletteProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.id,
}) : super.internal();
final String id; final String id;
@override
Override overrideWith(
FutureOr<Palette> Function(PlaylistArtPaletteRef provider) create,
) {
return ProviderOverride(
origin: this,
override: PlaylistArtPaletteProvider._internal(
(ref) => create(ref as PlaylistArtPaletteRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
id: id,
),
);
}
@override
AutoDisposeFutureProviderElement<Palette> createElement() {
return _PlaylistArtPaletteProviderElement(this);
}
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is PlaylistArtPaletteProvider && other.id == id; return other is PlaylistArtPaletteProvider && other.id == id;
@@ -289,6 +413,20 @@ class PlaylistArtPaletteProvider extends AutoDisposeFutureProvider<Palette> {
} }
} }
mixin PlaylistArtPaletteRef on AutoDisposeFutureProviderRef<Palette> {
/// The parameter `id` of this provider.
String get id;
}
class _PlaylistArtPaletteProviderElement
extends AutoDisposeFutureProviderElement<Palette>
with PlaylistArtPaletteRef {
_PlaylistArtPaletteProviderElement(super.provider);
@override
String get id => (origin as PlaylistArtPaletteProvider).id;
}
String _$mediaItemPaletteHash() => r'2f2744aa735c6056919197c283a367714d7e04e4'; String _$mediaItemPaletteHash() => r'2f2744aa735c6056919197c283a367714d7e04e4';
/// See also [mediaItemPalette]. /// See also [mediaItemPalette].
@@ -320,7 +458,6 @@ final mediaItemThemeProvider = AutoDisposeFutureProvider<ColorTheme>.internal(
typedef MediaItemThemeRef = AutoDisposeFutureProviderRef<ColorTheme>; typedef MediaItemThemeRef = AutoDisposeFutureProviderRef<ColorTheme>;
String _$albumArtThemeHash() => r'd3ee71b2df856f1763ec925e158ae2e0f613b9e0'; String _$albumArtThemeHash() => r'd3ee71b2df856f1763ec925e158ae2e0f613b9e0';
typedef AlbumArtThemeRef = AutoDisposeFutureProviderRef<ColorTheme>;
/// See also [albumArtTheme]. /// See also [albumArtTheme].
@ProviderFor(albumArtTheme) @ProviderFor(albumArtTheme)
@@ -368,10 +505,10 @@ class AlbumArtThemeFamily extends Family<AsyncValue<ColorTheme>> {
class AlbumArtThemeProvider extends AutoDisposeFutureProvider<ColorTheme> { class AlbumArtThemeProvider extends AutoDisposeFutureProvider<ColorTheme> {
/// See also [albumArtTheme]. /// See also [albumArtTheme].
AlbumArtThemeProvider( AlbumArtThemeProvider(
this.id, String id,
) : super.internal( ) : this._internal(
(ref) => albumArtTheme( (ref) => albumArtTheme(
ref, ref as AlbumArtThemeRef,
id, id,
), ),
from: albumArtThemeProvider, from: albumArtThemeProvider,
@@ -383,10 +520,44 @@ class AlbumArtThemeProvider extends AutoDisposeFutureProvider<ColorTheme> {
dependencies: AlbumArtThemeFamily._dependencies, dependencies: AlbumArtThemeFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
AlbumArtThemeFamily._allTransitiveDependencies, AlbumArtThemeFamily._allTransitiveDependencies,
id: id,
); );
AlbumArtThemeProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.id,
}) : super.internal();
final String id; final String id;
@override
Override overrideWith(
FutureOr<ColorTheme> Function(AlbumArtThemeRef provider) create,
) {
return ProviderOverride(
origin: this,
override: AlbumArtThemeProvider._internal(
(ref) => create(ref as AlbumArtThemeRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
id: id,
),
);
}
@override
AutoDisposeFutureProviderElement<ColorTheme> createElement() {
return _AlbumArtThemeProviderElement(this);
}
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is AlbumArtThemeProvider && other.id == id; return other is AlbumArtThemeProvider && other.id == id;
@@ -401,8 +572,20 @@ class AlbumArtThemeProvider extends AutoDisposeFutureProvider<ColorTheme> {
} }
} }
mixin AlbumArtThemeRef on AutoDisposeFutureProviderRef<ColorTheme> {
/// The parameter `id` of this provider.
String get id;
}
class _AlbumArtThemeProviderElement
extends AutoDisposeFutureProviderElement<ColorTheme> with AlbumArtThemeRef {
_AlbumArtThemeProviderElement(super.provider);
@override
String get id => (origin as AlbumArtThemeProvider).id;
}
String _$playlistArtThemeHash() => r'1629552e1f3aa2a1e7d223ac1e078893042e5e3b'; String _$playlistArtThemeHash() => r'1629552e1f3aa2a1e7d223ac1e078893042e5e3b';
typedef PlaylistArtThemeRef = AutoDisposeFutureProviderRef<ColorTheme>;
/// See also [playlistArtTheme]. /// See also [playlistArtTheme].
@ProviderFor(playlistArtTheme) @ProviderFor(playlistArtTheme)
@@ -450,10 +633,10 @@ class PlaylistArtThemeFamily extends Family<AsyncValue<ColorTheme>> {
class PlaylistArtThemeProvider extends AutoDisposeFutureProvider<ColorTheme> { class PlaylistArtThemeProvider extends AutoDisposeFutureProvider<ColorTheme> {
/// See also [playlistArtTheme]. /// See also [playlistArtTheme].
PlaylistArtThemeProvider( PlaylistArtThemeProvider(
this.id, String id,
) : super.internal( ) : this._internal(
(ref) => playlistArtTheme( (ref) => playlistArtTheme(
ref, ref as PlaylistArtThemeRef,
id, id,
), ),
from: playlistArtThemeProvider, from: playlistArtThemeProvider,
@@ -465,10 +648,44 @@ class PlaylistArtThemeProvider extends AutoDisposeFutureProvider<ColorTheme> {
dependencies: PlaylistArtThemeFamily._dependencies, dependencies: PlaylistArtThemeFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
PlaylistArtThemeFamily._allTransitiveDependencies, PlaylistArtThemeFamily._allTransitiveDependencies,
id: id,
); );
PlaylistArtThemeProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.id,
}) : super.internal();
final String id; final String id;
@override
Override overrideWith(
FutureOr<ColorTheme> Function(PlaylistArtThemeRef provider) create,
) {
return ProviderOverride(
origin: this,
override: PlaylistArtThemeProvider._internal(
(ref) => create(ref as PlaylistArtThemeRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
id: id,
),
);
}
@override
AutoDisposeFutureProviderElement<ColorTheme> createElement() {
return _PlaylistArtThemeProviderElement(this);
}
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is PlaylistArtThemeProvider && other.id == id; return other is PlaylistArtThemeProvider && other.id == id;
@@ -482,4 +699,19 @@ class PlaylistArtThemeProvider extends AutoDisposeFutureProvider<ColorTheme> {
return _SystemHash.finish(hash); return _SystemHash.finish(hash);
} }
} }
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
mixin PlaylistArtThemeRef on AutoDisposeFutureProviderRef<ColorTheme> {
/// The parameter `id` of this provider.
String get id;
}
class _PlaylistArtThemeProviderElement
extends AutoDisposeFutureProviderElement<ColorTheme>
with PlaylistArtThemeRef {
_PlaylistArtThemeProviderElement(super.provider);
@override
String get id => (origin as PlaylistArtThemeProvider).id;
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

File diff suppressed because it is too large Load Diff

View File

@@ -4,10 +4,10 @@ homepage: https://github.com/austinried/subtracks
repository: https://github.com/austinried/subtracks repository: https://github.com/austinried/subtracks
issue_tracker: https://github.com/austinried/subtracks/issues issue_tracker: https://github.com/austinried/subtracks/issues
publish_to: 'none' publish_to: 'none'
version: 2.0.0-alpha.1+10 version: 2.0.0-alpha.3+12
environment: environment:
sdk: '>=2.19.2 <3.0.0' sdk: '>=3.5.0 <4.0.0'
dependencies: dependencies:
flutter: flutter:
@@ -22,7 +22,7 @@ dependencies:
path: ^1.8.2 path: ^1.8.2
path_provider: ^2.0.12 path_provider: ^2.0.12
flutter_dotenv: ^5.0.2 # TODO: remove before release flutter_dotenv: ^5.0.2 # TODO: remove before release
collection: ^1.17.0 collection: ^1.17.1
intl: any intl: any
flutter_hooks: ^0.18.5+1 flutter_hooks: ^0.18.5+1
hooks_riverpod: ^2.3.2 hooks_riverpod: ^2.3.2
@@ -55,18 +55,17 @@ dependencies:
synchronized: ^3.1.0 synchronized: ^3.1.0
flutter_keyboard_visibility: ^5.4.0 flutter_keyboard_visibility: ^5.4.0
connectivity_plus: ^3.0.4 connectivity_plus: ^3.0.4
package_info_plus: ^3.1.1 package_info_plus: ^8.1.1
url_launcher: ^6.1.10 url_launcher: ^6.1.10
logging: ^1.1.1
share_plus: ^7.0.0
# https://github.com/dart-lang/intl/issues/522#issuecomment-1469961807 # https://github.com/dart-lang/intl/issues/522#issuecomment-1469961807
dependency_overrides: dependency_overrides:
intl: ^0.18.0 intl: ^0.18.0
dev_dependencies: dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0 flutter_lints: ^2.0.0
test: ^1.22.0
build_runner: build_runner:
riverpod_generator: ^2.1.4 riverpod_generator: ^2.1.4
freezed: ^2.3.2 freezed: ^2.3.2