diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml
index 15501a9..85d0857 100644
--- a/android/app/src/main/res/drawable-v21/launch_background.xml
+++ b/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -6,6 +6,6 @@
-
+ android:src="@mipmap/launch_bg" />
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml
index 47f03ce..55cdf4b 100644
--- a/android/app/src/main/res/drawable/launch_background.xml
+++ b/android/app/src/main/res/drawable/launch_background.xml
@@ -6,6 +6,6 @@
-
+ android:src="@mipmap/launch_bg" />
diff --git a/android/app/src/main/res/mipmap-xhdpi/launch_bg.png b/android/app/src/main/res/mipmap-xhdpi/launch_bg.png
new file mode 100755
index 0000000..665c69d
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/launch_bg.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/launch_image.png b/android/app/src/main/res/mipmap-xhdpi/launch_image.png
deleted file mode 100755
index c57fd06..0000000
Binary files a/android/app/src/main/res/mipmap-xhdpi/launch_image.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/launch_bg.png b/android/app/src/main/res/mipmap-xxhdpi/launch_bg.png
new file mode 100755
index 0000000..7473648
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/launch_bg.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/launch_image.png b/android/app/src/main/res/mipmap-xxhdpi/launch_image.png
deleted file mode 100755
index b00732b..0000000
Binary files a/android/app/src/main/res/mipmap-xxhdpi/launch_image.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/launch_bg.png b/android/app/src/main/res/mipmap-xxxhdpi/launch_bg.png
new file mode 100755
index 0000000..8cf0b74
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/launch_bg.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/launch_image.png b/android/app/src/main/res/mipmap-xxxhdpi/launch_image.png
deleted file mode 100755
index 6550306..0000000
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/launch_image.png and /dev/null differ
diff --git a/android/settings.gradle b/android/settings.gradle
index 536165d..3b2fdaa 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -19,7 +19,8 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.3.0" apply false
- id "org.jetbrains.kotlin.android" version "1.7.10" apply false
+// id "org.jetbrains.kotlin.android" version "1.7.10" apply false
+ id "org.jetbrains.kotlin.android" version "1.9.20" apply false
}
include ":app"
diff --git a/assets/images/side_a/launch_bg.png b/assets/images/side_a/launch_bg.png
new file mode 100755
index 0000000..7473648
Binary files /dev/null and b/assets/images/side_a/launch_bg.png differ
diff --git a/assets/images/side_a/launch_image.png b/assets/images/side_a/launch_image.png
deleted file mode 100755
index c57fd06..0000000
Binary files a/assets/images/side_a/launch_image.png and /dev/null differ
diff --git a/assets/images/side_b/add_to_playlist.png b/assets/images/side_b/add_to_playlist.png
new file mode 100755
index 0000000..211256a
Binary files /dev/null and b/assets/images/side_b/add_to_playlist.png differ
diff --git a/assets/images/side_b/add_to_queue.png b/assets/images/side_b/add_to_queue.png
new file mode 100755
index 0000000..64b39e3
Binary files /dev/null and b/assets/images/side_b/add_to_queue.png differ
diff --git a/assets/images/side_b/collected.png b/assets/images/side_b/collected.png
new file mode 100644
index 0000000..0fb8b43
Binary files /dev/null and b/assets/images/side_b/collected.png differ
diff --git a/assets/images/side_b/delete_history.png b/assets/images/side_b/delete_history.png
new file mode 100644
index 0000000..3dc7162
Binary files /dev/null and b/assets/images/side_b/delete_history.png differ
diff --git a/assets/images/side_b/delete_white.png b/assets/images/side_b/delete_white.png
new file mode 100644
index 0000000..26e1893
Binary files /dev/null and b/assets/images/side_b/delete_white.png differ
diff --git a/assets/images/side_b/downloaded.png b/assets/images/side_b/downloaded.png
new file mode 100644
index 0000000..dcb290c
Binary files /dev/null and b/assets/images/side_b/downloaded.png differ
diff --git a/assets/images/side_b/empty.jpg b/assets/images/side_b/empty.jpg
new file mode 100644
index 0000000..9794e37
Binary files /dev/null and b/assets/images/side_b/empty.jpg differ
diff --git a/assets/images/side_b/img_error.png b/assets/images/side_b/img_error.png
deleted file mode 100644
index 7ef1e09..0000000
Binary files a/assets/images/side_b/img_error.png and /dev/null differ
diff --git a/assets/images/side_b/img_placeholder.png b/assets/images/side_b/img_placeholder.png
deleted file mode 100644
index f7a5faf..0000000
Binary files a/assets/images/side_b/img_placeholder.png and /dev/null differ
diff --git a/assets/images/side_b/love_songs_bg.png b/assets/images/side_b/love_songs_bg.png
new file mode 100644
index 0000000..452e396
Binary files /dev/null and b/assets/images/side_b/love_songs_bg.png differ
diff --git a/assets/images/side_b/more.png b/assets/images/side_b/more.png
new file mode 100644
index 0000000..9e29af0
Binary files /dev/null and b/assets/images/side_b/more.png differ
diff --git a/assets/images/side_b/more_edit.png b/assets/images/side_b/more_edit.png
new file mode 100644
index 0000000..f7db255
Binary files /dev/null and b/assets/images/side_b/more_edit.png differ
diff --git a/assets/images/side_b/more_remove.png b/assets/images/side_b/more_remove.png
new file mode 100644
index 0000000..f9e9359
Binary files /dev/null and b/assets/images/side_b/more_remove.png differ
diff --git a/assets/images/side_b/music_bar_next.png b/assets/images/side_b/music_bar_next.png
new file mode 100644
index 0000000..91f1f1b
Binary files /dev/null and b/assets/images/side_b/music_bar_next.png differ
diff --git a/assets/images/side_b/music_placeholder.png b/assets/images/side_b/music_placeholder.png
new file mode 100644
index 0000000..df530de
Binary files /dev/null and b/assets/images/side_b/music_placeholder.png differ
diff --git a/assets/images/side_b/download.png b/assets/images/side_b/not_download1.png
similarity index 100%
rename from assets/images/side_b/download.png
rename to assets/images/side_b/not_download1.png
diff --git a/assets/images/side_b/not_download2.png b/assets/images/side_b/not_download2.png
new file mode 100644
index 0000000..d6063ec
Binary files /dev/null and b/assets/images/side_b/not_download2.png differ
diff --git a/assets/images/side_b/personal_music_library_bg.png b/assets/images/side_b/personal_music_library_bg.png
index fbbab66..bb85ba4 100644
Binary files a/assets/images/side_b/personal_music_library_bg.png and b/assets/images/side_b/personal_music_library_bg.png differ
diff --git a/assets/images/side_b/playlist_play_all.png b/assets/images/side_b/playlist_play_all.png
new file mode 100644
index 0000000..413ee72
Binary files /dev/null and b/assets/images/side_b/playlist_play_all.png differ
diff --git a/assets/images/side_b/album_total.png b/assets/images/side_b/playlist_play_all_random.png
similarity index 100%
rename from assets/images/side_b/album_total.png
rename to assets/images/side_b/playlist_play_all_random.png
diff --git a/assets/images/side_b/album_title_bg.png b/assets/images/side_b/playlist_title_bg.png
similarity index 100%
rename from assets/images/side_b/album_title_bg.png
rename to assets/images/side_b/playlist_title_bg.png
diff --git a/assets/images/side_b/privacy_policy.png b/assets/images/side_b/privacy_policy.png
new file mode 100644
index 0000000..691f0f3
Binary files /dev/null and b/assets/images/side_b/privacy_policy.png differ
diff --git a/assets/images/side_b/report.png b/assets/images/side_b/report.png
new file mode 100755
index 0000000..b6ac8c9
Binary files /dev/null and b/assets/images/side_b/report.png differ
diff --git a/assets/images/side_b/search.png b/assets/images/side_b/search.png
new file mode 100644
index 0000000..39c7022
Binary files /dev/null and b/assets/images/side_b/search.png differ
diff --git a/assets/images/side_b/search_white.png b/assets/images/side_b/search_white.png
new file mode 100644
index 0000000..1295d88
Binary files /dev/null and b/assets/images/side_b/search_white.png differ
diff --git a/assets/images/side_b/setting_bg.png b/assets/images/side_b/setting_bg.png
new file mode 100644
index 0000000..ff2825d
Binary files /dev/null and b/assets/images/side_b/setting_bg.png differ
diff --git a/assets/images/side_b/terms_of_service.png b/assets/images/side_b/terms_of_service.png
new file mode 100644
index 0000000..cea8b79
Binary files /dev/null and b/assets/images/side_b/terms_of_service.png differ
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 6e9af27..a985f8a 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -503,7 +503,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.tone.music.offline;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
- "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = tone_snap;
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = ToneSnap_DEV;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
@@ -702,7 +702,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.tone.music.offline;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
- "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = tone_snap;
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = ToneSnap_DEV;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
@@ -736,7 +736,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.tone.music.offline;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
- "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = tone_snap;
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = ToneSnap_DEV;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index 497328a..d0021ba 100644
--- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -51,7 +51,7 @@
????
CFBundleVersion
$(FLUTTER_BUILD_NUMBER)
+ GADApplicationIdentifier
+ ca-app-pub-5684307632319406~7113477061
LSRequiresIPhoneOS
+ NSAppleMusicUsageDescription
+ We need to access the device media library to select audio files.
NSMicrophoneUsageDescription
We need to access the microphone to record or select audio files.
NSPhotoLibraryUsageDescription
We need access to the photo library to pick audio files.
- NSAppleMusicUsageDescription
- We need to access the device media library to select audio files.
- NSUserTrackingUsageDescription
- We need your permission to access the advertising identifier to provide better ad services.
+ NSUserTrackingUsageDescription
+ We need your permission to access the advertising identifier to provide better ad services.
+ SKAdNetworkItems
+
+
+ SKAdNetworkIdentifier
+ cstr6suwn9.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 4fzdc2evr5.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 4pfyvq9l8r.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 2fnua5tdw4.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ ydx93a7ass.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 5a6flpkh64.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ p78axxw29g.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ v72qych5uu.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ ludvb6z3bs.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ cp8zw746q7.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 3sh42y64q3.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ c6k4g5qg8m.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ s39g8k73mm.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 3qy4746246.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ f38h382jlk.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ hs6bdukanm.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ v4nxqhlyqp.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ wzmmz9fp6w.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ yclnxrl5pm.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ t38b2kh725.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 7ug5zh24hu.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ gta9lk7p23.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ vutu7akeur.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ y5ghdn5j9k.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ n6fk4nfna4.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ v9wttpbfk9.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ n38lu8286q.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 47vhws6wlr.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ kbd757ywx3.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 9t245vhmpl.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ eh6m2bh4zr.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ a2p9lx4jpn.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 22mmun2rn5.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 4468km3ulz.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 2u9pt9hc89.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 8s468mfl3y.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ klf5c3l5u5.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ ppxm28t8ap.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ ecpz2srf59.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ uw77j35x4d.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ pwa73g5rt2.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ mlmmfzh3r3.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 578prtvx9j.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 4dzt52r2t5.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ e5fvkxwrpn.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 8c4e2ghe7u.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ zq492l623r.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 3rd42ekr43.skadnetwork
+
+
+ SKAdNetworkIdentifier
+ 3qcr597p9d.skadnetwork
+
+
UIApplicationSupportsIndirectInputEvents
+ UIBackgroundModes
+
+ audio
+ fetch
+
UILaunchStoryboardName
LaunchScreen
UIMainStoryboardFile
@@ -53,206 +259,5 @@
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
- GADApplicationIdentifier
- ca-app-pub-5684307632319406~7113477061
- SKAdNetworkItems
-
-
- SKAdNetworkIdentifier
- cstr6suwn9.skadnetwork
-
-
- SKAdNetworkIdentifier
- 4fzdc2evr5.skadnetwork
-
-
- SKAdNetworkIdentifier
- 4pfyvq9l8r.skadnetwork
-
-
- SKAdNetworkIdentifier
- 2fnua5tdw4.skadnetwork
-
-
- SKAdNetworkIdentifier
- ydx93a7ass.skadnetwork
-
-
- SKAdNetworkIdentifier
- 5a6flpkh64.skadnetwork
-
-
- SKAdNetworkIdentifier
- p78axxw29g.skadnetwork
-
-
- SKAdNetworkIdentifier
- v72qych5uu.skadnetwork
-
-
- SKAdNetworkIdentifier
- ludvb6z3bs.skadnetwork
-
-
- SKAdNetworkIdentifier
- cp8zw746q7.skadnetwork
-
-
- SKAdNetworkIdentifier
- 3sh42y64q3.skadnetwork
-
-
- SKAdNetworkIdentifier
- c6k4g5qg8m.skadnetwork
-
-
- SKAdNetworkIdentifier
- s39g8k73mm.skadnetwork
-
-
- SKAdNetworkIdentifier
- 3qy4746246.skadnetwork
-
-
- SKAdNetworkIdentifier
- f38h382jlk.skadnetwork
-
-
- SKAdNetworkIdentifier
- hs6bdukanm.skadnetwork
-
-
- SKAdNetworkIdentifier
- v4nxqhlyqp.skadnetwork
-
-
- SKAdNetworkIdentifier
- wzmmz9fp6w.skadnetwork
-
-
- SKAdNetworkIdentifier
- yclnxrl5pm.skadnetwork
-
-
- SKAdNetworkIdentifier
- t38b2kh725.skadnetwork
-
-
- SKAdNetworkIdentifier
- 7ug5zh24hu.skadnetwork
-
-
- SKAdNetworkIdentifier
- gta9lk7p23.skadnetwork
-
-
- SKAdNetworkIdentifier
- vutu7akeur.skadnetwork
-
-
- SKAdNetworkIdentifier
- y5ghdn5j9k.skadnetwork
-
-
- SKAdNetworkIdentifier
- n6fk4nfna4.skadnetwork
-
-
- SKAdNetworkIdentifier
- v9wttpbfk9.skadnetwork
-
-
- SKAdNetworkIdentifier
- n38lu8286q.skadnetwork
-
-
- SKAdNetworkIdentifier
- 47vhws6wlr.skadnetwork
-
-
- SKAdNetworkIdentifier
- kbd757ywx3.skadnetwork
-
-
- SKAdNetworkIdentifier
- 9t245vhmpl.skadnetwork
-
-
- SKAdNetworkIdentifier
- eh6m2bh4zr.skadnetwork
-
-
- SKAdNetworkIdentifier
- a2p9lx4jpn.skadnetwork
-
-
- SKAdNetworkIdentifier
- 22mmun2rn5.skadnetwork
-
-
- SKAdNetworkIdentifier
- 4468km3ulz.skadnetwork
-
-
- SKAdNetworkIdentifier
- 2u9pt9hc89.skadnetwork
-
-
- SKAdNetworkIdentifier
- 8s468mfl3y.skadnetwork
-
-
- SKAdNetworkIdentifier
- klf5c3l5u5.skadnetwork
-
-
- SKAdNetworkIdentifier
- ppxm28t8ap.skadnetwork
-
-
- SKAdNetworkIdentifier
- ecpz2srf59.skadnetwork
-
-
- SKAdNetworkIdentifier
- uw77j35x4d.skadnetwork
-
-
- SKAdNetworkIdentifier
- pwa73g5rt2.skadnetwork
-
-
- SKAdNetworkIdentifier
- mlmmfzh3r3.skadnetwork
-
-
- SKAdNetworkIdentifier
- 578prtvx9j.skadnetwork
-
-
- SKAdNetworkIdentifier
- 4dzt52r2t5.skadnetwork
-
-
- SKAdNetworkIdentifier
- e5fvkxwrpn.skadnetwork
-
-
- SKAdNetworkIdentifier
- 8c4e2ghe7u.skadnetwork
-
-
- SKAdNetworkIdentifier
- zq492l623r.skadnetwork
-
-
- SKAdNetworkIdentifier
- 3rd42ekr43.skadnetwork
-
-
- SKAdNetworkIdentifier
- 3qcr597p9d.skadnetwork
-
-
-
\ No newline at end of file
+
diff --git a/lib/ads/app_open_ad_manager.dart b/lib/ads/app_open_ad_manager.dart
index 90df786..7b480a8 100644
--- a/lib/ads/app_open_ad_manager.dart
+++ b/lib/ads/app_open_ad_manager.dart
@@ -7,7 +7,10 @@ import 'dart:io' show Platform;
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
+import 'package:get/get.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
+import 'package:tone_snap/data/storage/music_box.dart';
+import 'package:tone_snap/modules/launch/launch_controller.dart';
import 'package:tone_snap/utils/log_util.dart';
class AppOpenAdManager {
@@ -26,13 +29,16 @@ class AppOpenAdManager {
AppOpenAd? _appOpenAd;
bool _isShowingAd = false;
+ /// 记录关闭时的时间,用于下一次展示时计算时间差
+ DateTime? closeDateTime;
+
/// 开屏广告单元id
final adUnitId = Platform.isAndroid
- ? (kDebugMode ? 'ca-app-pub-3940256099942544/9257395921' : '')
- : (kDebugMode ? 'ca-app-pub-3940256099942544/5575463023' : 'ca-app-pub-5684307632319406/2523581084');
+ ? (kReleaseMode ? '' : 'ca-app-pub-3940256099942544/9257395921')
+ : (kReleaseMode ? 'ca-app-pub-5684307632319406/2523581084' : 'ca-app-pub-3940256099942544/5575463023');
/// 加载广告
- void loadAd() async {
+ Future loadAd() async {
final List connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult.contains(ConnectivityResult.none)) {
return;
@@ -40,7 +46,7 @@ class AppOpenAdManager {
if (isAdAvailable) {
return;
}
- AppOpenAd.load(
+ await AppOpenAd.load(
adUnitId: adUnitId,
request: const AdRequest(),
adLoadCallback: AppOpenAdLoadCallback(
@@ -48,6 +54,11 @@ class AppOpenAdManager {
LogUtil.d('开屏广告加载完成');
_appOpenAd = ad;
_appOpenLoadTime = DateTime.now();
+ if (AppOpenAdManager().isAdAvailable) {
+ if (Get.isRegistered()) {
+ LaunchController.to.editChangeValue();
+ }
+ }
},
onAdFailedToLoad: (error) {
LogUtil.e('开屏广告加载失败: $error');
@@ -84,6 +95,17 @@ class AppOpenAdManager {
if(onTap != null) onTap();
return;
}
+ if (closeDateTime != null) {
+ // 计算时间差
+ Duration timeDifference = DateTime.now().difference(closeDateTime!);
+ // 获取配置的 openAppEventDuration
+ int openAppEventDuration = MusicBox().getOpenAppEventDuration();
+ // 检查时间差是否小于10秒
+ if (timeDifference < Duration(seconds: openAppEventDuration)) {
+ return;
+ }
+ }
+
// 设置 fullScreenContentCallback 并显示广告
_appOpenAd!.fullScreenContentCallback = FullScreenContentCallback(
// 暂停应用程序中的活动或记录广告展示的时间
@@ -108,6 +130,8 @@ class AppOpenAdManager {
},
onAdDismissedFullScreenContent: (ad) {
LogUtil.d('$ad onAdDismissedFullScreenContent');
+ closeDateTime = DateTime.now();
+
// 显示状态栏(用户关闭广告后)
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values);
diff --git a/lib/ads/interstitial_ad_manager.dart b/lib/ads/interstitial_ad_manager.dart
index ec4cef3..7a44ec1 100644
--- a/lib/ads/interstitial_ad_manager.dart
+++ b/lib/ads/interstitial_ad_manager.dart
@@ -27,8 +27,8 @@ class InterstitialAdManager {
/// 插页广告单元id
final adUnitId = Platform.isAndroid
- ? (kDebugMode ? 'ca-app-pub-3940256099942544/1033173712' : '')
- : (kDebugMode ? 'ca-app-pub-3940256099942544/4411468910' : 'ca-app-pub-5684307632319406/2760767691');
+ ? (kReleaseMode ? '' : 'ca-app-pub-3940256099942544/1033173712')
+ : (kReleaseMode ? 'ca-app-pub-5684307632319406/2760767691' : 'ca-app-pub-3940256099942544/4411468910');
/// 加载广告
void loadAd() async {
diff --git a/lib/components/base_easyloading.dart b/lib/components/base_easyloading.dart
index 9609730..52bbfe5 100644
--- a/lib/components/base_easyloading.dart
+++ b/lib/components/base_easyloading.dart
@@ -43,7 +43,7 @@ class BaseEasyLoading {
bool show = true,
}) {
EasyLoading.instance.userInteractions = false;
- if (show) EasyLoading.show(status: value, dismissOnTap: true);
+ if (show) EasyLoading.show(status: value, dismissOnTap: false);
}
static void dismiss({bool dismiss = true}) {
diff --git a/lib/components/dialog/add_playlist_dialog.dart b/lib/components/dialog/add_playlist_dialog.dart
new file mode 100644
index 0000000..8e08457
--- /dev/null
+++ b/lib/components/dialog/add_playlist_dialog.dart
@@ -0,0 +1,143 @@
+// Author: fengshengxiong
+// Date: 2024/5/11
+// Description: 创建播放列表弹框
+
+import 'package:flutter/material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:get/get.dart';
+import 'package:tone_snap/components/divider_widget.dart';
+import 'package:tone_snap/res/themes/app_colors.dart';
+import 'package:tone_snap/utils/obj_util.dart';
+
+class CreatePlaylistDialog extends Dialog {
+ CreatePlaylistDialog({super.key,this.name, required this.onTap});
+
+ final _textEditingController = TextEditingController();
+ final String? name;
+ final Function(String name) onTap;
+
+ @override
+ Widget build(BuildContext context) {
+ _textEditingController.text = name ?? '';
+ return Scaffold(
+ backgroundColor: Colors.transparent,
+ body: Material(
+ type: MaterialType.transparency,
+ child: Center(
+ child: IntrinsicHeight(
+ child: Container(
+ width: 1.sw * 0.72,
+ clipBehavior: Clip.antiAlias,
+ decoration: BoxDecoration(
+ color: const Color(0xFF282A2C),
+ borderRadius: BorderRadius.circular(12.r),
+ ),
+ child: Column(
+ children: [
+ SizedBox(height: 19.h),
+ Text(
+ 'Create playlist',
+ textAlign: TextAlign.center,
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 17.sp,
+ fontWeight: FontWeight.w600,
+ ),
+ ),
+ SizedBox(height: 19.h),
+ Container(
+ height: 30.h,
+ alignment: Alignment.center,
+ margin: EdgeInsets.symmetric(horizontal: 16.w),
+ decoration: BoxDecoration(
+ color: const Color(0xFF1c1c1e),
+ borderRadius: BorderRadius.circular(6).r,
+ border: Border.all(
+ color: const Color(0xff333437),
+ width: 1.w,
+ ),
+ ),
+ child: TextField(
+ maxLines: 1,
+ controller: _textEditingController,
+ textInputAction: TextInputAction.done,
+ keyboardType: TextInputType.text,
+ style: TextStyle(color: Colors.white, fontSize: 15.sp),
+ textAlignVertical: TextAlignVertical.center,
+ maxLength: 30,
+ decoration: InputDecoration(
+ counterText: '',
+ hintText: 'My playlist1',
+ hintStyle: TextStyle(
+ color: const Color(0xFF5a635f),
+ fontSize: 15.sp,
+ ),
+ contentPadding: const EdgeInsets.symmetric(horizontal: 10).w,
+ isCollapsed: true,
+ border: InputBorder.none,
+ ),
+ ),
+ ),
+ SizedBox(height: 19.h),
+ DividerWidget(
+ height: 0.5.h,
+ color: const Color(0xA6545458),
+ ),
+ SizedBox(
+ height: 44.h,
+ child: Row(
+ children: [
+ _optionButton('Cancel', false),
+ Container(
+ width: 0.5.w,
+ height: double.infinity,
+ color: const Color(0xA6545458),
+ ),
+ _optionButton('Confirm', true),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ Widget _optionButton(String label, bool isConfirm) {
+ return Expanded(
+ child: Material(
+ color: Colors.transparent,
+ child: InkWell(
+ onTap: () {
+ if (isConfirm) {
+ if (ObjUtil.isNotEmpty(_textEditingController.text)) {
+ onTap(_textEditingController.text);
+ } else {
+ onTap('My playlist1');
+ }
+ Get.back();
+ } else {
+ Get.back();
+ }
+ },
+ child: SizedBox(
+ height: double.infinity,
+ child: Center(
+ child: Text(
+ label,
+ textAlign: TextAlign.center,
+ style: TextStyle(
+ color: isConfirm ? seedColor : Colors.white,
+ fontSize: 17.sp,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/components/dialog/rename_dialog.dart b/lib/components/dialog/rename_dialog.dart
index 0e481da..8056406 100644
--- a/lib/components/dialog/rename_dialog.dart
+++ b/lib/components/dialog/rename_dialog.dart
@@ -134,7 +134,7 @@ class RenameDialogState extends State {
child: InkWell(
onTap: () {
if (isConfirm) {
- if (!ObjUtil.isNotEmptyStr(_textEditingController.text)) {
+ if (!ObjUtil.isNotEmpty(_textEditingController.text)) {
BaseEasyLoading.toast('name cannot be empty');
return;
}
diff --git a/lib/components/get_bind_widget.dart b/lib/components/get_bind_widget.dart
new file mode 100644
index 0000000..d3c0bde
--- /dev/null
+++ b/lib/components/get_bind_widget.dart
@@ -0,0 +1,96 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+/// [author] Fson
+/// [date] 2022/12/7
+/// [description]
+
+/// GetBindWidget can bind GetxController, and when the page is disposed,
+/// it can automatically destroy the bound related GetXController
+///
+///
+/// Sample:
+///
+/// class SampleController extends GetxController {
+/// final String title = 'My Awesome View';
+/// }
+///
+/// class SamplePage extends StatelessWidget {
+/// final controller = SampleController();
+///
+/// @override
+/// Widget build(BuildContext context) {
+/// return GetBindWidget(
+/// bind: controller,
+/// child: Container(),
+/// );
+/// }
+/// }
+class GetBindWidget extends StatefulWidget {
+ const GetBindWidget({
+ super.key,
+ this.bind,
+ this.tag,
+ this.binds,
+ this.tags,
+ required this.child,
+ }) : assert(
+ binds == null || tags == null || binds.length == tags.length,
+ 'The binds and tags arrays length should be equal\n'
+ 'and the elements in the two arrays correspond one-to-one',
+ );
+
+ final GetxController? bind;
+ final String? tag;
+
+ final List? binds;
+ final List? tags;
+
+ final Widget child;
+
+ @override
+ GetBindWidgetState createState() => GetBindWidgetState();
+}
+
+class GetBindWidgetState extends State{
+ @override
+ Widget build(BuildContext context) {
+ return widget.child;
+ }
+
+ @override
+ void dispose() {
+ _closeGetXController();
+ _closeGetXControllers();
+
+ super.dispose();
+ }
+
+ ///Close GetxController bound to the current page
+ void _closeGetXController() {
+ if (widget.bind == null) {
+ return;
+ }
+
+ var key = widget.bind.runtimeType.toString() + (widget.tag ?? '');
+ GetInstance().delete(key: key);
+ }
+
+ ///Batch close GetxController bound to the current page
+ void _closeGetXControllers() {
+ if (widget.binds == null) {
+ return;
+ }
+
+ for (var i = 0; i < widget.binds!.length; i++) {
+ var type = widget.binds![i].runtimeType.toString();
+
+ if (widget.tags == null) {
+ GetInstance().delete(key: type);
+ } else {
+ var key = type + (widget.tags?[i] ?? '');
+ GetInstance().delete(key: key);
+ }
+ }
+ }
+}
diff --git a/lib/components/music_bar/music_bar_controller.dart b/lib/components/music_bar/music_bar_controller.dart
deleted file mode 100644
index 90f90ba..0000000
--- a/lib/components/music_bar/music_bar_controller.dart
+++ /dev/null
@@ -1,49 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-import 'package:tone_snap/routes/app_routes.dart';
-
-class MusicBarController extends GetxController with GetSingleTickerProviderStateMixin {
- static MusicBarController get to => Get.find();
- AnimationController? _controller;
- var bottom = 0.0.obs;
- double bottomPadding = 0.0;
-
- @override
- void onInit() {
- super.onInit();
- _controller = AnimationController(vsync: this)..duration = const Duration(milliseconds: 200);
- WidgetsBinding.instance.addPostFrameCallback((_) {
- bottomPadding = MediaQuery.of(Get.context!).padding.bottom;
- bottom.value = kBottomNavigationBarHeight + bottomPadding;
- });
- }
-
- @override
- void onClose() {
- _controller?.dispose();
- super.onClose();
- }
-
- /// 底部导航栏消失时沉底
- void toBottom() {
- var animation = Tween(begin: bottom.value, end: bottomPadding).animate(_controller!);
- animation.addListener(() {
- bottom.value = animation.value;
- });
- _controller!.forward();
- }
-
- /// 底部导航栏出现时抬高
- void riseUp() {
- var animation = Tween(begin: bottom.value, end: kBottomNavigationBarHeight + bottomPadding).animate(_controller!);
- animation.addListener(() {
- bottom.value = animation.value;
- });
- _controller!.forward();
- }
-
- /// 打开播放页面
- void openPlayPage() {
- Get.toNamed(AppRoutes.playPage, arguments: {'isMusicBarOpen': true});
- }
-}
diff --git a/lib/components/music_bar/music_bar_view.dart b/lib/components/music_bar/music_bar_view.dart
deleted file mode 100644
index 662fff5..0000000
--- a/lib/components/music_bar/music_bar_view.dart
+++ /dev/null
@@ -1,95 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_screenutil/flutter_screenutil.dart';
-import 'package:get/get.dart';
-import 'package:tone_snap/components/my_marquee_text.dart';
-import 'package:tone_snap/components/network_image_widget.dart';
-import 'package:tone_snap/modules/sideb/controllers/music_player_controller.dart';
-import 'package:tone_snap/res/themes/app_sizes.dart';
-import 'package:tone_snap/utils/obj_util.dart';
-
-import 'music_bar_controller.dart';
-
-class MusicBarView extends StatelessWidget {
- MusicBarView({super.key});
-
- final controller = Get.put(MusicBarController(), permanent: true);
- final musicPlayerController = MusicPlayerController.to;
-
- @override
- Widget build(BuildContext context) {
- return Obx(() {
- return Stack(
- fit: StackFit.expand,
- children: [
- Positioned(
- bottom: controller.bottom.value,
- left: 16.w,
- right: 16.w,
- child: GestureDetector(
- onTap: controller.openPlayPage,
- child: Container(
- width: 1.sw - 32.w,
- height: musicBarHeight,
- padding: EdgeInsets.symmetric(horizontal: 26.w),
- decoration: BoxDecoration(
- color: const Color(0xFF80F988),
- borderRadius: BorderRadius.circular(36).r,
- boxShadow: const [
- BoxShadow(
- color: Color(0x40040604),
- offset: Offset(0, 4),
- blurRadius: 4,
- spreadRadius: 0,
- ),
- ],
- ),
- child: Row(
- children: [
- ClipOval(
- child: Obx(() {
- return NetworkImageWidget(
- url: musicPlayerController.musicModel.value.thumbnail,
- width: 48.w,
- height: 48.w,
- );
- }),
- ),
- SizedBox(width: 12.w),
- Expanded(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Obx(() {
- return MyMarqueeText(
- text: ObjUtil.getStr(musicPlayerController.musicModel.value.title),
- textStyle: TextStyle(
- color: Colors.black,
- fontSize: 16.sp,
- fontWeight: FontWeight.w600,
- ),
- );
- }),
- SizedBox(height: 4.h),
- Obx(() {
- return MyMarqueeText(
- text: ObjUtil.getStr(musicPlayerController.musicModel.value.subTitle),
- textStyle: TextStyle(
- color: Colors.black,
- fontSize: 12.sp,
- ),
- );
- }),
- ],
- ),
- ),
- ],
- ),
- ),
- ),
- ),
- ],
- );
- });
- }
-}
diff --git a/lib/components/my_marquee_text.dart b/lib/components/my_marquee_text.dart
index 57df683..09a39fa 100644
--- a/lib/components/my_marquee_text.dart
+++ b/lib/components/my_marquee_text.dart
@@ -20,8 +20,8 @@ class MyMarqueeText extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Marquee(
- delay: const Duration(seconds: 2),
- duration: Duration(seconds: enable ? 12 : 0),
+ delay: Duration.zero,
+ duration: Duration(seconds: enable ? 16 : 0),
pause: Duration.zero,
gap: 80,
child: Text(text, style: textStyle),
diff --git a/lib/components/network_image_widget.dart b/lib/components/network_image_widget.dart
index 32b7a73..82bde1f 100644
--- a/lib/components/network_image_widget.dart
+++ b/lib/components/network_image_widget.dart
@@ -4,6 +4,7 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:tone_snap/generated/assets.dart';
class NetworkImageWidget extends StatelessWidget {
@@ -14,7 +15,9 @@ class NetworkImageWidget extends StatelessWidget {
this.radius = 0.0,
this.url,
this.fit = BoxFit.cover,
- this.placeholder,
+ this.placeholderWidth,
+ this.placeholderHeight,
+ this.placeholderImg,
this.noPlaceholder = false,
});
@@ -23,7 +26,9 @@ class NetworkImageWidget extends StatelessWidget {
final double radius;
final String? url;
final BoxFit fit;
- final String? placeholder;
+ final double? placeholderWidth;
+ final double? placeholderHeight;
+ final String? placeholderImg;
final bool noPlaceholder;
@override
@@ -35,20 +40,27 @@ class NetworkImageWidget extends StatelessWidget {
height: height,
imageUrl: '$url',
fit: fit,
- placeholder: noPlaceholder ? null : (context, url) {
- return _placeholderWidget(Assets.sideBImgPlaceholder);
+ placeholder: (context, url) {
+ return noPlaceholder ? Container() : _placeholderWidget();
},
- errorWidget: noPlaceholder ? null : (context, url, error) {
- return _placeholderWidget(Assets.sideBImgError);
+ errorWidget: (context, url, error) {
+ return noPlaceholder ? Container() : _placeholderWidget();
},
),
);
}
- Widget _placeholderWidget(String img) {
- return Image.asset(
- placeholder ?? img,
- color: Colors.white12,
+ Widget _placeholderWidget() {
+ return Container(
+ color: const Color(0xFF242529),
+ child: FittedBox(
+ fit: BoxFit.none,
+ child: Image.asset(
+ placeholderImg ?? Assets.sideBMusicPlaceholder,
+ width: placeholderWidth ?? 24.w,
+ height: placeholderHeight ?? 24.w,
+ ),
+ ),
);
}
}
diff --git a/lib/components/refresh/base_easyrefresh.dart b/lib/components/refresh/base_easyrefresh.dart
index dce1782..d04ec95 100644
--- a/lib/components/refresh/base_easyrefresh.dart
+++ b/lib/components/refresh/base_easyrefresh.dart
@@ -1,58 +1,42 @@
-// Author: fengshengxiong
-// Date: 2024/5/7
-// Description: 下拉刷新、上拉加载
-
import 'dart:async';
+
import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
-import 'package:flutter_screenutil/flutter_screenutil.dart';
-import 'package:tone_snap/components/view_state_widget.dart';
class BaseEasyRefresh extends StatelessWidget {
- const BaseEasyRefresh({
- super.key,
- required this.controller,
- this.header,
- this.footer,
- this.onRefresh,
- this.onLoad,
- this.refreshOnStart = false,
- required this.viewState,
- required this.child,
- this.width,
- this.height,
- });
-
- final EasyRefreshController controller;
+ final EasyRefreshController? controller;
+ final bool noMoreRefresh;
+ final bool noMoreLoad;
+ final bool refreshOnStart;
final Header? header;
final Footer? footer;
final FutureOr Function()? onRefresh;
final FutureOr Function()? onLoad;
- final bool refreshOnStart;
- final ViewState viewState;
final Widget child;
- final double? width;
- final double? height;
+
+ const BaseEasyRefresh({
+ super.key,
+ this.controller,
+ this.noMoreRefresh = false,
+ this.noMoreLoad = false,
+ this.refreshOnStart = false,
+ this.header,
+ this.footer,
+ required this.child,
+ this.onRefresh,
+ this.onLoad,
+ });
@override
Widget build(BuildContext context) {
return EasyRefresh(
+ refreshOnStart: refreshOnStart,
controller: controller,
- header: header ?? const ClassicHeader(),
- footer: footer ?? const ClassicFooter(),
+ header: header,
+ footer: footer,
onRefresh: onRefresh,
onLoad: onLoad,
- refreshOnStart: refreshOnStart,
- child: viewState == ViewState.normal ? child : SingleChildScrollView(
- child: SizedBox(
- width: width ?? 1.sw,
- height: height ?? 300.h,
- child: ViewStateWidget(
- viewState: viewState,
- child: child,
- ),
- ),
- ),
+ child: child,
);
}
}
diff --git a/lib/components/view_state_widget.dart b/lib/components/view_state_widget.dart
index afb0a53..3cf4775 100644
--- a/lib/components/view_state_widget.dart
+++ b/lib/components/view_state_widget.dart
@@ -4,6 +4,10 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:tone_snap/data/enum/app_side_enum.dart';
+import 'package:tone_snap/generated/assets.dart';
+import 'package:tone_snap/global/app_config.dart';
+import 'package:tone_snap/res/themes/app_colors.dart';
/// 四种视图状态
enum ViewState { normal, error, loading, empty }
@@ -26,11 +30,9 @@ class ViewStateWidget extends StatelessWidget {
case ViewState.normal:
return child;
case ViewState.loading:
- return loadingView(
- backgroundColor: cpiBgColor,
- );
+ return loadingView(backgroundColor: cpiBgColor);
case ViewState.empty:
- return emptyView();
+ return AppConfig.appSideEnum == AppSideEnum.sideA ? emptyViewA() : emptyViewB();
case ViewState.error:
return errorView();
}
@@ -40,23 +42,19 @@ class ViewStateWidget extends StatelessWidget {
/// 加载中视图
Widget loadingView({
Color? color,
- Animation? valueColor,
Color? backgroundColor,
- double? value,
}) {
return Center(
child: CircularProgressIndicator(
strokeWidth: 3,
- color: color,
- valueColor: valueColor,
+ color: AppConfig.appSideEnum == AppSideEnum.sideA ? color : seedColor,
backgroundColor: backgroundColor,
- value: value,
),
);
}
/// 空视图
-Widget emptyView({String? msg, Color? textColor}) {
+Widget emptyViewA({String? msg, Color? textColor}) {
return Center(
child: Text(
msg ?? 'No data',
@@ -69,6 +67,17 @@ Widget emptyView({String? msg, Color? textColor}) {
);
}
+/// 空视图2
+Widget emptyViewB() {
+ return Center(
+ child: Image.asset(
+ Assets.sideBEmpty,
+ width: 180.w,
+ height: 160.h,
+ ),
+ );
+}
+
/// 错误视图
Widget errorView({String? msg, Color? textColor}) {
return Center(
diff --git a/lib/data/api/music_api.dart b/lib/data/api/music_api.dart
index 672fa8c..34c9be4 100644
--- a/lib/data/api/music_api.dart
+++ b/lib/data/api/music_api.dart
@@ -2,65 +2,72 @@
// Date: 2024/6/18
// Description: 音乐播放器Api
-import 'package:devicelocale/devicelocale.dart';
-import 'package:tone_snap/data/models/player_model.dart';
-import 'package:tone_snap/global/app_config.dart';
-import 'package:tone_snap/data/models/browse_model.dart';
-import 'package:tone_snap/data/network/dio_client.dart';
+import 'package:dio/dio.dart';
+import 'package:flutter/material.dart';
import 'package:tone_snap/data/models/next_model.dart';
-import 'package:tone_snap/utils/date_util.dart';
+import 'package:tone_snap/data/models/player_model.dart';
+import 'package:tone_snap/data/models/search_suggestions_model.dart';
+import 'package:tone_snap/data/network/base_error.dart';
+import 'package:tone_snap/data/network/dio_client.dart';
+import 'package:tone_snap/data/storage/music_box.dart';
+import 'package:tone_snap/global/app_config.dart';
class MusicApi {
static const String baseUrl = 'https://music.youtube.com/youtubei/v1/';
- /// 首页browse接口
+ /// browse
static Future browse({
String? visitorData,
Map? queryParameters,
T Function(Map)? formJson,
+ bool showLoading = false,
+ bool showToast = false,
}) async {
- String date = DateUtil.getSevenDaysAgo();
- String locale = await Devicelocale.currentLocale ?? AppConfig.defaultLocale;
+ String clientVersion = MusicBox().getClientVersion();
+ String preferredLanguages = WidgetsBinding.instance.platformDispatcher.locale.languageCode;
final body = {
"context": {
"client": {
"visitorData": visitorData,
"clientName": "WEB_REMIX",
- // "clientVersion": "1.$date.01.00",
- "clientVersion": "1.20240607.01.00",
+ "clientVersion": clientVersion,
"platform": "DESKTOP",
- "hl": locale,
- // "gl": AppConfig.isoCode
- "gl": 'HK'
+ "hl": preferredLanguages,
+ "gl": AppConfig.isoCode
}
}
};
- T? resultModel;
+ T? model;
await DioClient().request(
'browse',
+ showLoading: showLoading,
+ showToast: showToast,
requestMethod: RequestMethod.post,
data: body,
queryParameters: queryParameters,
formJson: formJson,
- success: (model) => resultModel = model,
+ success: (data) => model = data,
);
- return resultModel;
+ return model;
}
- /// next接口
- static Future next({String? visitorData, String? playlistId, String? videoId}) async {
- String date = DateUtil.getSevenDaysAgo();
- String locale = await Devicelocale.currentLocale ?? AppConfig.defaultLocale;
+ /// next
+ static Future next({
+ String? playlistId,
+ String? videoId,
+ bool showLoading = false,
+ bool showToast = true,
+ }) async {
+ String clientVersion = MusicBox().getClientVersion();
+ String preferredLanguages = WidgetsBinding.instance.platformDispatcher.locale.languageCode;
final body = {
"context": {
"client": {
- "visitorData": visitorData,
"clientName": "WEB_REMIX",
- "clientVersion": "1.$date",
+ "clientVersion": clientVersion,
"platform": "DESKTOP",
- "hl": locale,
- // "gl": AppConfig.isoCode
- "gl": 'HK'
+ "hl": preferredLanguages,
+ "gl": AppConfig.isoCode
}
}
};
@@ -69,28 +76,34 @@ class MusicApi {
'playlistId': playlistId,
'videoId': videoId
};
- NextModel? nextModel;
+ NextModel? model;
await DioClient().request(
'next',
- showLoading: true,
- showToast: true,
+ showLoading: showLoading,
+ showToast: showToast,
requestMethod: RequestMethod.post,
data: body,
queryParameters: queryParameters,
formJson: NextModel.fromMap,
- success: (model) => nextModel = model,
+ success: (data) => model = data,
);
- return nextModel;
+ return model;
}
- /// player接口
- static Future player({String? visitorData, String? videoId}) async {
- String date = DateUtil.getSevenDaysAgo();
+ /// player
+ static Future player({
+ String? videoId,
+ CancelToken? cancelToken,
+ Function(BaseError baseError)? fail,
+ bool showLoading = false,
+ bool showToast = true,
+ }) async {
+ String playerVersion = MusicBox().getPlayerVersion();
final body = {
"context": {
"client": {
"clientName": "ANDROID_MUSIC",
- "clientVersion": "6.07.1",
+ "clientVersion": playerVersion,
"platform": "MOBILE",
"browserVersion":"125.0.0.0"
}
@@ -101,17 +114,92 @@ class MusicApi {
'playlistId': null,
'videoId': videoId
};
- PlayerModel? playerModel;
+ PlayerModel? model;
await DioClient().request(
'player',
- showLoading: true,
- showToast: true,
+ showLoading: showLoading,
+ showToast: showToast,
requestMethod: RequestMethod.post,
data: body,
queryParameters: queryParameters,
+ cancelToken: cancelToken,
formJson: PlayerModel.fromMap,
- success: (model) => playerModel = model,
+ success: (data) => model = data,
+ fail: fail,
);
- return playerModel;
+ return model;
+ }
+
+ /// 搜索建议
+ static Future searchSuggestions({
+ String? input,
+ CancelToken? cancelToken,
+ bool showLoading = false,
+ bool showToast = false,
+ }) async {
+ String clientVersion = MusicBox().getClientVersion();
+ String preferredLanguages = WidgetsBinding.instance.platformDispatcher.locale.languageCode;
+ final body = {
+ "context": {
+ "client": {
+ "clientName": "WEB_REMIX",
+ "clientVersion": clientVersion,
+ "platform": "DESKTOP",
+ "hl": preferredLanguages,
+ "gl": AppConfig.isoCode
+ }
+ }
+ };
+ Map? queryParameters = {
+ 'prettyPrint': false,
+ 'input': input,
+ };
+ SearchSuggestionsModel? model;
+ await DioClient().request(
+ 'music/get_search_suggestions',
+ showLoading: showLoading,
+ showToast: showToast,
+ requestMethod: RequestMethod.post,
+ data: body,
+ queryParameters: queryParameters,
+ cancelToken: cancelToken,
+ formJson: SearchSuggestionsModel.fromMap,
+ success: (data) => model = data,
+ );
+ return model;
+ }
+
+ /// 搜索
+ static Future search({
+ Map? queryParameters,
+ T Function(Map)? formJson,
+ bool showLoading = false,
+ bool showToast = true,
+ }) async {
+ String clientVersion = MusicBox().getClientVersion();
+ String preferredLanguages = WidgetsBinding.instance.platformDispatcher.locale.languageCode;
+ final body = {
+ "context": {
+ "client": {
+ "clientName": "WEB_REMIX",
+ "clientVersion": clientVersion,
+ "platform": "DESKTOP",
+ "hl": preferredLanguages,
+ "gl": AppConfig.isoCode
+ }
+ }
+ };
+ T? model;
+ await DioClient().request(
+ 'search',
+ showLoading: showLoading,
+ showToast: showToast,
+ requestMethod: RequestMethod.post,
+ data: body,
+ queryParameters: queryParameters,
+ formJson: formJson,
+ success: (data) => model = data,
+ );
+ return model;
}
}
diff --git a/lib/data/api/tikustok_api.dart b/lib/data/api/tikustok_api.dart
index 134f599..56259ed 100644
--- a/lib/data/api/tikustok_api.dart
+++ b/lib/data/api/tikustok_api.dart
@@ -9,13 +9,13 @@ import 'package:tone_snap/data/models/isocode_model.dart';
class TikUsTokApi {
static const String baseUrl = 'https://api.tikustok.com/';
- /// 获取所在区域、ip
- static Future?> getIp() async {
- BaseModel? baseModel;
- await DioClient(baseUrl: baseUrl).request>(
+ /// 获取所在区域
+ static Future?> getIsoCode() async {
+ BaseModel? baseModel;
+ await DioClient(baseUrl: baseUrl).request>(
'app/common/getIPInfo',
requestMethod: RequestMethod.get,
- formJson: (json) => BaseModel.fromMap(json, IosCodeModel.fromMap),
+ formJson: (json) => BaseModel.fromMap(json, IsoCodeModel.fromMap),
success: (model) => baseModel = model,
);
return baseModel;
diff --git a/lib/data/enum/browse_type.dart b/lib/data/enum/music_type.dart
similarity index 53%
rename from lib/data/enum/browse_type.dart
rename to lib/data/enum/music_type.dart
index b8ac3f1..c1c56d5 100644
--- a/lib/data/enum/browse_type.dart
+++ b/lib/data/enum/music_type.dart
@@ -1,9 +1,9 @@
// Author: fengshengxiong
// Date: 2024/6/13
-// Description: 资源类型
+// Description: 音乐类型
-enum BrowseType {
- /// 电台/单曲
+enum MusicType {
+ /// 单曲
musicVideoTypeAtv(name: 'MUSIC_VIDEO_TYPE_ATV'),
/// 视频
@@ -12,11 +12,11 @@ enum BrowseType {
/// 专辑
musicPageTypeAlbum(name: 'MUSIC_PAGE_TYPE_ALBUM'),
- /// 艺术家
- // musicPageTypeArtist(name: 'MUSIC_PAGE_TYPE_ARTIST'),
-
/// 歌单/列表
- musicPageTypePlaylist(name: 'MUSIC_PAGE_TYPE_PLAYLIST');
+ musicPageTypePlaylist(name: 'MUSIC_PAGE_TYPE_PLAYLIST'),
+
+ /// 艺术家
+ musicPageTypeArtist(name: 'MUSIC_PAGE_TYPE_ARTIST');
/// 歌词
// musicPageTypeTrackLyrics(name: 'MUSIC_PAGE_TYPE_TRACK_LYRICS'),
@@ -24,20 +24,21 @@ enum BrowseType {
/// 相关内容
// musicPageTypeTrackRelated(name: 'MUSIC_PAGE_TYPE_TRACK_RELATED');
- const BrowseType({
+ const MusicType({
required this.name,
});
final String name;
}
-extension BrowseTypeExtension on BrowseType {
+extension MusicTypeExtension on MusicType {
static bool isThereAny(String? type) {
- if (type == BrowseType.musicVideoTypeAtv.name ||
- type == BrowseType.musicVideoTypeOmv.name ||
- type == BrowseType.musicPageTypeAlbum.name ||
- // type == BrowseType.musicPageTypeArtist.name ||
- type == BrowseType.musicPageTypePlaylist.name) {
+ if (type == MusicType.musicVideoTypeAtv.name ||
+ // type == BrowseType.musicVideoTypeOmv.name ||
+ type == MusicType.musicPageTypeAlbum.name ||
+ type == MusicType.musicPageTypePlaylist.name
+ // type == BrowseType.musicPageTypeArtist.name
+ ) {
return true;
} else {
return false;
diff --git a/lib/data/models/browse_group_model.dart b/lib/data/models/browse_group_model.dart
new file mode 100644
index 0000000..ab2ab43
--- /dev/null
+++ b/lib/data/models/browse_group_model.dart
@@ -0,0 +1,35 @@
+// Author: fengshengxiong
+// Date: 2024/6/20
+// Description: Browse分组模型
+
+import 'dart:convert';
+
+import 'package:tone_snap/data/models/music_model.dart';
+
+class BrowseGroupModel {
+ String? groupTitle;
+ String? musicType;
+ List? browseList;
+
+ BrowseGroupModel({
+ this.groupTitle,
+ this.musicType,
+ this.browseList,
+ });
+
+ factory BrowseGroupModel.fromJson(String str) => BrowseGroupModel.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory BrowseGroupModel.fromMap(Map json) => BrowseGroupModel(
+ groupTitle: json["groupTitle"],
+ musicType: json["musicType"],
+ browseList: json["browseList"] == null ? [] : List.from(json["browseList"]!.map((x) => MusicModel.fromMap(x))),
+ );
+
+ Map toMap() => {
+ "groupTitle": groupTitle,
+ "musicType": musicType,
+ "browseList": browseList == null ? [] : List.from(browseList!.map((x) => x.toMap())),
+ };
+}
diff --git a/lib/data/models/browse_model.dart b/lib/data/models/browse_model.dart
index cbae2e8..3d14b81 100644
--- a/lib/data/models/browse_model.dart
+++ b/lib/data/models/browse_model.dart
@@ -9,6 +9,7 @@ class BrowseModel {
Contents? contents;
ContinuationContents? continuationContents;
String? trackingParams;
+ Microformat? microformat;
int? maxAgeStoreSeconds;
ThumbnailClass? background;
@@ -146,9 +147,11 @@ class ThumbnailElement {
class Contents {
SingleColumnBrowseResultsRenderer? singleColumnBrowseResultsRenderer;
+ TwoColumnBrowseResultsRenderer? twoColumnBrowseResultsRenderer;
Contents({
this.singleColumnBrowseResultsRenderer,
+ this.twoColumnBrowseResultsRenderer,
});
factory Contents.fromJson(String str) => Contents.fromMap(json.decode(str));
@@ -157,10 +160,12 @@ class Contents {
factory Contents.fromMap(Map json) => Contents(
singleColumnBrowseResultsRenderer: json["singleColumnBrowseResultsRenderer"] == null ? null : SingleColumnBrowseResultsRenderer.fromMap(json["singleColumnBrowseResultsRenderer"]),
+ twoColumnBrowseResultsRenderer: json["twoColumnBrowseResultsRenderer"] == null ? null : TwoColumnBrowseResultsRenderer.fromMap(json["twoColumnBrowseResultsRenderer"]),
);
Map toMap() => {
"singleColumnBrowseResultsRenderer": singleColumnBrowseResultsRenderer?.toMap(),
+ "twoColumnBrowseResultsRenderer": twoColumnBrowseResultsRenderer?.toMap(),
};
}
@@ -303,10 +308,12 @@ class SectionList {
class SectionListContinuationContent {
MusicCarouselShelfRenderer? musicCarouselShelfRenderer;
MusicTastebuilderShelfRenderer? musicTastebuilderShelfRenderer;
+ MusicResponsiveHeaderRenderer? musicResponsiveHeaderRenderer;
SectionListContinuationContent({
this.musicCarouselShelfRenderer,
this.musicTastebuilderShelfRenderer,
+ this.musicResponsiveHeaderRenderer,
});
factory SectionListContinuationContent.fromJson(String str) => SectionListContinuationContent.fromMap(json.decode(str));
@@ -316,11 +323,13 @@ class SectionListContinuationContent {
factory SectionListContinuationContent.fromMap(Map json) => SectionListContinuationContent(
musicCarouselShelfRenderer: json["musicCarouselShelfRenderer"] == null ? null : MusicCarouselShelfRenderer.fromMap(json["musicCarouselShelfRenderer"]),
musicTastebuilderShelfRenderer: json["musicTastebuilderShelfRenderer"] == null ? null : MusicTastebuilderShelfRenderer.fromMap(json["musicTastebuilderShelfRenderer"]),
+ musicResponsiveHeaderRenderer: json["musicResponsiveHeaderRenderer"] == null ? null : MusicResponsiveHeaderRenderer.fromMap(json["musicResponsiveHeaderRenderer"]),
);
Map toMap() => {
"musicCarouselShelfRenderer": musicCarouselShelfRenderer?.toMap(),
"musicTastebuilderShelfRenderer": musicTastebuilderShelfRenderer?.toMap(),
+ "musicResponsiveHeaderRenderer": musicResponsiveHeaderRenderer?.toMap(),
};
}
@@ -389,6 +398,7 @@ class MusicResponsiveListItemRenderer {
ThumbnailClass? thumbnail;
Overlay? overlay;
List? flexColumns;
+ List? fixedColumns;
MusicResponsiveListItemRendererMenu? menu;
PlaylistItemData? playlistItemData;
String? flexColumnDisplayStyle;
@@ -399,6 +409,7 @@ class MusicResponsiveListItemRenderer {
this.thumbnail,
this.overlay,
this.flexColumns,
+ this.fixedColumns,
this.menu,
this.playlistItemData,
this.flexColumnDisplayStyle,
@@ -414,6 +425,7 @@ class MusicResponsiveListItemRenderer {
thumbnail: json["thumbnail"] == null ? null : ThumbnailClass.fromMap(json["thumbnail"]),
overlay: json["overlay"] == null ? null : Overlay.fromMap(json["overlay"]),
flexColumns: json["flexColumns"] == null ? [] : List.from(json["flexColumns"]!.map((x) => FlexColumn.fromMap(x))),
+ fixedColumns: json["fixedColumns"] == null ? [] : List.from(json["fixedColumns"]!.map((x) => FixedColumn.fromMap(x))),
menu: json["menu"] == null ? null : MusicResponsiveListItemRendererMenu.fromMap(json["menu"]),
playlistItemData: json["playlistItemData"] == null ? null : PlaylistItemData.fromMap(json["playlistItemData"]),
flexColumnDisplayStyle: json["flexColumnDisplayStyle"],
@@ -425,6 +437,7 @@ class MusicResponsiveListItemRenderer {
"thumbnail": thumbnail?.toMap(),
"overlay": overlay?.toMap(),
"flexColumns": flexColumns == null ? [] : List.from(flexColumns!.map((x) => x.toMap())),
+ "fixedColumns": fixedColumns == null ? [] : List.from(fixedColumns!.map((x) => x.toMap())),
"menu": menu?.toMap(),
"playlistItemData": playlistItemData?.toMap(),
"flexColumnDisplayStyle": flexColumnDisplayStyle,
@@ -1706,9 +1719,13 @@ class VerticalGradient {
class PurpleContent {
PurpleMusicPlayButtonRenderer? musicPlayButtonRenderer;
+ MusicShelfRenderer? musicShelfRenderer;
+ MusicPlaylistShelfRenderer? musicPlaylistShelfRenderer;
PurpleContent({
this.musicPlayButtonRenderer,
+ this.musicShelfRenderer,
+ this.musicPlaylistShelfRenderer,
});
factory PurpleContent.fromJson(String str) => PurpleContent.fromMap(json.decode(str));
@@ -1717,10 +1734,14 @@ class PurpleContent {
factory PurpleContent.fromMap(Map json) => PurpleContent(
musicPlayButtonRenderer: json["musicPlayButtonRenderer"] == null ? null : PurpleMusicPlayButtonRenderer.fromMap(json["musicPlayButtonRenderer"]),
+ musicShelfRenderer: json["musicShelfRenderer"] == null ? null : MusicShelfRenderer.fromMap(json["musicShelfRenderer"]),
+ musicPlaylistShelfRenderer: json["musicPlaylistShelfRenderer"] == null ? null : MusicPlaylistShelfRenderer.fromMap(json["musicPlaylistShelfRenderer"]),
);
Map toMap() => {
"musicPlayButtonRenderer": musicPlayButtonRenderer?.toMap(),
+ "musicShelfRenderer": musicShelfRenderer?.toMap(),
+ "musicPlaylistShelfRenderer": musicPlaylistShelfRenderer?.toMap(),
};
}
@@ -3027,3 +3048,1419 @@ class Param {
"value": value,
};
}
+
+class TwoColumnBrowseResultsRenderer {
+ SecondaryContents? secondaryContents;
+ List? tabs;
+
+ TwoColumnBrowseResultsRenderer({
+ this.secondaryContents,
+ this.tabs,
+ });
+
+ factory TwoColumnBrowseResultsRenderer.fromJson(String str) => TwoColumnBrowseResultsRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory TwoColumnBrowseResultsRenderer.fromMap(Map json) => TwoColumnBrowseResultsRenderer(
+ secondaryContents: json["secondaryContents"] == null ? null : SecondaryContents.fromMap(json["secondaryContents"]),
+ tabs: json["tabs"] == null ? [] : List.from(json["tabs"]!.map((x) => Tab.fromMap(x))),
+ );
+
+ Map toMap() => {
+ "secondaryContents": secondaryContents?.toMap(),
+ "tabs": tabs == null ? [] : List.from(tabs!.map((x) => x.toMap())),
+ };
+}
+
+class SecondaryContents {
+ SecondaryContentsSectionListRenderer? sectionListRenderer;
+
+ SecondaryContents({
+ this.sectionListRenderer,
+ });
+
+ factory SecondaryContents.fromJson(String str) => SecondaryContents.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory SecondaryContents.fromMap(Map json) => SecondaryContents(
+ sectionListRenderer: json["sectionListRenderer"] == null ? null : SecondaryContentsSectionListRenderer.fromMap(json["sectionListRenderer"]),
+ );
+
+ Map toMap() => {
+ "sectionListRenderer": sectionListRenderer?.toMap(),
+ };
+}
+
+class SecondaryContentsSectionListRenderer {
+ List? contents;
+ String? trackingParams;
+
+ SecondaryContentsSectionListRenderer({
+ this.contents,
+ this.trackingParams,
+ });
+
+ factory SecondaryContentsSectionListRenderer.fromJson(String str) => SecondaryContentsSectionListRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory SecondaryContentsSectionListRenderer.fromMap(Map json) => SecondaryContentsSectionListRenderer(
+ contents: json["contents"] == null ? [] : List.from(json["contents"]!.map((x) => PurpleContent.fromMap(x))),
+ trackingParams: json["trackingParams"],
+ );
+
+ Map toMap() => {
+ "contents": contents == null ? [] : List.from(contents!.map((x) => x.toMap())),
+ "trackingParams": trackingParams,
+ };
+}
+
+class MusicShelfRenderer {
+ List? contents;
+ String? trackingParams;
+ ShelfDivider? shelfDivider;
+ bool? contentsMultiSelectable;
+
+ MusicShelfRenderer({
+ this.contents,
+ this.trackingParams,
+ this.shelfDivider,
+ this.contentsMultiSelectable,
+ });
+
+ factory MusicShelfRenderer.fromJson(String str) => MusicShelfRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MusicShelfRenderer.fromMap(Map json) => MusicShelfRenderer(
+ contents: json["contents"] == null ? [] : List.from(json["contents"]!.map((x) => MusicShelfRendererContent.fromMap(x))),
+ trackingParams: json["trackingParams"],
+ shelfDivider: json["shelfDivider"] == null ? null : ShelfDivider.fromMap(json["shelfDivider"]),
+ contentsMultiSelectable: json["contentsMultiSelectable"],
+ );
+
+ Map toMap() => {
+ "contents": contents == null ? [] : List.from(contents!.map((x) => x.toMap())),
+ "trackingParams": trackingParams,
+ "shelfDivider": shelfDivider?.toMap(),
+ "contentsMultiSelectable": contentsMultiSelectable,
+ };
+}
+
+class MusicShelfRendererContent {
+ MusicResponsiveListItemRenderer? musicResponsiveListItemRenderer;
+
+ MusicShelfRendererContent({
+ this.musicResponsiveListItemRenderer,
+ });
+
+ factory MusicShelfRendererContent.fromJson(String str) => MusicShelfRendererContent.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MusicShelfRendererContent.fromMap(Map json) => MusicShelfRendererContent(
+ musicResponsiveListItemRenderer: json["musicResponsiveListItemRenderer"] == null ? null : MusicResponsiveListItemRenderer.fromMap(json["musicResponsiveListItemRenderer"]),
+ );
+
+ Map toMap() => {
+ "musicResponsiveListItemRenderer": musicResponsiveListItemRenderer?.toMap(),
+ };
+}
+
+class FixedColumn {
+ MusicResponsiveListItemFixedColumnRenderer? musicResponsiveListItemFixedColumnRenderer;
+
+ FixedColumn({
+ this.musicResponsiveListItemFixedColumnRenderer,
+ });
+
+ factory FixedColumn.fromJson(String str) => FixedColumn.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory FixedColumn.fromMap(Map json) => FixedColumn(
+ musicResponsiveListItemFixedColumnRenderer: json["musicResponsiveListItemFixedColumnRenderer"] == null ? null : MusicResponsiveListItemFixedColumnRenderer.fromMap(json["musicResponsiveListItemFixedColumnRenderer"]),
+ );
+
+ Map toMap() => {
+ "musicResponsiveListItemFixedColumnRenderer": musicResponsiveListItemFixedColumnRenderer?.toMap(),
+ };
+}
+
+class MusicResponsiveListItemFixedColumnRenderer {
+ Index? text;
+ String? displayPriority;
+ String? size;
+
+ MusicResponsiveListItemFixedColumnRenderer({
+ this.text,
+ this.displayPriority,
+ this.size,
+ });
+
+ factory MusicResponsiveListItemFixedColumnRenderer.fromJson(String str) => MusicResponsiveListItemFixedColumnRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MusicResponsiveListItemFixedColumnRenderer.fromMap(Map json) => MusicResponsiveListItemFixedColumnRenderer(
+ text: json["text"] == null ? null : Index.fromMap(json["text"]),
+ displayPriority: json["displayPriority"],
+ size: json["size"],
+ );
+
+ Map toMap() => {
+ "text": text?.toMap(),
+ "displayPriority": displayPriority,
+ "size": size,
+ };
+}
+
+class Index {
+ List? runs;
+
+ Index({
+ this.runs,
+ });
+
+ factory Index.fromJson(String str) => Index.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory Index.fromMap(Map json) => Index(
+ runs: json["runs"] == null ? [] : List.from(json["runs"]!.map((x) => IndexRun.fromMap(x))),
+ );
+
+ Map toMap() => {
+ "runs": runs == null ? [] : List.from(runs!.map((x) => x.toMap())),
+ };
+}
+
+class IndexRun {
+ String? text;
+
+ IndexRun({
+ this.text,
+ });
+
+ factory IndexRun.fromJson(String str) => IndexRun.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory IndexRun.fromMap(Map json) => IndexRun(
+ text: json["text"],
+ );
+
+ Map toMap() => {
+ "text": text,
+ };
+}
+
+class NavigationEndpoint {
+ String? clickTrackingParams;
+ PlayNavigationEndpointWatchEndpoint? watchEndpoint;
+
+ NavigationEndpoint({
+ this.clickTrackingParams,
+ this.watchEndpoint,
+ });
+
+ factory NavigationEndpoint.fromJson(String str) => NavigationEndpoint.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory NavigationEndpoint.fromMap(Map json) => NavigationEndpoint(
+ clickTrackingParams: json["clickTrackingParams"],
+ watchEndpoint: json["watchEndpoint"] == null ? null : PlayNavigationEndpointWatchEndpoint.fromMap(json["watchEndpoint"]),
+ );
+
+ Map toMap() => {
+ "clickTrackingParams": clickTrackingParams,
+ "watchEndpoint": watchEndpoint?.toMap(),
+ };
+}
+
+class PlayNavigationEndpointWatchEndpoint {
+ String? videoId;
+ String? playlistId;
+ LoggingContext? loggingContext;
+ WatchEndpointMusicSupportedConfigs? watchEndpointMusicSupportedConfigs;
+ String? params;
+ int? index;
+
+ PlayNavigationEndpointWatchEndpoint({
+ this.videoId,
+ this.playlistId,
+ this.loggingContext,
+ this.watchEndpointMusicSupportedConfigs,
+ this.params,
+ this.index,
+ });
+
+ factory PlayNavigationEndpointWatchEndpoint.fromJson(String str) => PlayNavigationEndpointWatchEndpoint.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory PlayNavigationEndpointWatchEndpoint.fromMap(Map json) => PlayNavigationEndpointWatchEndpoint(
+ videoId: json["videoId"],
+ playlistId: json["playlistId"],
+ loggingContext: json["loggingContext"] == null ? null : LoggingContext.fromMap(json["loggingContext"]),
+ watchEndpointMusicSupportedConfigs: json["watchEndpointMusicSupportedConfigs"] == null ? null : WatchEndpointMusicSupportedConfigs.fromMap(json["watchEndpointMusicSupportedConfigs"]),
+ params: json["params"],
+ index: json["index"],
+ );
+
+ Map toMap() => {
+ "videoId": videoId,
+ "playlistId": playlistId,
+ "loggingContext": loggingContext?.toMap(),
+ "watchEndpointMusicSupportedConfigs": watchEndpointMusicSupportedConfigs?.toMap(),
+ "params": params,
+ "index": index,
+ };
+}
+
+class Menu {
+ MenuMenuRenderer? menuRenderer;
+
+ Menu({
+ this.menuRenderer,
+ });
+
+ factory Menu.fromJson(String str) => Menu.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory Menu.fromMap(Map json) => Menu(
+ menuRenderer: json["menuRenderer"] == null ? null : MenuMenuRenderer.fromMap(json["menuRenderer"]),
+ );
+
+ Map toMap() => {
+ "menuRenderer": menuRenderer?.toMap(),
+ };
+}
+
+class MenuMenuRenderer {
+ List? items;
+ String? trackingParams;
+ List? topLevelButtons;
+ Accessibility? accessibility;
+
+ MenuMenuRenderer({
+ this.items,
+ this.trackingParams,
+ this.topLevelButtons,
+ this.accessibility,
+ });
+
+ factory MenuMenuRenderer.fromJson(String str) => MenuMenuRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MenuMenuRenderer.fromMap(Map json) => MenuMenuRenderer(
+ items: json["items"] == null ? [] : List.from(json["items"]!.map((x) => PurpleItem.fromMap(x))),
+ trackingParams: json["trackingParams"],
+ topLevelButtons: json["topLevelButtons"] == null ? [] : List.from(json["topLevelButtons"]!.map((x) => TopLevelButton.fromMap(x))),
+ accessibility: json["accessibility"] == null ? null : Accessibility.fromMap(json["accessibility"]),
+ );
+
+ Map toMap() => {
+ "items": items == null ? [] : List.from(items!.map((x) => x.toMap())),
+ "trackingParams": trackingParams,
+ "topLevelButtons": topLevelButtons == null ? [] : List.from(topLevelButtons!.map((x) => x.toMap())),
+ "accessibility": accessibility?.toMap(),
+ };
+}
+
+class BrowseEndpoint {
+ String? browseId;
+ BrowseEndpointContextSupportedConfigs? browseEndpointContextSupportedConfigs;
+
+ BrowseEndpoint({
+ this.browseId,
+ this.browseEndpointContextSupportedConfigs,
+ });
+
+ factory BrowseEndpoint.fromJson(String str) => BrowseEndpoint.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory BrowseEndpoint.fromMap(Map json) => BrowseEndpoint(
+ browseId: json["browseId"],
+ browseEndpointContextSupportedConfigs: json["browseEndpointContextSupportedConfigs"] == null ? null : BrowseEndpointContextSupportedConfigs.fromMap(json["browseEndpointContextSupportedConfigs"]),
+ );
+
+ Map toMap() => {
+ "browseId": browseId,
+ "browseEndpointContextSupportedConfigs": browseEndpointContextSupportedConfigs?.toMap(),
+ };
+}
+
+class ModalWithTitleAndButtonRendererButton {
+ ButtonRenderer? buttonRenderer;
+
+ ModalWithTitleAndButtonRendererButton({
+ this.buttonRenderer,
+ });
+
+ factory ModalWithTitleAndButtonRendererButton.fromJson(String str) => ModalWithTitleAndButtonRendererButton.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory ModalWithTitleAndButtonRendererButton.fromMap(Map json) => ModalWithTitleAndButtonRendererButton(
+ buttonRenderer: json["buttonRenderer"] == null ? null : ButtonRenderer.fromMap(json["buttonRenderer"]),
+ );
+
+ Map toMap() => {
+ "buttonRenderer": buttonRenderer?.toMap(),
+ };
+}
+
+class ButtonRenderer {
+ String? style;
+ bool? isDisabled;
+ Index? text;
+ ButtonRendererNavigationEndpoint? navigationEndpoint;
+ String? trackingParams;
+
+ ButtonRenderer({
+ this.style,
+ this.isDisabled,
+ this.text,
+ this.navigationEndpoint,
+ this.trackingParams,
+ });
+
+ factory ButtonRenderer.fromJson(String str) => ButtonRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory ButtonRenderer.fromMap(Map json) => ButtonRenderer(
+ style: json["style"],
+ isDisabled: json["isDisabled"],
+ text: json["text"] == null ? null : Index.fromMap(json["text"]),
+ navigationEndpoint: json["navigationEndpoint"] == null ? null : ButtonRendererNavigationEndpoint.fromMap(json["navigationEndpoint"]),
+ trackingParams: json["trackingParams"],
+ );
+
+ Map toMap() => {
+ "style": style,
+ "isDisabled": isDisabled,
+ "text": text?.toMap(),
+ "navigationEndpoint": navigationEndpoint?.toMap(),
+ "trackingParams": trackingParams,
+ };
+}
+
+class ButtonRendererNavigationEndpoint {
+ String? clickTrackingParams;
+ SignInEndpoint? signInEndpoint;
+
+ ButtonRendererNavigationEndpoint({
+ this.clickTrackingParams,
+ this.signInEndpoint,
+ });
+
+ factory ButtonRendererNavigationEndpoint.fromJson(String str) => ButtonRendererNavigationEndpoint.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory ButtonRendererNavigationEndpoint.fromMap(Map json) => ButtonRendererNavigationEndpoint(
+ clickTrackingParams: json["clickTrackingParams"],
+ signInEndpoint: json["signInEndpoint"] == null ? null : SignInEndpoint.fromMap(json["signInEndpoint"]),
+ );
+
+ Map toMap() => {
+ "clickTrackingParams": clickTrackingParams,
+ "signInEndpoint": signInEndpoint?.toMap(),
+ };
+}
+
+class DefaultNavigationEndpoint {
+ String? clickTrackingParams;
+ ModalEndpoint? modalEndpoint;
+
+ DefaultNavigationEndpoint({
+ this.clickTrackingParams,
+ this.modalEndpoint,
+ });
+
+ factory DefaultNavigationEndpoint.fromJson(String str) => DefaultNavigationEndpoint.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory DefaultNavigationEndpoint.fromMap(Map json) => DefaultNavigationEndpoint(
+ clickTrackingParams: json["clickTrackingParams"],
+ modalEndpoint: json["modalEndpoint"] == null ? null : ModalEndpoint.fromMap(json["modalEndpoint"]),
+ );
+
+ Map toMap() => {
+ "clickTrackingParams": clickTrackingParams,
+ "modalEndpoint": modalEndpoint?.toMap(),
+ };
+}
+
+class LikeButtonRendererTarget {
+ String? videoId;
+
+ LikeButtonRendererTarget({
+ this.videoId,
+ });
+
+ factory LikeButtonRendererTarget.fromJson(String str) => LikeButtonRendererTarget.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory LikeButtonRendererTarget.fromMap(Map json) => LikeButtonRendererTarget(
+ videoId: json["videoId"],
+ );
+
+ Map toMap() => {
+ "videoId": videoId,
+ };
+}
+
+class MultiSelectCheckbox {
+ CheckboxRenderer? checkboxRenderer;
+
+ MultiSelectCheckbox({
+ this.checkboxRenderer,
+ });
+
+ factory MultiSelectCheckbox.fromJson(String str) => MultiSelectCheckbox.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MultiSelectCheckbox.fromMap(Map json) => MultiSelectCheckbox(
+ checkboxRenderer: json["checkboxRenderer"] == null ? null : CheckboxRenderer.fromMap(json["checkboxRenderer"]),
+ );
+
+ Map toMap() => {
+ "checkboxRenderer": checkboxRenderer?.toMap(),
+ };
+}
+
+class CheckboxRenderer {
+ OnSelectionChangeCommand? onSelectionChangeCommand;
+ String? checkedState;
+ String? trackingParams;
+
+ CheckboxRenderer({
+ this.onSelectionChangeCommand,
+ this.checkedState,
+ this.trackingParams,
+ });
+
+ factory CheckboxRenderer.fromJson(String str) => CheckboxRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory CheckboxRenderer.fromMap(Map json) => CheckboxRenderer(
+ onSelectionChangeCommand: json["onSelectionChangeCommand"] == null ? null : OnSelectionChangeCommand.fromMap(json["onSelectionChangeCommand"]),
+ checkedState: json["checkedState"],
+ trackingParams: json["trackingParams"],
+ );
+
+ Map toMap() => {
+ "onSelectionChangeCommand": onSelectionChangeCommand?.toMap(),
+ "checkedState": checkedState,
+ "trackingParams": trackingParams,
+ };
+}
+
+class OnSelectionChangeCommand {
+ String? clickTrackingParams;
+ UpdateMultiSelectStateCommand? updateMultiSelectStateCommand;
+
+ OnSelectionChangeCommand({
+ this.clickTrackingParams,
+ this.updateMultiSelectStateCommand,
+ });
+
+ factory OnSelectionChangeCommand.fromJson(String str) => OnSelectionChangeCommand.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory OnSelectionChangeCommand.fromMap(Map json) => OnSelectionChangeCommand(
+ clickTrackingParams: json["clickTrackingParams"],
+ updateMultiSelectStateCommand: json["updateMultiSelectStateCommand"] == null ? null : UpdateMultiSelectStateCommand.fromMap(json["updateMultiSelectStateCommand"]),
+ );
+
+ Map toMap() => {
+ "clickTrackingParams": clickTrackingParams,
+ "updateMultiSelectStateCommand": updateMultiSelectStateCommand?.toMap(),
+ };
+}
+
+class UpdateMultiSelectStateCommand {
+ String? multiSelectParams;
+ String? multiSelectItem;
+
+ UpdateMultiSelectStateCommand({
+ this.multiSelectParams,
+ this.multiSelectItem,
+ });
+
+ factory UpdateMultiSelectStateCommand.fromJson(String str) => UpdateMultiSelectStateCommand.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory UpdateMultiSelectStateCommand.fromMap(Map json) => UpdateMultiSelectStateCommand(
+ multiSelectParams: json["multiSelectParams"],
+ multiSelectItem: json["multiSelectItem"],
+ );
+
+ Map toMap() => {
+ "multiSelectParams": multiSelectParams,
+ "multiSelectItem": multiSelectItem,
+ };
+}
+
+class MusicItemThumbnailOverlayRenderer {
+ Background? background;
+ MusicItemThumbnailOverlayRendererContent? content;
+ String? contentPosition;
+ String? displayStyle;
+
+ MusicItemThumbnailOverlayRenderer({
+ this.background,
+ this.content,
+ this.contentPosition,
+ this.displayStyle,
+ });
+
+ factory MusicItemThumbnailOverlayRenderer.fromJson(String str) => MusicItemThumbnailOverlayRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MusicItemThumbnailOverlayRenderer.fromMap(Map json) => MusicItemThumbnailOverlayRenderer(
+ background: json["background"] == null ? null : Background.fromMap(json["background"]),
+ content: json["content"] == null ? null : MusicItemThumbnailOverlayRendererContent.fromMap(json["content"]),
+ contentPosition: json["contentPosition"],
+ displayStyle: json["displayStyle"],
+ );
+
+ Map toMap() => {
+ "background": background?.toMap(),
+ "content": content?.toMap(),
+ "contentPosition": contentPosition,
+ "displayStyle": displayStyle,
+ };
+}
+
+class Background {
+ VerticalGradient? verticalGradient;
+
+ Background({
+ this.verticalGradient,
+ });
+
+ factory Background.fromJson(String str) => Background.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory Background.fromMap(Map json) => Background(
+ verticalGradient: json["verticalGradient"] == null ? null : VerticalGradient.fromMap(json["verticalGradient"]),
+ );
+
+ Map toMap() => {
+ "verticalGradient": verticalGradient?.toMap(),
+ };
+}
+
+class MusicItemThumbnailOverlayRendererContent {
+ ContentMusicPlayButtonRenderer? musicPlayButtonRenderer;
+
+ MusicItemThumbnailOverlayRendererContent({
+ this.musicPlayButtonRenderer,
+ });
+
+ factory MusicItemThumbnailOverlayRendererContent.fromJson(String str) => MusicItemThumbnailOverlayRendererContent.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MusicItemThumbnailOverlayRendererContent.fromMap(Map json) => MusicItemThumbnailOverlayRendererContent(
+ musicPlayButtonRenderer: json["musicPlayButtonRenderer"] == null ? null : ContentMusicPlayButtonRenderer.fromMap(json["musicPlayButtonRenderer"]),
+ );
+
+ Map toMap() => {
+ "musicPlayButtonRenderer": musicPlayButtonRenderer?.toMap(),
+ };
+}
+
+class ContentMusicPlayButtonRenderer {
+ NavigationEndpoint? playNavigationEndpoint;
+ String? trackingParams;
+ Icon? playIcon;
+ Icon? pauseIcon;
+ int? iconColor;
+ int? backgroundColor;
+ int? activeBackgroundColor;
+ int? loadingIndicatorColor;
+ Icon? playingIcon;
+ int? iconLoadingColor;
+ int? activeScaleFactor;
+ String? buttonSize;
+ String? rippleTarget;
+ Accessibility? accessibilityPlayData;
+ Accessibility? accessibilityPauseData;
+
+ ContentMusicPlayButtonRenderer({
+ this.playNavigationEndpoint,
+ this.trackingParams,
+ this.playIcon,
+ this.pauseIcon,
+ this.iconColor,
+ this.backgroundColor,
+ this.activeBackgroundColor,
+ this.loadingIndicatorColor,
+ this.playingIcon,
+ this.iconLoadingColor,
+ this.activeScaleFactor,
+ this.buttonSize,
+ this.rippleTarget,
+ this.accessibilityPlayData,
+ this.accessibilityPauseData,
+ });
+
+ factory ContentMusicPlayButtonRenderer.fromJson(String str) => ContentMusicPlayButtonRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory ContentMusicPlayButtonRenderer.fromMap(Map json) => ContentMusicPlayButtonRenderer(
+ playNavigationEndpoint: json["playNavigationEndpoint"] == null ? null : NavigationEndpoint.fromMap(json["playNavigationEndpoint"]),
+ trackingParams: json["trackingParams"],
+ playIcon: json["playIcon"] == null ? null : Icon.fromMap(json["playIcon"]),
+ pauseIcon: json["pauseIcon"] == null ? null : Icon.fromMap(json["pauseIcon"]),
+ iconColor: json["iconColor"],
+ backgroundColor: json["backgroundColor"],
+ activeBackgroundColor: json["activeBackgroundColor"],
+ loadingIndicatorColor: json["loadingIndicatorColor"],
+ playingIcon: json["playingIcon"] == null ? null : Icon.fromMap(json["playingIcon"]),
+ iconLoadingColor: json["iconLoadingColor"],
+ activeScaleFactor: json["activeScaleFactor"],
+ buttonSize: json["buttonSize"],
+ rippleTarget: json["rippleTarget"],
+ accessibilityPlayData: json["accessibilityPlayData"] == null ? null : Accessibility.fromMap(json["accessibilityPlayData"]),
+ accessibilityPauseData: json["accessibilityPauseData"] == null ? null : Accessibility.fromMap(json["accessibilityPauseData"]),
+ );
+
+ Map toMap() => {
+ "playNavigationEndpoint": playNavigationEndpoint?.toMap(),
+ "trackingParams": trackingParams,
+ "playIcon": playIcon?.toMap(),
+ "pauseIcon": pauseIcon?.toMap(),
+ "iconColor": iconColor,
+ "backgroundColor": backgroundColor,
+ "activeBackgroundColor": activeBackgroundColor,
+ "loadingIndicatorColor": loadingIndicatorColor,
+ "playingIcon": playingIcon?.toMap(),
+ "iconLoadingColor": iconLoadingColor,
+ "activeScaleFactor": activeScaleFactor,
+ "buttonSize": buttonSize,
+ "rippleTarget": rippleTarget,
+ "accessibilityPlayData": accessibilityPlayData?.toMap(),
+ "accessibilityPauseData": accessibilityPauseData?.toMap(),
+ };
+}
+
+class ShelfDivider {
+ MusicShelfDividerRenderer? musicShelfDividerRenderer;
+
+ ShelfDivider({
+ this.musicShelfDividerRenderer,
+ });
+
+ factory ShelfDivider.fromJson(String str) => ShelfDivider.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory ShelfDivider.fromMap(Map json) => ShelfDivider(
+ musicShelfDividerRenderer: json["musicShelfDividerRenderer"] == null ? null : MusicShelfDividerRenderer.fromMap(json["musicShelfDividerRenderer"]),
+ );
+
+ Map toMap() => {
+ "musicShelfDividerRenderer": musicShelfDividerRenderer?.toMap(),
+ };
+}
+
+class MusicShelfDividerRenderer {
+ bool? hidden;
+
+ MusicShelfDividerRenderer({
+ this.hidden,
+ });
+
+ factory MusicShelfDividerRenderer.fromJson(String str) => MusicShelfDividerRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MusicShelfDividerRenderer.fromMap(Map json) => MusicShelfDividerRenderer(
+ hidden: json["hidden"],
+ );
+
+ Map toMap() => {
+ "hidden": hidden,
+ };
+}
+
+class ContentSectionListRenderer {
+ List? contents;
+ String? trackingParams;
+
+ ContentSectionListRenderer({
+ this.contents,
+ this.trackingParams,
+ });
+
+ factory ContentSectionListRenderer.fromJson(String str) => ContentSectionListRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory ContentSectionListRenderer.fromMap(Map json) => ContentSectionListRenderer(
+ contents: json["contents"] == null ? [] : List.from(json["contents"]!.map((x) => FluffyContent.fromMap(x))),
+ trackingParams: json["trackingParams"],
+ );
+
+ Map toMap() => {
+ "contents": contents == null ? [] : List.from(contents!.map((x) => x.toMap())),
+ "trackingParams": trackingParams,
+ };
+}
+
+class MusicResponsiveHeaderRenderer {
+ StraplineThumbnailClass? thumbnail;
+ List? buttons;
+ Index? title;
+ Index? subtitle;
+ String? trackingParams;
+ StraplineTextOne? straplineTextOne;
+ StraplineThumbnailClass? straplineThumbnail;
+ MusicResponsiveHeaderRendererDescription? description;
+ Index? secondSubtitle;
+
+ MusicResponsiveHeaderRenderer({
+ this.thumbnail,
+ this.buttons,
+ this.title,
+ this.subtitle,
+ this.trackingParams,
+ this.straplineTextOne,
+ this.straplineThumbnail,
+ this.description,
+ this.secondSubtitle,
+ });
+
+ factory MusicResponsiveHeaderRenderer.fromJson(String str) => MusicResponsiveHeaderRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MusicResponsiveHeaderRenderer.fromMap(Map json) => MusicResponsiveHeaderRenderer(
+ thumbnail: json["thumbnail"] == null ? null : StraplineThumbnailClass.fromMap(json["thumbnail"]),
+ buttons: json["buttons"] == null ? [] : List.from(json["buttons"]!.map((x) => ButtonElement.fromMap(x))),
+ title: json["title"] == null ? null : Index.fromMap(json["title"]),
+ subtitle: json["subtitle"] == null ? null : Index.fromMap(json["subtitle"]),
+ trackingParams: json["trackingParams"],
+ straplineTextOne: json["straplineTextOne"] == null ? null : StraplineTextOne.fromMap(json["straplineTextOne"]),
+ straplineThumbnail: json["straplineThumbnail"] == null ? null : StraplineThumbnailClass.fromMap(json["straplineThumbnail"]),
+ description: json["description"] == null ? null : MusicResponsiveHeaderRendererDescription.fromMap(json["description"]),
+ secondSubtitle: json["secondSubtitle"] == null ? null : Index.fromMap(json["secondSubtitle"]),
+ );
+
+ Map toMap() => {
+ "thumbnail": thumbnail?.toMap(),
+ "buttons": buttons == null ? [] : List.from(buttons!.map((x) => x.toMap())),
+ "title": title?.toMap(),
+ "subtitle": subtitle?.toMap(),
+ "trackingParams": trackingParams,
+ "straplineTextOne": straplineTextOne?.toMap(),
+ "straplineThumbnail": straplineThumbnail?.toMap(),
+ "description": description?.toMap(),
+ "secondSubtitle": secondSubtitle?.toMap(),
+ };
+}
+
+class ButtonElement {
+ ButtonToggleButtonRenderer? toggleButtonRenderer;
+ ButtonMusicPlayButtonRenderer? musicPlayButtonRenderer;
+ ButtonMenuRenderer? menuRenderer;
+
+ ButtonElement({
+ this.toggleButtonRenderer,
+ this.musicPlayButtonRenderer,
+ this.menuRenderer,
+ });
+
+ factory ButtonElement.fromJson(String str) => ButtonElement.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory ButtonElement.fromMap(Map json) => ButtonElement(
+ toggleButtonRenderer: json["toggleButtonRenderer"] == null ? null : ButtonToggleButtonRenderer.fromMap(json["toggleButtonRenderer"]),
+ musicPlayButtonRenderer: json["musicPlayButtonRenderer"] == null ? null : ButtonMusicPlayButtonRenderer.fromMap(json["musicPlayButtonRenderer"]),
+ menuRenderer: json["menuRenderer"] == null ? null : ButtonMenuRenderer.fromMap(json["menuRenderer"]),
+ );
+
+ Map toMap() => {
+ "toggleButtonRenderer": toggleButtonRenderer?.toMap(),
+ "musicPlayButtonRenderer": musicPlayButtonRenderer?.toMap(),
+ "menuRenderer": menuRenderer?.toMap(),
+ };
+}
+
+class ButtonMenuRenderer {
+ List? items;
+ String? trackingParams;
+ Accessibility? accessibility;
+
+ ButtonMenuRenderer({
+ this.items,
+ this.trackingParams,
+ this.accessibility,
+ });
+
+ factory ButtonMenuRenderer.fromJson(String str) => ButtonMenuRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory ButtonMenuRenderer.fromMap(Map json) => ButtonMenuRenderer(
+ items: json["items"] == null ? [] : List.from(json["items"]!.map((x) => FluffyItem.fromMap(x))),
+ trackingParams: json["trackingParams"],
+ accessibility: json["accessibility"] == null ? null : Accessibility.fromMap(json["accessibility"]),
+ );
+
+ Map toMap() => {
+ "items": items == null ? [] : List.from(items!.map((x) => x.toMap())),
+ "trackingParams": trackingParams,
+ "accessibility": accessibility?.toMap(),
+ };
+}
+
+class ToggleMenuServiceItemRenderer {
+ Index? defaultText;
+ Icon? defaultIcon;
+ DefaultNavigationEndpoint? defaultServiceEndpoint;
+ Index? toggledText;
+ Icon? toggledIcon;
+ ToggledServiceEndpoint? toggledServiceEndpoint;
+ String? trackingParams;
+
+ ToggleMenuServiceItemRenderer({
+ this.defaultText,
+ this.defaultIcon,
+ this.defaultServiceEndpoint,
+ this.toggledText,
+ this.toggledIcon,
+ this.toggledServiceEndpoint,
+ this.trackingParams,
+ });
+
+ factory ToggleMenuServiceItemRenderer.fromJson(String str) => ToggleMenuServiceItemRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory ToggleMenuServiceItemRenderer.fromMap(Map json) => ToggleMenuServiceItemRenderer(
+ defaultText: json["defaultText"] == null ? null : Index.fromMap(json["defaultText"]),
+ defaultIcon: json["defaultIcon"] == null ? null : Icon.fromMap(json["defaultIcon"]),
+ defaultServiceEndpoint: json["defaultServiceEndpoint"] == null ? null : DefaultNavigationEndpoint.fromMap(json["defaultServiceEndpoint"]),
+ toggledText: json["toggledText"] == null ? null : Index.fromMap(json["toggledText"]),
+ toggledIcon: json["toggledIcon"] == null ? null : Icon.fromMap(json["toggledIcon"]),
+ toggledServiceEndpoint: json["toggledServiceEndpoint"] == null ? null : ToggledServiceEndpoint.fromMap(json["toggledServiceEndpoint"]),
+ trackingParams: json["trackingParams"],
+ );
+
+ Map toMap() => {
+ "defaultText": defaultText?.toMap(),
+ "defaultIcon": defaultIcon?.toMap(),
+ "defaultServiceEndpoint": defaultServiceEndpoint?.toMap(),
+ "toggledText": toggledText?.toMap(),
+ "toggledIcon": toggledIcon?.toMap(),
+ "toggledServiceEndpoint": toggledServiceEndpoint?.toMap(),
+ "trackingParams": trackingParams,
+ };
+}
+
+class ToggledServiceEndpoint {
+ String? clickTrackingParams;
+ LikeEndpoint? likeEndpoint;
+
+ ToggledServiceEndpoint({
+ this.clickTrackingParams,
+ this.likeEndpoint,
+ });
+
+ factory ToggledServiceEndpoint.fromJson(String str) => ToggledServiceEndpoint.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory ToggledServiceEndpoint.fromMap(Map json) => ToggledServiceEndpoint(
+ clickTrackingParams: json["clickTrackingParams"],
+ likeEndpoint: json["likeEndpoint"] == null ? null : LikeEndpoint.fromMap(json["likeEndpoint"]),
+ );
+
+ Map toMap() => {
+ "clickTrackingParams": clickTrackingParams,
+ "likeEndpoint": likeEndpoint?.toMap(),
+ };
+}
+
+class LikeEndpointTarget {
+ String? playlistId;
+
+ LikeEndpointTarget({
+ this.playlistId,
+ });
+
+ factory LikeEndpointTarget.fromJson(String str) => LikeEndpointTarget.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory LikeEndpointTarget.fromMap(Map json) => LikeEndpointTarget(
+ playlistId: json["playlistId"],
+ );
+
+ Map toMap() => {
+ "playlistId": playlistId,
+ };
+}
+
+class ButtonMusicPlayButtonRenderer {
+ NavigationEndpoint? playNavigationEndpoint;
+ String? trackingParams;
+ Icon? playIcon;
+ Icon? pauseIcon;
+ int? iconColor;
+ int? backgroundColor;
+ int? activeBackgroundColor;
+ int? loadingIndicatorColor;
+ Icon? playingIcon;
+ int? iconLoadingColor;
+ int? activeScaleFactor;
+ Accessibility? accessibilityPlayData;
+ Accessibility? accessibilityPauseData;
+
+ ButtonMusicPlayButtonRenderer({
+ this.playNavigationEndpoint,
+ this.trackingParams,
+ this.playIcon,
+ this.pauseIcon,
+ this.iconColor,
+ this.backgroundColor,
+ this.activeBackgroundColor,
+ this.loadingIndicatorColor,
+ this.playingIcon,
+ this.iconLoadingColor,
+ this.activeScaleFactor,
+ this.accessibilityPlayData,
+ this.accessibilityPauseData,
+ });
+
+ factory ButtonMusicPlayButtonRenderer.fromJson(String str) => ButtonMusicPlayButtonRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory ButtonMusicPlayButtonRenderer.fromMap(Map json) => ButtonMusicPlayButtonRenderer(
+ playNavigationEndpoint: json["playNavigationEndpoint"] == null ? null : NavigationEndpoint.fromMap(json["playNavigationEndpoint"]),
+ trackingParams: json["trackingParams"],
+ playIcon: json["playIcon"] == null ? null : Icon.fromMap(json["playIcon"]),
+ pauseIcon: json["pauseIcon"] == null ? null : Icon.fromMap(json["pauseIcon"]),
+ iconColor: json["iconColor"],
+ backgroundColor: json["backgroundColor"],
+ activeBackgroundColor: json["activeBackgroundColor"],
+ loadingIndicatorColor: json["loadingIndicatorColor"],
+ playingIcon: json["playingIcon"] == null ? null : Icon.fromMap(json["playingIcon"]),
+ iconLoadingColor: json["iconLoadingColor"],
+ activeScaleFactor: json["activeScaleFactor"],
+ accessibilityPlayData: json["accessibilityPlayData"] == null ? null : Accessibility.fromMap(json["accessibilityPlayData"]),
+ accessibilityPauseData: json["accessibilityPauseData"] == null ? null : Accessibility.fromMap(json["accessibilityPauseData"]),
+ );
+
+ Map toMap() => {
+ "playNavigationEndpoint": playNavigationEndpoint?.toMap(),
+ "trackingParams": trackingParams,
+ "playIcon": playIcon?.toMap(),
+ "pauseIcon": pauseIcon?.toMap(),
+ "iconColor": iconColor,
+ "backgroundColor": backgroundColor,
+ "activeBackgroundColor": activeBackgroundColor,
+ "loadingIndicatorColor": loadingIndicatorColor,
+ "playingIcon": playingIcon?.toMap(),
+ "iconLoadingColor": iconLoadingColor,
+ "activeScaleFactor": activeScaleFactor,
+ "accessibilityPlayData": accessibilityPlayData?.toMap(),
+ "accessibilityPauseData": accessibilityPauseData?.toMap(),
+ };
+}
+
+class ButtonToggleButtonRenderer {
+ bool? isToggled;
+ bool? isDisabled;
+ Icon? defaultIcon;
+ Icon? toggledIcon;
+ String? trackingParams;
+ DefaultNavigationEndpoint? defaultNavigationEndpoint;
+ Accessibility? accessibilityData;
+ Accessibility? toggledAccessibilityData;
+
+ ButtonToggleButtonRenderer({
+ this.isToggled,
+ this.isDisabled,
+ this.defaultIcon,
+ this.toggledIcon,
+ this.trackingParams,
+ this.defaultNavigationEndpoint,
+ this.accessibilityData,
+ this.toggledAccessibilityData,
+ });
+
+ factory ButtonToggleButtonRenderer.fromJson(String str) => ButtonToggleButtonRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory ButtonToggleButtonRenderer.fromMap(Map json) => ButtonToggleButtonRenderer(
+ isToggled: json["isToggled"],
+ isDisabled: json["isDisabled"],
+ defaultIcon: json["defaultIcon"] == null ? null : Icon.fromMap(json["defaultIcon"]),
+ toggledIcon: json["toggledIcon"] == null ? null : Icon.fromMap(json["toggledIcon"]),
+ trackingParams: json["trackingParams"],
+ defaultNavigationEndpoint: json["defaultNavigationEndpoint"] == null ? null : DefaultNavigationEndpoint.fromMap(json["defaultNavigationEndpoint"]),
+ accessibilityData: json["accessibilityData"] == null ? null : Accessibility.fromMap(json["accessibilityData"]),
+ toggledAccessibilityData: json["toggledAccessibilityData"] == null ? null : Accessibility.fromMap(json["toggledAccessibilityData"]),
+ );
+
+ Map toMap() => {
+ "isToggled": isToggled,
+ "isDisabled": isDisabled,
+ "defaultIcon": defaultIcon?.toMap(),
+ "toggledIcon": toggledIcon?.toMap(),
+ "trackingParams": trackingParams,
+ "defaultNavigationEndpoint": defaultNavigationEndpoint?.toMap(),
+ "accessibilityData": accessibilityData?.toMap(),
+ "toggledAccessibilityData": toggledAccessibilityData?.toMap(),
+ };
+}
+
+class MusicResponsiveHeaderRendererDescription {
+ MusicDescriptionShelfRenderer? musicDescriptionShelfRenderer;
+
+ MusicResponsiveHeaderRendererDescription({
+ this.musicDescriptionShelfRenderer,
+ });
+
+ factory MusicResponsiveHeaderRendererDescription.fromJson(String str) => MusicResponsiveHeaderRendererDescription.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MusicResponsiveHeaderRendererDescription.fromMap(Map json) => MusicResponsiveHeaderRendererDescription(
+ musicDescriptionShelfRenderer: json["musicDescriptionShelfRenderer"] == null ? null : MusicDescriptionShelfRenderer.fromMap(json["musicDescriptionShelfRenderer"]),
+ );
+
+ Map toMap() => {
+ "musicDescriptionShelfRenderer": musicDescriptionShelfRenderer?.toMap(),
+ };
+}
+
+class MusicDescriptionShelfRenderer {
+ MusicDescriptionShelfRendererDescription? description;
+ MoreButton? moreButton;
+ String? trackingParams;
+ String? shelfStyle;
+
+ MusicDescriptionShelfRenderer({
+ this.description,
+ this.moreButton,
+ this.trackingParams,
+ this.shelfStyle,
+ });
+
+ factory MusicDescriptionShelfRenderer.fromJson(String str) => MusicDescriptionShelfRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MusicDescriptionShelfRenderer.fromMap(Map json) => MusicDescriptionShelfRenderer(
+ description: json["description"] == null ? null : MusicDescriptionShelfRendererDescription.fromMap(json["description"]),
+ moreButton: json["moreButton"] == null ? null : MoreButton.fromMap(json["moreButton"]),
+ trackingParams: json["trackingParams"],
+ shelfStyle: json["shelfStyle"],
+ );
+
+ Map toMap() => {
+ "description": description?.toMap(),
+ "moreButton": moreButton?.toMap(),
+ "trackingParams": trackingParams,
+ "shelfStyle": shelfStyle,
+ };
+}
+
+class MusicDescriptionShelfRendererDescription {
+ List? runs;
+
+ MusicDescriptionShelfRendererDescription({
+ this.runs,
+ });
+
+ factory MusicDescriptionShelfRendererDescription.fromJson(String str) => MusicDescriptionShelfRendererDescription.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MusicDescriptionShelfRendererDescription.fromMap(Map json) => MusicDescriptionShelfRendererDescription(
+ runs: json["runs"] == null ? [] : List.from(json["runs"]!.map((x) => DescriptionRun.fromMap(x))),
+ );
+
+ Map toMap() => {
+ "runs": runs == null ? [] : List.from(runs!.map((x) => x.toMap())),
+ };
+}
+
+class DescriptionRun {
+ String? text;
+ PurpleNavigationEndpoint? navigationEndpoint;
+
+ DescriptionRun({
+ this.text,
+ this.navigationEndpoint,
+ });
+
+ factory DescriptionRun.fromJson(String str) => DescriptionRun.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory DescriptionRun.fromMap(Map json) => DescriptionRun(
+ text: json["text"],
+ navigationEndpoint: json["navigationEndpoint"] == null ? null : PurpleNavigationEndpoint.fromMap(json["navigationEndpoint"]),
+ );
+
+ Map toMap() => {
+ "text": text,
+ "navigationEndpoint": navigationEndpoint?.toMap(),
+ };
+}
+
+class UrlEndpoint {
+ String? url;
+ String? target;
+
+ UrlEndpoint({
+ this.url,
+ this.target,
+ });
+
+ factory UrlEndpoint.fromJson(String str) => UrlEndpoint.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory UrlEndpoint.fromMap(Map json) => UrlEndpoint(
+ url: json["url"],
+ target: json["target"],
+ );
+
+ Map toMap() => {
+ "url": url,
+ "target": target,
+ };
+}
+
+class MoreButton {
+ MoreButtonToggleButtonRenderer? toggleButtonRenderer;
+
+ MoreButton({
+ this.toggleButtonRenderer,
+ });
+
+ factory MoreButton.fromJson(String str) => MoreButton.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MoreButton.fromMap(Map json) => MoreButton(
+ toggleButtonRenderer: json["toggleButtonRenderer"] == null ? null : MoreButtonToggleButtonRenderer.fromMap(json["toggleButtonRenderer"]),
+ );
+
+ Map toMap() => {
+ "toggleButtonRenderer": toggleButtonRenderer?.toMap(),
+ };
+}
+
+class MoreButtonToggleButtonRenderer {
+ bool? isToggled;
+ bool? isDisabled;
+ Icon? defaultIcon;
+ Index? defaultText;
+ Icon? toggledIcon;
+ Index? toggledText;
+ String? trackingParams;
+
+ MoreButtonToggleButtonRenderer({
+ this.isToggled,
+ this.isDisabled,
+ this.defaultIcon,
+ this.defaultText,
+ this.toggledIcon,
+ this.toggledText,
+ this.trackingParams,
+ });
+
+ factory MoreButtonToggleButtonRenderer.fromJson(String str) => MoreButtonToggleButtonRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MoreButtonToggleButtonRenderer.fromMap(Map json) => MoreButtonToggleButtonRenderer(
+ isToggled: json["isToggled"],
+ isDisabled: json["isDisabled"],
+ defaultIcon: json["defaultIcon"] == null ? null : Icon.fromMap(json["defaultIcon"]),
+ defaultText: json["defaultText"] == null ? null : Index.fromMap(json["defaultText"]),
+ toggledIcon: json["toggledIcon"] == null ? null : Icon.fromMap(json["toggledIcon"]),
+ toggledText: json["toggledText"] == null ? null : Index.fromMap(json["toggledText"]),
+ trackingParams: json["trackingParams"],
+ );
+
+ Map toMap() => {
+ "isToggled": isToggled,
+ "isDisabled": isDisabled,
+ "defaultIcon": defaultIcon?.toMap(),
+ "defaultText": defaultText?.toMap(),
+ "toggledIcon": toggledIcon?.toMap(),
+ "toggledText": toggledText?.toMap(),
+ "trackingParams": trackingParams,
+ };
+}
+
+class StraplineTextOne {
+ List? runs;
+
+ StraplineTextOne({
+ this.runs,
+ });
+
+ factory StraplineTextOne.fromJson(String str) => StraplineTextOne.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory StraplineTextOne.fromMap(Map json) => StraplineTextOne(
+ runs: json["runs"] == null ? [] : List.from(json["runs"]!.map((x) => StraplineTextOneRun.fromMap(x))),
+ );
+
+ Map toMap() => {
+ "runs": runs == null ? [] : List.from(runs!.map((x) => x.toMap())),
+ };
+}
+
+class StraplineTextOneRun {
+ String? text;
+ FluffyNavigationEndpoint? navigationEndpoint;
+
+ StraplineTextOneRun({
+ this.text,
+ this.navigationEndpoint,
+ });
+
+ factory StraplineTextOneRun.fromJson(String str) => StraplineTextOneRun.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory StraplineTextOneRun.fromMap(Map json) => StraplineTextOneRun(
+ text: json["text"],
+ navigationEndpoint: json["navigationEndpoint"] == null ? null : FluffyNavigationEndpoint.fromMap(json["navigationEndpoint"]),
+ );
+
+ Map toMap() => {
+ "text": text,
+ "navigationEndpoint": navigationEndpoint?.toMap(),
+ };
+}
+
+class StraplineThumbnailClass {
+ MusicThumbnailRenderer? musicThumbnailRenderer;
+
+ StraplineThumbnailClass({
+ this.musicThumbnailRenderer,
+ });
+
+ factory StraplineThumbnailClass.fromJson(String str) => StraplineThumbnailClass.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory StraplineThumbnailClass.fromMap(Map json) => StraplineThumbnailClass(
+ musicThumbnailRenderer: json["musicThumbnailRenderer"] == null ? null : MusicThumbnailRenderer.fromMap(json["musicThumbnailRenderer"]),
+ );
+
+ Map toMap() => {
+ "musicThumbnailRenderer": musicThumbnailRenderer?.toMap(),
+ };
+}
+
+class Microformat {
+ MicroformatDataRenderer? microformatDataRenderer;
+
+ Microformat({
+ this.microformatDataRenderer,
+ });
+
+ factory Microformat.fromJson(String str) => Microformat.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory Microformat.fromMap(Map json) => Microformat(
+ microformatDataRenderer: json["microformatDataRenderer"] == null ? null : MicroformatDataRenderer.fromMap(json["microformatDataRenderer"]),
+ );
+
+ Map toMap() => {
+ "microformatDataRenderer": microformatDataRenderer?.toMap(),
+ };
+}
+
+class MicroformatDataRenderer {
+ String? urlCanonical;
+
+ MicroformatDataRenderer({
+ this.urlCanonical,
+ });
+
+ factory MicroformatDataRenderer.fromJson(String str) => MicroformatDataRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MicroformatDataRenderer.fromMap(Map json) => MicroformatDataRenderer(
+ urlCanonical: json["urlCanonical"],
+ );
+
+ Map toMap() => {
+ "urlCanonical": urlCanonical,
+ };
+}
+
+class MusicPlaylistShelfRenderer {
+ String? playlistId;
+ List? contents;
+ int? collapsedItemCount;
+ String? trackingParams;
+ bool? contentsMultiSelectable;
+
+ MusicPlaylistShelfRenderer({
+ this.playlistId,
+ this.contents,
+ this.collapsedItemCount,
+ this.trackingParams,
+ this.contentsMultiSelectable,
+ });
+
+ factory MusicPlaylistShelfRenderer.fromJson(String str) => MusicPlaylistShelfRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MusicPlaylistShelfRenderer.fromMap(Map json) => MusicPlaylistShelfRenderer(
+ playlistId: json["playlistId"],
+ contents: json["contents"] == null ? [] : List.from(json["contents"]!.map((x) => MusicShelfRendererContent.fromMap(x))),
+ collapsedItemCount: json["collapsedItemCount"],
+ trackingParams: json["trackingParams"],
+ contentsMultiSelectable: json["contentsMultiSelectable"],
+ );
+
+ Map toMap() => {
+ "playlistId": playlistId,
+ "contents": contents == null ? [] : List.from(contents!.map((x) => x.toMap())),
+ "collapsedItemCount": collapsedItemCount,
+ "trackingParams": trackingParams,
+ "contentsMultiSelectable": contentsMultiSelectable,
+ };
+}
\ No newline at end of file
diff --git a/lib/data/models/home_model.dart b/lib/data/models/home_model.dart
deleted file mode 100644
index cd8ecde..0000000
--- a/lib/data/models/home_model.dart
+++ /dev/null
@@ -1,77 +0,0 @@
-// Author: fengshengxiong
-// Date: 2024/6/20
-// Description: 首页实际展示数据模型
-
-import 'dart:convert';
-
-class HomeModel {
- String? headerTitle;
- List? contents;
- String? browseType;
-
- HomeModel({
- this.headerTitle,
- this.contents,
- this.browseType,
- });
-
- factory HomeModel.fromJson(String str) => HomeModel.fromMap(json.decode(str));
-
- String toJson() => json.encode(toMap());
-
- factory HomeModel.fromMap(Map json) => HomeModel(
- headerTitle: json["headerTitle"],
- contents: json["contents"] == null ? [] : List.from(json["contents"]!.map((x) => Content.fromMap(x))),
- browseType: json["browseType"]
- );
-
- Map toMap() => {
- "headerTitle": headerTitle,
- "contents": contents == null ? [] : List.from(contents!.map((x) => x.toMap())),
- "browseType": browseType,
- };
-}
-
-class Content {
- String? title;
- String? subTitle;
- String? thumbnail;
- String? videoId;
- String? playlistId;
- String? browseId;
- String? params;
-
- Content({
- this.title,
- this.subTitle,
- this.thumbnail,
- this.videoId,
- this.playlistId,
- this.browseId,
- this.params,
- });
-
- factory Content.fromJson(String str) => Content.fromMap(json.decode(str));
-
- String toJson() => json.encode(toMap());
-
- factory Content.fromMap(Map json) => Content(
- title: json["title"],
- subTitle: json["subTitle"],
- thumbnail: json["thumbnail"],
- videoId: json["videoId"],
- playlistId: json["playlistId"],
- browseId: json["browseId"],
- params: json["params"],
- );
-
- Map toMap() => {
- "title": title,
- "subTitle": subTitle,
- "thumbnail": thumbnail,
- "videoId": videoId,
- "playlistId": playlistId,
- "browseId": browseId,
- "params": params,
- };
-}
diff --git a/lib/data/models/isocode_model.dart b/lib/data/models/isocode_model.dart
index 4fcd251..66f853e 100644
--- a/lib/data/models/isocode_model.dart
+++ b/lib/data/models/isocode_model.dart
@@ -4,20 +4,20 @@
import 'dart:convert';
-class IosCodeModel {
+class IsoCodeModel {
String? isoCode;
String? ip;
- IosCodeModel({
+ IsoCodeModel({
this.isoCode,
this.ip,
});
- factory IosCodeModel.fromJson(String str) => IosCodeModel.fromMap(json.decode(str));
+ factory IsoCodeModel.fromJson(String str) => IsoCodeModel.fromMap(json.decode(str));
String toJson() => json.encode(toMap());
- factory IosCodeModel.fromMap(Map json) => IosCodeModel(
+ factory IsoCodeModel.fromMap(Map json) => IsoCodeModel(
isoCode: json["isoCode"],
ip: json["ip"],
);
diff --git a/lib/data/models/music_model.dart b/lib/data/models/music_model.dart
index e3262a9..c43673c 100644
--- a/lib/data/models/music_model.dart
+++ b/lib/data/models/music_model.dart
@@ -1,9 +1,11 @@
// Author: fengshengxiong
// Date: 2024/6/24
-// Description: 音乐模型
+// Description: 音乐个体模型
import 'dart:convert';
+import 'package:background_downloader/background_downloader.dart';
+import 'package:dio/dio.dart';
import 'package:hive/hive.dart';
part 'music_model.g.dart';
@@ -11,42 +13,82 @@ part 'music_model.g.dart';
@HiveType(typeId: 2)
class MusicModel extends HiveObject {
@HiveField(0)
- String? title;
- @HiveField(1)
- String? subTitle;
- @HiveField(2)
- String? thumbnail;
- @HiveField(3)
String? videoId;
+ @HiveField(1)
+ String? title;
+ @HiveField(2)
+ String? subtitle;
+ @HiveField(3)
+ String? coverUrl;
@HiveField(4)
- String? playlistId;
- @HiveField(5)
String? url;
+ @HiveField(5)
+ String? localPath;
+ @HiveField(6)
+ String? musicType;
+ @HiveField(7)
+ String? playlistId;
+ @HiveField(8)
+ String? browseId;
+ @HiveField(9)
+ String? params;
+
+ /// 收藏状态
+ bool isLove = false;
+
+ /// 下载进度、任务状态
+ double progress;
+ TaskStatus? taskStatus;
+ CancelToken? cancelToken;
MusicModel({
- this.title,
- this.subTitle,
- this.thumbnail,
this.videoId,
- this.playlistId,
+ this.title,
+ this.subtitle,
+ this.coverUrl,
this.url,
+ this.localPath,
+ this.musicType,
+ this.playlistId,
+ this.browseId,
+ this.params,
+ this.isLove = false,
+ this.progress = 0.0,
+ this.taskStatus,
+ this.cancelToken,
});
MusicModel copyWith({
- String? title,
- String? subTitle,
- String? thumbnail,
- String? url,
String? videoId,
+ String? title,
+ String? subtitle,
+ String? coverUrl,
+ String? url,
+ String? localPath,
+ String? musicType,
String? playlistId,
+ String? browseId,
+ String? params,
+ bool? isLove,
+ double? progress,
+ TaskStatus? taskStatus,
+ CancelToken? cancelToken,
}) =>
MusicModel(
- title: title ?? this.title,
- subTitle: subTitle ?? this.subTitle,
- thumbnail: thumbnail ?? this.thumbnail,
- url: url ?? this.url,
videoId: videoId ?? this.videoId,
+ title: title ?? this.title,
+ subtitle: subtitle ?? this.subtitle,
+ coverUrl: coverUrl ?? this.coverUrl,
+ url: url ?? this.url,
+ localPath: localPath ?? this.localPath,
+ musicType: musicType ?? this.musicType,
playlistId: playlistId ?? this.playlistId,
+ browseId: browseId ?? this.browseId,
+ params: params ?? this.params,
+ isLove: isLove ?? this.isLove,
+ progress: progress ?? this.progress,
+ taskStatus: taskStatus ?? this.taskStatus,
+ cancelToken: cancelToken ?? this.cancelToken,
);
factory MusicModel.fromJson(String str) =>
@@ -55,20 +97,36 @@ class MusicModel extends HiveObject {
String toJson() => json.encode(toMap());
factory MusicModel.fromMap(Map json) => MusicModel(
- title: json["title"],
- subTitle: json["subTitle"],
- thumbnail: json["thumbnail"],
videoId: json["videoId"],
- playlistId: json["playlistId"],
+ title: json["title"],
+ subtitle: json["subtitle"],
+ coverUrl: json["coverUrl"],
url: json["url"],
+ localPath: json["localPath"],
+ musicType: json["musicType"],
+ playlistId: json["playlistId"],
+ browseId: json["browseId"],
+ params: json["params"],
+ isLove: json["isLove"] ?? false,
+ progress: json["progress"] ?? 0.0,
+ taskStatus: json["taskStatus"],
+ cancelToken: json["cancelToken"],
);
Map toMap() => {
- "title": title,
- "subTitle": subTitle,
- "thumbnail": thumbnail,
"videoId": videoId,
- "playlistId": playlistId,
+ "title": title,
+ "subTitle": subtitle,
+ "coverUrl": coverUrl,
"url": url,
+ "localPath": localPath,
+ "musicType": musicType,
+ "playlistId": playlistId,
+ "browseId": browseId,
+ "params": params,
+ "isLove": isLove,
+ "progress": progress,
+ "taskStatus": taskStatus,
+ "cancelToken": cancelToken,
};
}
diff --git a/lib/data/models/music_model.g.dart b/lib/data/models/music_model.g.dart
index 4aa388f..26fdb33 100644
--- a/lib/data/models/music_model.g.dart
+++ b/lib/data/models/music_model.g.dart
@@ -17,31 +17,40 @@ class MusicModelAdapter extends TypeAdapter {
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return MusicModel(
- title: fields[0] as String?,
- subTitle: fields[1] as String?,
- thumbnail: fields[2] as String?,
- videoId: fields[3] as String?,
- playlistId: fields[4] as String?,
- url: fields[5] as String?,
+ videoId: fields[0] as String?,
+ title: fields[1] as String?,
+ subtitle: fields[2] as String?,
+ coverUrl: fields[3] as String?,
+ url: fields[4] as String?,
+ localPath: fields[5] as String?,
+ musicType: fields[6] as String?,
+ playlistId: fields[7] as String?,
+ browseId: fields[8] as String?,
);
}
@override
void write(BinaryWriter writer, MusicModel obj) {
writer
- ..writeByte(6)
+ ..writeByte(9)
..writeByte(0)
- ..write(obj.title)
- ..writeByte(1)
- ..write(obj.subTitle)
- ..writeByte(2)
- ..write(obj.thumbnail)
- ..writeByte(3)
..write(obj.videoId)
+ ..writeByte(1)
+ ..write(obj.title)
+ ..writeByte(2)
+ ..write(obj.subtitle)
+ ..writeByte(3)
+ ..write(obj.coverUrl)
..writeByte(4)
- ..write(obj.playlistId)
+ ..write(obj.url)
..writeByte(5)
- ..write(obj.url);
+ ..write(obj.localPath)
+ ..writeByte(6)
+ ..write(obj.musicType)
+ ..writeByte(7)
+ ..write(obj.playlistId)
+ ..writeByte(8)
+ ..write(obj.browseId);
}
@override
diff --git a/lib/data/models/playlist_model.dart b/lib/data/models/playlist_model.dart
new file mode 100644
index 0000000..891f302
--- /dev/null
+++ b/lib/data/models/playlist_model.dart
@@ -0,0 +1,85 @@
+// Author: fengshengxiong
+// Date: 2024/6/24
+// Description: 播放列表模型
+
+import 'dart:convert';
+
+import 'package:hive/hive.dart';
+import 'package:tone_snap/data/models/music_model.dart';
+
+part 'playlist_model.g.dart';
+
+@HiveType(typeId: 3)
+class PlaylistModel extends HiveObject {
+ @HiveField(0)
+ String id;
+ @HiveField(1)
+ String title;
+
+ /// playlists
+ @HiveField(2)
+ int? milliseconds;
+ @HiveField(3)
+ List? musicList;
+
+ /// collect_playlists
+ @HiveField(4)
+ String? params;
+ @HiveField(5)
+ String? coverUrl;
+ @HiveField(6)
+ String? subtitle;
+
+ PlaylistModel({
+ required this.id,
+ required this.title,
+ this.milliseconds,
+ this.musicList,
+ this.params,
+ this.coverUrl,
+ this.subtitle,
+ });
+
+ PlaylistModel copyWith({
+ required String id,
+ required String title,
+ int? milliseconds,
+ List? musicList,
+ String? params,
+ String? coverUrl,
+ String? subtitle,
+ }) =>
+ PlaylistModel(
+ id: id,
+ title: title,
+ milliseconds: milliseconds ?? this.milliseconds,
+ musicList: musicList ?? this.musicList,
+ params: params ?? this.params,
+ coverUrl: coverUrl ?? this.coverUrl,
+ subtitle: subtitle ?? this.subtitle,
+ );
+
+ factory PlaylistModel.fromJson(String str) => PlaylistModel.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory PlaylistModel.fromMap(Map json) => PlaylistModel(
+ id: json["id"],
+ title: json["title"],
+ milliseconds: json["milliseconds"],
+ musicList: json["musicList"],
+ params: json["params"],
+ coverUrl: json["coverUrl"],
+ subtitle: json["subtitle"],
+ );
+
+ Map toMap() => {
+ "id": id,
+ "title": title,
+ "milliseconds": milliseconds,
+ "musicList": musicList,
+ "params": params,
+ "coverUrl": coverUrl,
+ "subtitle": subtitle,
+ };
+}
diff --git a/lib/data/models/playlist_model.g.dart b/lib/data/models/playlist_model.g.dart
new file mode 100644
index 0000000..2ffabd1
--- /dev/null
+++ b/lib/data/models/playlist_model.g.dart
@@ -0,0 +1,59 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'playlist_model.dart';
+
+// **************************************************************************
+// TypeAdapterGenerator
+// **************************************************************************
+
+class PlaylistModelAdapter extends TypeAdapter {
+ @override
+ final int typeId = 3;
+
+ @override
+ PlaylistModel read(BinaryReader reader) {
+ final numOfFields = reader.readByte();
+ final fields = {
+ for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
+ };
+ return PlaylistModel(
+ id: fields[0] as String,
+ title: fields[1] as String,
+ milliseconds: fields[2] as int?,
+ musicList: (fields[3] as List?)?.cast(),
+ params: fields[4] as String?,
+ coverUrl: fields[5] as String?,
+ subtitle: fields[6] as String?,
+ );
+ }
+
+ @override
+ void write(BinaryWriter writer, PlaylistModel obj) {
+ writer
+ ..writeByte(7)
+ ..writeByte(0)
+ ..write(obj.id)
+ ..writeByte(1)
+ ..write(obj.title)
+ ..writeByte(2)
+ ..write(obj.milliseconds)
+ ..writeByte(3)
+ ..write(obj.musicList)
+ ..writeByte(4)
+ ..write(obj.params)
+ ..writeByte(5)
+ ..write(obj.coverUrl)
+ ..writeByte(6)
+ ..write(obj.subtitle);
+ }
+
+ @override
+ int get hashCode => typeId.hashCode;
+
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ other is PlaylistModelAdapter &&
+ runtimeType == other.runtimeType &&
+ typeId == other.typeId;
+}
diff --git a/lib/data/models/browse_album_model.dart b/lib/data/models/search_result_model.dart
similarity index 62%
rename from lib/data/models/browse_album_model.dart
rename to lib/data/models/search_result_model.dart
index 24627d0..1dfa331 100644
--- a/lib/data/models/browse_album_model.dart
+++ b/lib/data/models/search_result_model.dart
@@ -1,57 +1,1897 @@
// Author: fengshengxiong
-// Date: 2024/6/30
-// Description: Browse-专辑模型
+// Date: 2024/7/28
+// Description: 搜索结果模型
import 'dart:convert';
-class BrowseAlbumModel {
+class SearchResultModel {
ResponseContext? responseContext;
Contents? contents;
String? trackingParams;
- Microformat? microformat;
- StraplineThumbnailClass? background;
- BrowseAlbumModel({
+ SearchResultModel({
this.responseContext,
this.contents,
this.trackingParams,
- this.microformat,
- this.background,
});
- factory BrowseAlbumModel.fromJson(String str) => BrowseAlbumModel.fromMap(json.decode(str));
+ factory SearchResultModel.fromJson(String str) => SearchResultModel.fromMap(json.decode(str));
String toJson() => json.encode(toMap());
- factory BrowseAlbumModel.fromMap(Map json) => BrowseAlbumModel(
+ factory SearchResultModel.fromMap(Map json) => SearchResultModel(
responseContext: json["responseContext"] == null ? null : ResponseContext.fromMap(json["responseContext"]),
contents: json["contents"] == null ? null : Contents.fromMap(json["contents"]),
trackingParams: json["trackingParams"],
- microformat: json["microformat"] == null ? null : Microformat.fromMap(json["microformat"]),
- background: json["background"] == null ? null : StraplineThumbnailClass.fromMap(json["background"]),
);
Map toMap() => {
"responseContext": responseContext?.toMap(),
"contents": contents?.toMap(),
"trackingParams": trackingParams,
- "microformat": microformat?.toMap(),
- "background": background?.toMap(),
};
}
-class StraplineThumbnailClass {
- MusicThumbnailRenderer? musicThumbnailRenderer;
+class Contents {
+ TabbedSearchResultsRenderer? tabbedSearchResultsRenderer;
- StraplineThumbnailClass({
- this.musicThumbnailRenderer,
+ Contents({
+ this.tabbedSearchResultsRenderer,
});
- factory StraplineThumbnailClass.fromJson(String str) => StraplineThumbnailClass.fromMap(json.decode(str));
+ factory Contents.fromJson(String str) => Contents.fromMap(json.decode(str));
String toJson() => json.encode(toMap());
- factory StraplineThumbnailClass.fromMap(Map json) => StraplineThumbnailClass(
+ factory Contents.fromMap(Map json) => Contents(
+ tabbedSearchResultsRenderer: json["tabbedSearchResultsRenderer"] == null ? null : TabbedSearchResultsRenderer.fromMap(json["tabbedSearchResultsRenderer"]),
+ );
+
+ Map toMap() => {
+ "tabbedSearchResultsRenderer": tabbedSearchResultsRenderer?.toMap(),
+ };
+}
+
+class TabbedSearchResultsRenderer {
+ List? tabs;
+
+ TabbedSearchResultsRenderer({
+ this.tabs,
+ });
+
+ factory TabbedSearchResultsRenderer.fromJson(String str) => TabbedSearchResultsRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory TabbedSearchResultsRenderer.fromMap(Map json) => TabbedSearchResultsRenderer(
+ tabs: json["tabs"] == null ? [] : List.from(json["tabs"]!.map((x) => Tab.fromMap(x))),
+ );
+
+ Map toMap() => {
+ "tabs": tabs == null ? [] : List.from(tabs!.map((x) => x.toMap())),
+ };
+}
+
+class Tab {
+ TabRenderer? tabRenderer;
+
+ Tab({
+ this.tabRenderer,
+ });
+
+ factory Tab.fromJson(String str) => Tab.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory Tab.fromMap(Map json) => Tab(
+ tabRenderer: json["tabRenderer"] == null ? null : TabRenderer.fromMap(json["tabRenderer"]),
+ );
+
+ Map toMap() => {
+ "tabRenderer": tabRenderer?.toMap(),
+ };
+}
+
+class TabRenderer {
+ String? title;
+ bool? selected;
+ TabRendererContent? content;
+ String? tabIdentifier;
+ String? trackingParams;
+
+ TabRenderer({
+ this.title,
+ this.selected,
+ this.content,
+ this.tabIdentifier,
+ this.trackingParams,
+ });
+
+ factory TabRenderer.fromJson(String str) => TabRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory TabRenderer.fromMap(Map json) => TabRenderer(
+ title: json["title"],
+ selected: json["selected"],
+ content: json["content"] == null ? null : TabRendererContent.fromMap(json["content"]),
+ tabIdentifier: json["tabIdentifier"],
+ trackingParams: json["trackingParams"],
+ );
+
+ Map toMap() => {
+ "title": title,
+ "selected": selected,
+ "content": content?.toMap(),
+ "tabIdentifier": tabIdentifier,
+ "trackingParams": trackingParams,
+ };
+}
+
+class TabRendererContent {
+ SectionListRenderer? sectionListRenderer;
+
+ TabRendererContent({
+ this.sectionListRenderer,
+ });
+
+ factory TabRendererContent.fromJson(String str) => TabRendererContent.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory TabRendererContent.fromMap(Map json) => TabRendererContent(
+ sectionListRenderer: json["sectionListRenderer"] == null ? null : SectionListRenderer.fromMap(json["sectionListRenderer"]),
+ );
+
+ Map toMap() => {
+ "sectionListRenderer": sectionListRenderer?.toMap(),
+ };
+}
+
+class SectionListRenderer {
+ List? contents;
+ String? trackingParams;
+ SectionListRendererHeader? header;
+
+ SectionListRenderer({
+ this.contents,
+ this.trackingParams,
+ this.header,
+ });
+
+ factory SectionListRenderer.fromJson(String str) => SectionListRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory SectionListRenderer.fromMap(Map json) => SectionListRenderer(
+ contents: json["contents"] == null ? [] : List.from(json["contents"]!.map((x) => SectionListRendererContent.fromMap(x))),
+ trackingParams: json["trackingParams"],
+ header: json["header"] == null ? null : SectionListRendererHeader.fromMap(json["header"]),
+ );
+
+ Map toMap() => {
+ "contents": contents == null ? [] : List.from(contents!.map((x) => x.toMap())),
+ "trackingParams": trackingParams,
+ "header": header?.toMap(),
+ };
+}
+
+class SectionListRendererContent {
+ MusicCardShelfRenderer? musicCardShelfRenderer;
+ MusicShelfRenderer? musicShelfRenderer;
+
+ SectionListRendererContent({
+ this.musicCardShelfRenderer,
+ this.musicShelfRenderer,
+ });
+
+ factory SectionListRendererContent.fromJson(String str) => SectionListRendererContent.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory SectionListRendererContent.fromMap(Map json) => SectionListRendererContent(
+ musicCardShelfRenderer: json["musicCardShelfRenderer"] == null ? null : MusicCardShelfRenderer.fromMap(json["musicCardShelfRenderer"]),
+ musicShelfRenderer: json["musicShelfRenderer"] == null ? null : MusicShelfRenderer.fromMap(json["musicShelfRenderer"]),
+ );
+
+ Map toMap() => {
+ "musicCardShelfRenderer": musicCardShelfRenderer?.toMap(),
+ "musicShelfRenderer": musicShelfRenderer?.toMap(),
+ };
+}
+
+class MusicCardShelfRenderer {
+ String? trackingParams;
+ MusicResponsiveListItemRendererThumbnail? thumbnail;
+ Title? title;
+ Subtitle? subtitle;
+ List? contents;
+ List? buttons;
+ MusicCardShelfRendererMenu? menu;
+ OnTap? onTap;
+ MusicCardShelfRendererHeader? header;
+ ThumbnailOverlayClass? thumbnailOverlay;
+
+ MusicCardShelfRenderer({
+ this.trackingParams,
+ this.thumbnail,
+ this.title,
+ this.subtitle,
+ this.contents,
+ this.buttons,
+ this.menu,
+ this.onTap,
+ this.header,
+ this.thumbnailOverlay,
+ });
+
+ factory MusicCardShelfRenderer.fromJson(String str) => MusicCardShelfRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory MusicCardShelfRenderer.fromMap(Map json) => MusicCardShelfRenderer(
+ trackingParams: json["trackingParams"],
+ thumbnail: json["thumbnail"] == null ? null : MusicResponsiveListItemRendererThumbnail.fromMap(json["thumbnail"]),
+ title: json["title"] == null ? null : Title.fromMap(json["title"]),
+ subtitle: json["subtitle"] == null ? null : Subtitle.fromMap(json["subtitle"]),
+ contents: json["contents"] == null ? [] : List.from(json["contents"]!.map((x) => MusicCardShelfRendererContent.fromMap(x))),
+ buttons: json["buttons"] == null ? [] : List.from(json["buttons"]!.map((x) => ButtonElement.fromMap(x))),
+ menu: json["menu"] == null ? null : MusicCardShelfRendererMenu.fromMap(json["menu"]),
+ onTap: json["onTap"] == null ? null : OnTap.fromMap(json["onTap"]),
+ header: json["header"] == null ? null : MusicCardShelfRendererHeader.fromMap(json["header"]),
+ thumbnailOverlay: json["thumbnailOverlay"] == null ? null : ThumbnailOverlayClass.fromMap(json["thumbnailOverlay"]),
+ );
+
+ Map toMap() => {
+ "trackingParams": trackingParams,
+ "thumbnail": thumbnail?.toMap(),
+ "title": title?.toMap(),
+ "subtitle": subtitle?.toMap(),
+ "contents": contents == null ? [] : List.from(contents!.map((x) => x.toMap())),
+ "buttons": buttons == null ? [] : List.from(buttons!.map((x) => x.toMap())),
+ "menu": menu?.toMap(),
+ "onTap": onTap?.toMap(),
+ "header": header?.toMap(),
+ "thumbnailOverlay": thumbnailOverlay?.toMap(),
+ };
+}
+
+class ButtonElement {
+ PurpleButtonRenderer? buttonRenderer;
+
+ ButtonElement({
+ this.buttonRenderer,
+ });
+
+ factory ButtonElement.fromJson(String str) => ButtonElement.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory ButtonElement.fromMap(Map json) => ButtonElement(
+ buttonRenderer: json["buttonRenderer"] == null ? null : PurpleButtonRenderer.fromMap(json["buttonRenderer"]),
+ );
+
+ Map toMap() => {
+ "buttonRenderer": buttonRenderer?.toMap(),
+ };
+}
+
+class PurpleButtonRenderer {
+ String? style;
+ String? size;
+ bool? isDisabled;
+ BottomText? text;
+ Icon? icon;
+ AccessibilityAccessibility? accessibility;
+ String? trackingParams;
+ AccessibilityPauseDataClass? accessibilityData;
+ ButtonRendererCommand? command;
+
+ PurpleButtonRenderer({
+ this.style,
+ this.size,
+ this.isDisabled,
+ this.text,
+ this.icon,
+ this.accessibility,
+ this.trackingParams,
+ this.accessibilityData,
+ this.command,
+ });
+
+ factory PurpleButtonRenderer.fromJson(String str) => PurpleButtonRenderer.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory PurpleButtonRenderer.fromMap(Map json) => PurpleButtonRenderer(
+ style: json["style"],
+ size: json["size"],
+ isDisabled: json["isDisabled"],
+ text: json["text"] == null ? null : BottomText.fromMap(json["text"]),
+ icon: json["icon"] == null ? null : Icon.fromMap(json["icon"]),
+ accessibility: json["accessibility"] == null ? null : AccessibilityAccessibility.fromMap(json["accessibility"]),
+ trackingParams: json["trackingParams"],
+ accessibilityData: json["accessibilityData"] == null ? null : AccessibilityPauseDataClass.fromMap(json["accessibilityData"]),
+ command: json["command"] == null ? null : ButtonRendererCommand.fromMap(json["command"]),
+ );
+
+ Map toMap() => {
+ "style": style,
+ "size": size,
+ "isDisabled": isDisabled,
+ "text": text?.toMap(),
+ "icon": icon?.toMap(),
+ "accessibility": accessibility?.toMap(),
+ "trackingParams": trackingParams,
+ "accessibilityData": accessibilityData?.toMap(),
+ "command": command?.toMap(),
+ };
+}
+
+class AccessibilityAccessibility {
+ String? label;
+
+ AccessibilityAccessibility({
+ this.label,
+ });
+
+ factory AccessibilityAccessibility.fromJson(String str) => AccessibilityAccessibility.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory AccessibilityAccessibility.fromMap(Map json) => AccessibilityAccessibility(
+ label: json["label"],
+ );
+
+ Map toMap() => {
+ "label": label,
+ };
+}
+
+class AccessibilityPauseDataClass {
+ AccessibilityAccessibility? accessibilityData;
+
+ AccessibilityPauseDataClass({
+ this.accessibilityData,
+ });
+
+ factory AccessibilityPauseDataClass.fromJson(String str) => AccessibilityPauseDataClass.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory AccessibilityPauseDataClass.fromMap(Map json) => AccessibilityPauseDataClass(
+ accessibilityData: json["accessibilityData"] == null ? null : AccessibilityAccessibility.fromMap(json["accessibilityData"]),
+ );
+
+ Map toMap() => {
+ "accessibilityData": accessibilityData?.toMap(),
+ };
+}
+
+class ButtonRendererCommand {
+ String? clickTrackingParams;
+ CommandWatchEndpoint? watchEndpoint;
+ ModalEndpoint? modalEndpoint;
+
+ ButtonRendererCommand({
+ this.clickTrackingParams,
+ this.watchEndpoint,
+ this.modalEndpoint,
+ });
+
+ factory ButtonRendererCommand.fromJson(String str) => ButtonRendererCommand.fromMap(json.decode(str));
+
+ String toJson() => json.encode(toMap());
+
+ factory ButtonRendererCommand.fromMap(Map