diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index edac498..fdde745 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,10 +1,14 @@
-
+
+
+
+
+
+ android:name="io.flutter.embedding.android.NormalTheme"
+ android:resource="@style/NormalTheme"
+ />
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
\ No newline at end of file
diff --git a/android/app/src/main/ic_launcher-playstore.png b/android/app/src/main/ic_launcher-playstore.png
new file mode 100644
index 0000000..f3ae518
Binary files /dev/null and b/android/app/src/main/ic_launcher-playstore.png differ
diff --git a/android/app/src/main/res/drawable-anydpi/ic_stat_name.xml b/android/app/src/main/res/drawable-anydpi/ic_stat_name.xml
new file mode 100644
index 0000000..9d76126
--- /dev/null
+++ b/android/app/src/main/res/drawable-anydpi/ic_stat_name.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable-hdpi/ic_stat_name.png b/android/app/src/main/res/drawable-hdpi/ic_stat_name.png
new file mode 100644
index 0000000..fb2a3f4
Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/ic_stat_name.png differ
diff --git a/android/app/src/main/res/drawable-mdpi/ic_stat_name.png b/android/app/src/main/res/drawable-mdpi/ic_stat_name.png
new file mode 100644
index 0000000..a4abbef
Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/ic_stat_name.png differ
diff --git a/android/app/src/main/res/drawable-xhdpi/ic_stat_name.png b/android/app/src/main/res/drawable-xhdpi/ic_stat_name.png
new file mode 100644
index 0000000..19c9ddc
Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/ic_stat_name.png differ
diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_stat_name.png b/android/app/src/main/res/drawable-xxhdpi/ic_stat_name.png
new file mode 100644
index 0000000..f58aa1f
Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/ic_stat_name.png differ
diff --git a/android/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..ca3826a
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/ic_launcher_foreground.xml b/android/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..ffcb604
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..7353dbd
--- /dev/null
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..7353dbd
--- /dev/null
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index db77bb4..0000000
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..7bd6309
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..3698920
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..fea0421
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png
new file mode 100644
index 0000000..dac978b
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 17987b7..0000000
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..f1a7bbf
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..8885078
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..e4210b5
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/android/app/src/main/res/mipmap-mdpi/launcher_icon.png b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png
new file mode 100644
index 0000000..0e0a3dd
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index 09d4391..0000000
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..27446b5
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..56d116d
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b4491d
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png
new file mode 100644
index 0000000..98458eb
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index d5f1c8d..0000000
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..ec97d1a
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..3bfe3c8
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..f2815cc
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png
new file mode 100644
index 0000000..245a0f0
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 4d6372e..0000000
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..176143f
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..9f6628d
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..c257b68
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png
new file mode 100644
index 0000000..0539fd5
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png differ
diff --git a/android/app/src/main/res/values/ic_launcher_background.xml b/android/app/src/main/res/values/ic_launcher_background.xml
new file mode 100644
index 0000000..cad15c8
--- /dev/null
+++ b/android/app/src/main/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #BD7F44
+
\ No newline at end of file
diff --git a/assets/icon.png b/assets/icon.png
new file mode 100644
index 0000000..ada9129
Binary files /dev/null and b/assets/icon.png differ
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 884d190..33a5f5c 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -540,7 +540,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
@@ -597,7 +597,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
index dc9ada4..aefff76 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
index 7353c41..ea0a97a 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
index 797d452..1a60071 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
index 6ed2d93..26f6e91 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
index 4cd7b00..eac57e9 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
index fe73094..8b47f53 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
index 321773c..e90b6ef 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
index 797d452..1a60071 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
index 502f463..530b01c 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
index 0ec3034..ae65a03 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png
new file mode 100644
index 0000000..971149c
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png
new file mode 100644
index 0000000..1d2bcf7
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png
new file mode 100644
index 0000000..dd27983
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png
new file mode 100644
index 0000000..0813fb9
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
index 0ec3034..ae65a03 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
index e9f5fea..16ff1d1 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png
new file mode 100644
index 0000000..e2a75b4
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png
new file mode 100644
index 0000000..a3b4614
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
index 84ac32a..125ddee 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
index 8953cba..1e6583a 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
index 0467bf1..6ecee5a 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ
diff --git a/lib/providers/audio_player.dart b/lib/providers/audio_player.dart
index 8356432..553dee8 100644
--- a/lib/providers/audio_player.dart
+++ b/lib/providers/audio_player.dart
@@ -1,19 +1,16 @@
import 'dart:async';
-import 'dart:convert';
import 'dart:math';
-import 'package:get/get.dart';
+import 'package:drift/drift.dart';
+import 'package:get/get.dart' hide Value;
import 'package:media_kit/media_kit.dart' hide Track;
+import 'package:rhythm_box/providers/database.dart';
import 'package:rhythm_box/services/audio_player/state.dart';
-import 'package:rhythm_box/services/local_track.dart';
-import 'package:rhythm_box/services/server/sourced_track.dart';
+import 'package:rhythm_box/services/database/database.dart';
import 'package:spotify/spotify.dart' hide Playlist;
import 'package:rhythm_box/services/audio_player/audio_player.dart';
-import 'package:shared_preferences/shared_preferences.dart';
class AudioPlayerProvider extends GetxController {
- late final SharedPreferences _prefs;
-
RxBool isPlaying = false.obs;
Rx state = Rx(AudioPlayerState(
@@ -28,41 +25,39 @@ class AudioPlayerProvider extends GetxController {
@override
void onInit() {
- SharedPreferences.getInstance().then((ins) async {
- _prefs = ins;
- final res = await _readSavedState();
- if (res != null) {
- state.value = res;
- } else {
- state.value = AudioPlayerState(
- loopMode: audioPlayer.loopMode,
- playing: audioPlayer.isPlaying,
- playlist: audioPlayer.playlist,
- shuffled: audioPlayer.isShuffled,
- collections: [],
- );
- }
- });
-
_subscriptions = [
audioPlayer.playingStream.listen((playing) async {
state.value = state.value.copyWith(playing: playing);
- await _updateSavedState();
+ await _updatePlayerState(
+ AudioPlayerStateTableCompanion(
+ playing: Value(playing),
+ ),
+ );
}),
audioPlayer.loopModeStream.listen((loopMode) async {
state.value = state.value.copyWith(loopMode: loopMode);
- await _updateSavedState();
+ await _updatePlayerState(
+ AudioPlayerStateTableCompanion(
+ loopMode: Value(loopMode),
+ ),
+ );
}),
audioPlayer.shuffledStream.listen((shuffled) async {
state.value = state.value.copyWith(shuffled: shuffled);
- await _updateSavedState();
+ await _updatePlayerState(
+ AudioPlayerStateTableCompanion(
+ shuffled: Value(shuffled),
+ ),
+ );
}),
audioPlayer.playlistStream.listen((playlist) async {
state.value = state.value.copyWith(playlist: playlist);
- await _updateSavedState();
+ await _updatePlaylist(playlist);
}),
];
+ _readSavedState();
+
audioPlayer.playingStream.listen((playing) {
isPlaying.value = playing;
});
@@ -80,16 +75,124 @@ class AudioPlayerProvider extends GetxController {
super.dispose();
}
- Future _readSavedState() async {
- final data = _prefs.getString('player_state');
- if (data == null) return null;
+ Future _readSavedState() async {
+ final database = Get.find().database;
- return AudioPlayerState.fromJson(jsonDecode(data));
+ var playerState =
+ await database.select(database.audioPlayerStateTable).getSingleOrNull();
+
+ if (playerState == null) {
+ await database.into(database.audioPlayerStateTable).insert(
+ AudioPlayerStateTableCompanion.insert(
+ playing: audioPlayer.isPlaying,
+ loopMode: audioPlayer.loopMode,
+ shuffled: audioPlayer.isShuffled,
+ collections: [],
+ id: const Value(0),
+ ),
+ );
+
+ playerState =
+ await database.select(database.audioPlayerStateTable).getSingle();
+ } else {
+ await audioPlayer.setLoopMode(playerState.loopMode);
+ await audioPlayer.setShuffle(playerState.shuffled);
+ }
+
+ var playlist =
+ await database.select(database.playlistTable).getSingleOrNull();
+ var medias = await database.select(database.playlistMediaTable).get();
+
+ if (playlist == null) {
+ await database.into(database.playlistTable).insert(
+ PlaylistTableCompanion.insert(
+ audioPlayerStateId: 0,
+ index: audioPlayer.playlist.index,
+ id: const Value(0),
+ ),
+ );
+
+ playlist = await database.select(database.playlistTable).getSingle();
+ }
+
+ if (medias.isEmpty && audioPlayer.playlist.medias.isNotEmpty) {
+ await database.batch((batch) {
+ batch.insertAll(
+ database.playlistMediaTable,
+ [
+ for (final media in audioPlayer.playlist.medias)
+ PlaylistMediaTableCompanion.insert(
+ playlistId: playlist!.id,
+ uri: media.uri,
+ extras: Value(media.extras),
+ httpHeaders: Value(media.httpHeaders),
+ ),
+ ],
+ );
+ });
+ } else if (medias.isNotEmpty) {
+ await audioPlayer.openPlaylist(
+ medias
+ .map(
+ (media) => RhythmMedia.fromMedia(
+ Media(
+ media.uri,
+ extras: media.extras,
+ httpHeaders: media.httpHeaders,
+ ),
+ ),
+ )
+ .toList(),
+ initialIndex: playlist.index,
+ autoPlay: false,
+ );
+ }
+
+ if (playerState.collections.isNotEmpty) {
+ state.value = state.value.copyWith(
+ collections: playerState.collections,
+ );
+ }
}
- Future _updateSavedState() async {
- final out = jsonEncode(state.value.toJson());
- await _prefs.setString('player_state', out);
+ Future _updatePlayerState(
+ AudioPlayerStateTableCompanion companion,
+ ) async {
+ final database = Get.find().database;
+
+ await (database.update(database.audioPlayerStateTable)
+ ..where((tb) => tb.id.equals(0)))
+ .write(companion);
+ }
+
+ Future _updatePlaylist(
+ Playlist playlist,
+ ) async {
+ final database = Get.find().database;
+
+ await database.batch((batch) {
+ batch.update(
+ database.playlistTable,
+ PlaylistTableCompanion(index: Value(playlist.index)),
+ where: (tb) => tb.id.equals(0),
+ );
+
+ batch.deleteAll(database.playlistMediaTable);
+
+ if (playlist.medias.isEmpty) return;
+ batch.insertAll(
+ database.playlistMediaTable,
+ [
+ for (final media in playlist.medias)
+ PlaylistMediaTableCompanion.insert(
+ playlistId: 0,
+ uri: media.uri,
+ extras: Value(media.extras),
+ httpHeaders: Value(media.httpHeaders),
+ ),
+ ],
+ );
+ });
}
Future addCollections(List collectionIds) async {
@@ -98,7 +201,11 @@ class AudioPlayerProvider extends GetxController {
...collectionIds,
]);
- await _updateSavedState();
+ await _updatePlayerState(
+ AudioPlayerStateTableCompanion(
+ collections: Value(state.value.collections),
+ ),
+ );
}
Future addCollection(String collectionId) async {
@@ -112,7 +219,11 @@ class AudioPlayerProvider extends GetxController {
.toList(),
);
- await _updateSavedState();
+ await _updatePlayerState(
+ AudioPlayerStateTableCompanion(
+ collections: Value(state.value.collections),
+ ),
+ );
}
Future removeCollection(String collectionId) async {
diff --git a/lib/providers/audio_player_stream.dart b/lib/providers/audio_player_stream.dart
index 0fe9ac5..cb7eb7d 100644
--- a/lib/providers/audio_player_stream.dart
+++ b/lib/providers/audio_player_stream.dart
@@ -21,9 +21,16 @@ class AudioPlayerStreamProvider extends GetxController {
List? _subscriptions;
AudioPlayerStreamProvider() {
- AudioServices.create().then(
- (value) => notificationService = value,
- );
+ _initNotificationService();
+ }
+
+ Future _initNotificationService() async {
+ try {
+ final res = await AudioServices.create();
+ notificationService = res;
+ } catch (err) {
+ log('[AudioService] Unable to init audio service: $err');
+ }
}
@override
@@ -50,7 +57,7 @@ class AudioPlayerStreamProvider extends GetxController {
}
Future updatePalette() async {
- if (!Get.find().albumColorSync) {
+ if (!Get.find().state.value.albumColorSync) {
if (palette.value != null) {
palette.value = null;
}
diff --git a/lib/screens/player/view.dart b/lib/screens/player/view.dart
index dd109c0..bcfd40c 100644
--- a/lib/screens/player/view.dart
+++ b/lib/screens/player/view.dart
@@ -155,7 +155,10 @@ class _PlayerScreenState extends State {
),
child: Slider(
value: _draggingValue ??
- _durationCurrent.inMilliseconds.toDouble(),
+ (_durationCurrent.inMilliseconds <=
+ _durationTotal.inMilliseconds
+ ? _durationCurrent.inMilliseconds.toDouble()
+ : 0),
min: 0,
max: _durationTotal.inMilliseconds.toDouble(),
onChanged: (value) {
diff --git a/lib/services/audio_services/audio_services.dart b/lib/services/audio_services/audio_services.dart
index 0e43e84..e49019e 100755
--- a/lib/services/audio_services/audio_services.dart
+++ b/lib/services/audio_services/audio_services.dart
@@ -27,7 +27,7 @@ class AudioServices with WidgetsBindingObserver {
: 'dev.solsynth.rhythmBox',
androidNotificationChannelName: 'RhythmBox',
androidNotificationOngoing: false,
- androidNotificationIcon: 'drawable/ic_launcher_monochrome',
+ androidNotificationIcon: 'drawable/ic_stat_name',
androidStopForegroundOnPause: false,
androidNotificationChannelDescription: 'RhythmBox Music',
),
diff --git a/lib/services/database/database.dart b/lib/services/database/database.dart
index dce8791..fc2fffc 100755
--- a/lib/services/database/database.dart
+++ b/lib/services/database/database.dart
@@ -5,6 +5,7 @@ import 'dart:io';
import 'package:drift/drift.dart';
import 'package:encrypt/encrypt.dart';
+import 'package:media_kit/media_kit.dart' hide Track;
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:rhythm_box/services/color.dart';
@@ -27,6 +28,7 @@ part 'tables/skip_segment.dart';
part 'tables/source_match.dart';
part 'tables/history.dart';
part 'tables/lyrics.dart';
+part 'tables/audio_player_state.dart';
part 'typeconverters/color.dart';
part 'typeconverters/locale.dart';
@@ -44,6 +46,9 @@ part 'typeconverters/subtitle.dart';
SourceMatchTable,
HistoryTable,
LyricsTable,
+ AudioPlayerStateTable,
+ PlaylistTable,
+ PlaylistMediaTable,
],
)
class AppDatabase extends _$AppDatabase {
diff --git a/lib/services/database/database.g.dart b/lib/services/database/database.g.dart
index ea94029..a61f9ac 100644
--- a/lib/services/database/database.g.dart
+++ b/lib/services/database/database.g.dart
@@ -2951,6 +2951,879 @@ class LyricsTableCompanion extends UpdateCompanion {
}
}
+class $AudioPlayerStateTableTable extends AudioPlayerStateTable
+ with TableInfo<$AudioPlayerStateTableTable, AudioPlayerStateTableData> {
+ @override
+ final GeneratedDatabase attachedDatabase;
+ final String? _alias;
+ $AudioPlayerStateTableTable(this.attachedDatabase, [this._alias]);
+ static const VerificationMeta _idMeta = const VerificationMeta('id');
+ @override
+ late final GeneratedColumn id = GeneratedColumn(
+ 'id', aliasedName, false,
+ hasAutoIncrement: true,
+ type: DriftSqlType.int,
+ requiredDuringInsert: false,
+ defaultConstraints:
+ GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
+ static const VerificationMeta _playingMeta =
+ const VerificationMeta('playing');
+ @override
+ late final GeneratedColumn playing = GeneratedColumn(
+ 'playing', aliasedName, false,
+ type: DriftSqlType.bool,
+ requiredDuringInsert: true,
+ defaultConstraints:
+ GeneratedColumn.constraintIsAlways('CHECK ("playing" IN (0, 1))'));
+ static const VerificationMeta _loopModeMeta =
+ const VerificationMeta('loopMode');
+ @override
+ late final GeneratedColumnWithTypeConverter loopMode =
+ GeneratedColumn('loop_mode', aliasedName, false,
+ type: DriftSqlType.string, requiredDuringInsert: true)
+ .withConverter(
+ $AudioPlayerStateTableTable.$converterloopMode);
+ static const VerificationMeta _shuffledMeta =
+ const VerificationMeta('shuffled');
+ @override
+ late final GeneratedColumn shuffled = GeneratedColumn(
+ 'shuffled', aliasedName, false,
+ type: DriftSqlType.bool,
+ requiredDuringInsert: true,
+ defaultConstraints:
+ GeneratedColumn.constraintIsAlways('CHECK ("shuffled" IN (0, 1))'));
+ static const VerificationMeta _collectionsMeta =
+ const VerificationMeta('collections');
+ @override
+ late final GeneratedColumnWithTypeConverter, String>
+ collections = GeneratedColumn('collections', aliasedName, false,
+ type: DriftSqlType.string, requiredDuringInsert: true)
+ .withConverter>(
+ $AudioPlayerStateTableTable.$convertercollections);
+ @override
+ List get $columns =>
+ [id, playing, loopMode, shuffled, collections];
+ @override
+ String get aliasedName => _alias ?? actualTableName;
+ @override
+ String get actualTableName => $name;
+ static const String $name = 'audio_player_state_table';
+ @override
+ VerificationContext validateIntegrity(
+ Insertable instance,
+ {bool isInserting = false}) {
+ final context = VerificationContext();
+ final data = instance.toColumns(true);
+ if (data.containsKey('id')) {
+ context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
+ }
+ if (data.containsKey('playing')) {
+ context.handle(_playingMeta,
+ playing.isAcceptableOrUnknown(data['playing']!, _playingMeta));
+ } else if (isInserting) {
+ context.missing(_playingMeta);
+ }
+ context.handle(_loopModeMeta, const VerificationResult.success());
+ if (data.containsKey('shuffled')) {
+ context.handle(_shuffledMeta,
+ shuffled.isAcceptableOrUnknown(data['shuffled']!, _shuffledMeta));
+ } else if (isInserting) {
+ context.missing(_shuffledMeta);
+ }
+ context.handle(_collectionsMeta, const VerificationResult.success());
+ return context;
+ }
+
+ @override
+ Set get $primaryKey => {id};
+ @override
+ AudioPlayerStateTableData map(Map data,
+ {String? tablePrefix}) {
+ final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
+ return AudioPlayerStateTableData(
+ id: attachedDatabase.typeMapping
+ .read(DriftSqlType.int, data['${effectivePrefix}id'])!,
+ playing: attachedDatabase.typeMapping
+ .read(DriftSqlType.bool, data['${effectivePrefix}playing'])!,
+ loopMode: $AudioPlayerStateTableTable.$converterloopMode.fromSql(
+ attachedDatabase.typeMapping
+ .read(DriftSqlType.string, data['${effectivePrefix}loop_mode'])!),
+ shuffled: attachedDatabase.typeMapping
+ .read(DriftSqlType.bool, data['${effectivePrefix}shuffled'])!,
+ collections: $AudioPlayerStateTableTable.$convertercollections.fromSql(
+ attachedDatabase.typeMapping.read(
+ DriftSqlType.string, data['${effectivePrefix}collections'])!),
+ );
+ }
+
+ @override
+ $AudioPlayerStateTableTable createAlias(String alias) {
+ return $AudioPlayerStateTableTable(attachedDatabase, alias);
+ }
+
+ static JsonTypeConverter2 $converterloopMode =
+ const EnumNameConverter(PlaylistMode.values);
+ static TypeConverter, String> $convertercollections =
+ const StringListConverter();
+}
+
+class AudioPlayerStateTableData extends DataClass
+ implements Insertable {
+ final int id;
+ final bool playing;
+ final PlaylistMode loopMode;
+ final bool shuffled;
+ final List collections;
+ const AudioPlayerStateTableData(
+ {required this.id,
+ required this.playing,
+ required this.loopMode,
+ required this.shuffled,
+ required this.collections});
+ @override
+ Map toColumns(bool nullToAbsent) {
+ final map = {};
+ map['id'] = Variable(id);
+ map['playing'] = Variable(playing);
+ {
+ map['loop_mode'] = Variable(
+ $AudioPlayerStateTableTable.$converterloopMode.toSql(loopMode));
+ }
+ map['shuffled'] = Variable(shuffled);
+ {
+ map['collections'] = Variable(
+ $AudioPlayerStateTableTable.$convertercollections.toSql(collections));
+ }
+ return map;
+ }
+
+ AudioPlayerStateTableCompanion toCompanion(bool nullToAbsent) {
+ return AudioPlayerStateTableCompanion(
+ id: Value(id),
+ playing: Value(playing),
+ loopMode: Value(loopMode),
+ shuffled: Value(shuffled),
+ collections: Value(collections),
+ );
+ }
+
+ factory AudioPlayerStateTableData.fromJson(Map json,
+ {ValueSerializer? serializer}) {
+ serializer ??= driftRuntimeOptions.defaultSerializer;
+ return AudioPlayerStateTableData(
+ id: serializer.fromJson(json['id']),
+ playing: serializer.fromJson(json['playing']),
+ loopMode: $AudioPlayerStateTableTable.$converterloopMode
+ .fromJson(serializer.fromJson(json['loopMode'])),
+ shuffled: serializer.fromJson(json['shuffled']),
+ collections: serializer.fromJson>(json['collections']),
+ );
+ }
+ @override
+ Map toJson({ValueSerializer? serializer}) {
+ serializer ??= driftRuntimeOptions.defaultSerializer;
+ return {
+ 'id': serializer.toJson(id),
+ 'playing': serializer.toJson(playing),
+ 'loopMode': serializer.toJson(
+ $AudioPlayerStateTableTable.$converterloopMode.toJson(loopMode)),
+ 'shuffled': serializer.toJson(shuffled),
+ 'collections': serializer.toJson>(collections),
+ };
+ }
+
+ AudioPlayerStateTableData copyWith(
+ {int? id,
+ bool? playing,
+ PlaylistMode? loopMode,
+ bool? shuffled,
+ List? collections}) =>
+ AudioPlayerStateTableData(
+ id: id ?? this.id,
+ playing: playing ?? this.playing,
+ loopMode: loopMode ?? this.loopMode,
+ shuffled: shuffled ?? this.shuffled,
+ collections: collections ?? this.collections,
+ );
+ AudioPlayerStateTableData copyWithCompanion(
+ AudioPlayerStateTableCompanion data) {
+ return AudioPlayerStateTableData(
+ id: data.id.present ? data.id.value : this.id,
+ playing: data.playing.present ? data.playing.value : this.playing,
+ loopMode: data.loopMode.present ? data.loopMode.value : this.loopMode,
+ shuffled: data.shuffled.present ? data.shuffled.value : this.shuffled,
+ collections:
+ data.collections.present ? data.collections.value : this.collections,
+ );
+ }
+
+ @override
+ String toString() {
+ return (StringBuffer('AudioPlayerStateTableData(')
+ ..write('id: $id, ')
+ ..write('playing: $playing, ')
+ ..write('loopMode: $loopMode, ')
+ ..write('shuffled: $shuffled, ')
+ ..write('collections: $collections')
+ ..write(')'))
+ .toString();
+ }
+
+ @override
+ int get hashCode => Object.hash(id, playing, loopMode, shuffled, collections);
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ (other is AudioPlayerStateTableData &&
+ other.id == this.id &&
+ other.playing == this.playing &&
+ other.loopMode == this.loopMode &&
+ other.shuffled == this.shuffled &&
+ other.collections == this.collections);
+}
+
+class AudioPlayerStateTableCompanion
+ extends UpdateCompanion {
+ final Value id;
+ final Value playing;
+ final Value loopMode;
+ final Value shuffled;
+ final Value> collections;
+ const AudioPlayerStateTableCompanion({
+ this.id = const Value.absent(),
+ this.playing = const Value.absent(),
+ this.loopMode = const Value.absent(),
+ this.shuffled = const Value.absent(),
+ this.collections = const Value.absent(),
+ });
+ AudioPlayerStateTableCompanion.insert({
+ this.id = const Value.absent(),
+ required bool playing,
+ required PlaylistMode loopMode,
+ required bool shuffled,
+ required List collections,
+ }) : playing = Value(playing),
+ loopMode = Value(loopMode),
+ shuffled = Value(shuffled),
+ collections = Value(collections);
+ static Insertable custom({
+ Expression? id,
+ Expression? playing,
+ Expression? loopMode,
+ Expression? shuffled,
+ Expression? collections,
+ }) {
+ return RawValuesInsertable({
+ if (id != null) 'id': id,
+ if (playing != null) 'playing': playing,
+ if (loopMode != null) 'loop_mode': loopMode,
+ if (shuffled != null) 'shuffled': shuffled,
+ if (collections != null) 'collections': collections,
+ });
+ }
+
+ AudioPlayerStateTableCompanion copyWith(
+ {Value? id,
+ Value? playing,
+ Value? loopMode,
+ Value? shuffled,
+ Value>? collections}) {
+ return AudioPlayerStateTableCompanion(
+ id: id ?? this.id,
+ playing: playing ?? this.playing,
+ loopMode: loopMode ?? this.loopMode,
+ shuffled: shuffled ?? this.shuffled,
+ collections: collections ?? this.collections,
+ );
+ }
+
+ @override
+ Map toColumns(bool nullToAbsent) {
+ final map = {};
+ if (id.present) {
+ map['id'] = Variable(id.value);
+ }
+ if (playing.present) {
+ map['playing'] = Variable(playing.value);
+ }
+ if (loopMode.present) {
+ map['loop_mode'] = Variable(
+ $AudioPlayerStateTableTable.$converterloopMode.toSql(loopMode.value));
+ }
+ if (shuffled.present) {
+ map['shuffled'] = Variable(shuffled.value);
+ }
+ if (collections.present) {
+ map['collections'] = Variable($AudioPlayerStateTableTable
+ .$convertercollections
+ .toSql(collections.value));
+ }
+ return map;
+ }
+
+ @override
+ String toString() {
+ return (StringBuffer('AudioPlayerStateTableCompanion(')
+ ..write('id: $id, ')
+ ..write('playing: $playing, ')
+ ..write('loopMode: $loopMode, ')
+ ..write('shuffled: $shuffled, ')
+ ..write('collections: $collections')
+ ..write(')'))
+ .toString();
+ }
+}
+
+class $PlaylistTableTable extends PlaylistTable
+ with TableInfo<$PlaylistTableTable, PlaylistTableData> {
+ @override
+ final GeneratedDatabase attachedDatabase;
+ final String? _alias;
+ $PlaylistTableTable(this.attachedDatabase, [this._alias]);
+ static const VerificationMeta _idMeta = const VerificationMeta('id');
+ @override
+ late final GeneratedColumn id = GeneratedColumn(
+ 'id', aliasedName, false,
+ hasAutoIncrement: true,
+ type: DriftSqlType.int,
+ requiredDuringInsert: false,
+ defaultConstraints:
+ GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
+ static const VerificationMeta _audioPlayerStateIdMeta =
+ const VerificationMeta('audioPlayerStateId');
+ @override
+ late final GeneratedColumn audioPlayerStateId = GeneratedColumn(
+ 'audio_player_state_id', aliasedName, false,
+ type: DriftSqlType.int,
+ requiredDuringInsert: true,
+ defaultConstraints: GeneratedColumn.constraintIsAlways(
+ 'REFERENCES audio_player_state_table (id)'));
+ static const VerificationMeta _indexMeta = const VerificationMeta('index');
+ @override
+ late final GeneratedColumn index = GeneratedColumn(
+ 'index', aliasedName, false,
+ type: DriftSqlType.int, requiredDuringInsert: true);
+ @override
+ List get $columns => [id, audioPlayerStateId, index];
+ @override
+ String get aliasedName => _alias ?? actualTableName;
+ @override
+ String get actualTableName => $name;
+ static const String $name = 'playlist_table';
+ @override
+ VerificationContext validateIntegrity(Insertable instance,
+ {bool isInserting = false}) {
+ final context = VerificationContext();
+ final data = instance.toColumns(true);
+ if (data.containsKey('id')) {
+ context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
+ }
+ if (data.containsKey('audio_player_state_id')) {
+ context.handle(
+ _audioPlayerStateIdMeta,
+ audioPlayerStateId.isAcceptableOrUnknown(
+ data['audio_player_state_id']!, _audioPlayerStateIdMeta));
+ } else if (isInserting) {
+ context.missing(_audioPlayerStateIdMeta);
+ }
+ if (data.containsKey('index')) {
+ context.handle(
+ _indexMeta, index.isAcceptableOrUnknown(data['index']!, _indexMeta));
+ } else if (isInserting) {
+ context.missing(_indexMeta);
+ }
+ return context;
+ }
+
+ @override
+ Set get $primaryKey => {id};
+ @override
+ PlaylistTableData map(Map data, {String? tablePrefix}) {
+ final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
+ return PlaylistTableData(
+ id: attachedDatabase.typeMapping
+ .read(DriftSqlType.int, data['${effectivePrefix}id'])!,
+ audioPlayerStateId: attachedDatabase.typeMapping.read(
+ DriftSqlType.int, data['${effectivePrefix}audio_player_state_id'])!,
+ index: attachedDatabase.typeMapping
+ .read(DriftSqlType.int, data['${effectivePrefix}index'])!,
+ );
+ }
+
+ @override
+ $PlaylistTableTable createAlias(String alias) {
+ return $PlaylistTableTable(attachedDatabase, alias);
+ }
+}
+
+class PlaylistTableData extends DataClass
+ implements Insertable {
+ final int id;
+ final int audioPlayerStateId;
+ final int index;
+ const PlaylistTableData(
+ {required this.id,
+ required this.audioPlayerStateId,
+ required this.index});
+ @override
+ Map toColumns(bool nullToAbsent) {
+ final map = {};
+ map['id'] = Variable(id);
+ map['audio_player_state_id'] = Variable(audioPlayerStateId);
+ map['index'] = Variable(index);
+ return map;
+ }
+
+ PlaylistTableCompanion toCompanion(bool nullToAbsent) {
+ return PlaylistTableCompanion(
+ id: Value(id),
+ audioPlayerStateId: Value(audioPlayerStateId),
+ index: Value(index),
+ );
+ }
+
+ factory PlaylistTableData.fromJson(Map json,
+ {ValueSerializer? serializer}) {
+ serializer ??= driftRuntimeOptions.defaultSerializer;
+ return PlaylistTableData(
+ id: serializer.fromJson(json['id']),
+ audioPlayerStateId: serializer.fromJson(json['audioPlayerStateId']),
+ index: serializer.fromJson(json['index']),
+ );
+ }
+ @override
+ Map toJson({ValueSerializer? serializer}) {
+ serializer ??= driftRuntimeOptions.defaultSerializer;
+ return {
+ 'id': serializer.toJson(id),
+ 'audioPlayerStateId': serializer.toJson(audioPlayerStateId),
+ 'index': serializer.toJson(index),
+ };
+ }
+
+ PlaylistTableData copyWith({int? id, int? audioPlayerStateId, int? index}) =>
+ PlaylistTableData(
+ id: id ?? this.id,
+ audioPlayerStateId: audioPlayerStateId ?? this.audioPlayerStateId,
+ index: index ?? this.index,
+ );
+ PlaylistTableData copyWithCompanion(PlaylistTableCompanion data) {
+ return PlaylistTableData(
+ id: data.id.present ? data.id.value : this.id,
+ audioPlayerStateId: data.audioPlayerStateId.present
+ ? data.audioPlayerStateId.value
+ : this.audioPlayerStateId,
+ index: data.index.present ? data.index.value : this.index,
+ );
+ }
+
+ @override
+ String toString() {
+ return (StringBuffer('PlaylistTableData(')
+ ..write('id: $id, ')
+ ..write('audioPlayerStateId: $audioPlayerStateId, ')
+ ..write('index: $index')
+ ..write(')'))
+ .toString();
+ }
+
+ @override
+ int get hashCode => Object.hash(id, audioPlayerStateId, index);
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ (other is PlaylistTableData &&
+ other.id == this.id &&
+ other.audioPlayerStateId == this.audioPlayerStateId &&
+ other.index == this.index);
+}
+
+class PlaylistTableCompanion extends UpdateCompanion {
+ final Value id;
+ final Value audioPlayerStateId;
+ final Value index;
+ const PlaylistTableCompanion({
+ this.id = const Value.absent(),
+ this.audioPlayerStateId = const Value.absent(),
+ this.index = const Value.absent(),
+ });
+ PlaylistTableCompanion.insert({
+ this.id = const Value.absent(),
+ required int audioPlayerStateId,
+ required int index,
+ }) : audioPlayerStateId = Value(audioPlayerStateId),
+ index = Value(index);
+ static Insertable custom({
+ Expression? id,
+ Expression? audioPlayerStateId,
+ Expression? index,
+ }) {
+ return RawValuesInsertable({
+ if (id != null) 'id': id,
+ if (audioPlayerStateId != null)
+ 'audio_player_state_id': audioPlayerStateId,
+ if (index != null) 'index': index,
+ });
+ }
+
+ PlaylistTableCompanion copyWith(
+ {Value? id, Value? audioPlayerStateId, Value? index}) {
+ return PlaylistTableCompanion(
+ id: id ?? this.id,
+ audioPlayerStateId: audioPlayerStateId ?? this.audioPlayerStateId,
+ index: index ?? this.index,
+ );
+ }
+
+ @override
+ Map toColumns(bool nullToAbsent) {
+ final map = {};
+ if (id.present) {
+ map['id'] = Variable(id.value);
+ }
+ if (audioPlayerStateId.present) {
+ map['audio_player_state_id'] = Variable(audioPlayerStateId.value);
+ }
+ if (index.present) {
+ map['index'] = Variable(index.value);
+ }
+ return map;
+ }
+
+ @override
+ String toString() {
+ return (StringBuffer('PlaylistTableCompanion(')
+ ..write('id: $id, ')
+ ..write('audioPlayerStateId: $audioPlayerStateId, ')
+ ..write('index: $index')
+ ..write(')'))
+ .toString();
+ }
+}
+
+class $PlaylistMediaTableTable extends PlaylistMediaTable
+ with TableInfo<$PlaylistMediaTableTable, PlaylistMediaTableData> {
+ @override
+ final GeneratedDatabase attachedDatabase;
+ final String? _alias;
+ $PlaylistMediaTableTable(this.attachedDatabase, [this._alias]);
+ static const VerificationMeta _idMeta = const VerificationMeta('id');
+ @override
+ late final GeneratedColumn id = GeneratedColumn(
+ 'id', aliasedName, false,
+ hasAutoIncrement: true,
+ type: DriftSqlType.int,
+ requiredDuringInsert: false,
+ defaultConstraints:
+ GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
+ static const VerificationMeta _playlistIdMeta =
+ const VerificationMeta('playlistId');
+ @override
+ late final GeneratedColumn playlistId = GeneratedColumn(
+ 'playlist_id', aliasedName, false,
+ type: DriftSqlType.int,
+ requiredDuringInsert: true,
+ defaultConstraints:
+ GeneratedColumn.constraintIsAlways('REFERENCES playlist_table (id)'));
+ static const VerificationMeta _uriMeta = const VerificationMeta('uri');
+ @override
+ late final GeneratedColumn uri = GeneratedColumn(
+ 'uri', aliasedName, false,
+ type: DriftSqlType.string, requiredDuringInsert: true);
+ static const VerificationMeta _extrasMeta = const VerificationMeta('extras');
+ @override
+ late final GeneratedColumnWithTypeConverter