1.添加通知栏媒体控制

2.下一首上一首增加防抖
3.集成fb
4.首页单曲增加下载
5.增加后台播放(iOS仍有问题)
6.修改系统状态栏颜色
This commit is contained in:
fengshengxiong 2024-08-19 13:51:10 +08:00
parent caded892d9
commit 063e3d7c91
22 changed files with 610 additions and 361 deletions

View File

@ -9,8 +9,14 @@
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" <uses-permission android:name="android.permission.READ_MEDIA_AUDIO"
android:minSdkVersion = "33"/> android:minSdkVersion = "33"/>
<!-- ADD THESE TWO PERMISSIONS -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<!-- ALSO ADD THIS PERMISSION IF TARGETING SDK 34 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
<application <application
android:label="ToneSnap" android:label="@string/app_name"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/launcher_icon" android:icon="@mipmap/launcher_icon"
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
@ -25,7 +31,8 @@
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize"
tools:ignore="Instantiatable">
<!-- Specifies an Android theme to apply to this Activity as soon as <!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues while the Flutter UI initializes. After that, this theme continues
@ -39,6 +46,26 @@
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
</activity> </activity>
<!-- ADD THIS "SERVICE" element -->
<service android:name="com.ryanheise.audioservice.AudioService"
android:foregroundServiceType="mediaPlayback"
android:exported="true"
tools:ignore="Instantiatable">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
<!-- ADD THIS "RECEIVER" element -->
<receiver android:name="com.ryanheise.audioservice.MediaButtonReceiver"
android:exported="true"
tools:ignore="Instantiatable">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
<!-- Don't delete the meta-data below. <!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data <meta-data
@ -49,6 +76,10 @@
<meta-data <meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID" android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-5684307632319406~5753747604"/> android:value="ca-app-pub-5684307632319406~5753747604"/>
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
<meta-data android:name="com.facebook.sdk.ClientToken" android:value="@string/facebook_client_token"/>
</application> </application>
<!-- Required to query activities that can process text, see: <!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and https://developer.android.com/training/package-visibility and

View File

@ -1,5 +1,5 @@
package com.tone.music.offline package com.tone.music.offline
import io.flutter.embedding.android.FlutterActivity import com.ryanheise.audioservice.AudioServiceActivity
class MainActivity: FlutterActivity() class MainActivity: AudioServiceActivity()

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">ToneSnap</string>
<string name="facebook_app_id">1058126742561467</string>
<string name="facebook_client_token">d37b13dd56db288fe976782b2a10b4a7</string>
</resources>

View File

@ -490,7 +490,7 @@
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 15; CURRENT_PROJECT_VERSION = 17;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = UH427LWP22; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = UH427LWP22;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
@ -689,7 +689,7 @@
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 15; CURRENT_PROJECT_VERSION = 17;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = UH427LWP22; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = UH427LWP22;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
@ -723,7 +723,7 @@
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 15; CURRENT_PROJECT_VERSION = 17;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = UH427LWP22; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = UH427LWP22;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;

View File

@ -36,205 +36,21 @@
<string>We need access to the photo library to pick audio files.</string> <string>We need access to the photo library to pick audio files.</string>
<key>NSUserTrackingUsageDescription</key> <key>NSUserTrackingUsageDescription</key>
<string>We need your permission to access the advertising identifier to provide better ad services.</string> <string>We need your permission to access the advertising identifier to provide better ad services.</string>
<key>SKAdNetworkItems</key> <key>CFBundleURLTypes</key>
<array> <array>
<dict> <dict>
<key>SKAdNetworkIdentifier</key> <key>CFBundleURLSchemes</key>
<string>cstr6suwn9.skadnetwork</string> <array>
</dict> <string>fb1044438596577354</string>
<dict> </array>
<key>SKAdNetworkIdentifier</key> </dict>
<string>4fzdc2evr5.skadnetwork</string> </array>
</dict> <key>FacebookAppID</key>
<dict> <string>1044438596577354</string>
<key>SKAdNetworkIdentifier</key> <key>FacebookClientToken</key>
<string>4pfyvq9l8r.skadnetwork</string> <string>4d24452ca73a8fc8157f7a46d4d1930b</string>
</dict> <key>FacebookDisplayName</key>
<dict> <string>ToneSnap-ios</string>
<key>SKAdNetworkIdentifier</key>
<string>2fnua5tdw4.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ydx93a7ass.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>5a6flpkh64.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>p78axxw29g.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>v72qych5uu.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ludvb6z3bs.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>cp8zw746q7.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3sh42y64q3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>c6k4g5qg8m.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>s39g8k73mm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3qy4746246.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>f38h382jlk.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>hs6bdukanm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>v4nxqhlyqp.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>wzmmz9fp6w.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>yclnxrl5pm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>t38b2kh725.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>7ug5zh24hu.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>gta9lk7p23.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>vutu7akeur.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>y5ghdn5j9k.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>n6fk4nfna4.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>v9wttpbfk9.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>n38lu8286q.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>47vhws6wlr.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>kbd757ywx3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>9t245vhmpl.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>eh6m2bh4zr.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>a2p9lx4jpn.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>22mmun2rn5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4468km3ulz.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>2u9pt9hc89.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>8s468mfl3y.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>klf5c3l5u5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ppxm28t8ap.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ecpz2srf59.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>uw77j35x4d.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>pwa73g5rt2.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>mlmmfzh3r3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>578prtvx9j.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4dzt52r2t5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>e5fvkxwrpn.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>8c4e2ghe7u.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>zq492l623r.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3rd42ekr43.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3qcr597p9d.skadnetwork</string>
</dict>
</array>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>UIApplicationSupportsIndirectInputEvents</key>
<true/> <true/>
<key>UIBackgroundModes</key> <key>UIBackgroundModes</key>
@ -259,5 +75,204 @@
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>SKAdNetworkItems</key>
<array>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>cstr6suwn9.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4fzdc2evr5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4pfyvq9l8r.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>2fnua5tdw4.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ydx93a7ass.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>5a6flpkh64.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>p78axxw29g.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>v72qych5uu.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ludvb6z3bs.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>cp8zw746q7.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3sh42y64q3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>c6k4g5qg8m.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>s39g8k73mm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3qy4746246.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>f38h382jlk.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>hs6bdukanm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>v4nxqhlyqp.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>wzmmz9fp6w.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>yclnxrl5pm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>t38b2kh725.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>7ug5zh24hu.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>gta9lk7p23.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>vutu7akeur.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>y5ghdn5j9k.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>n6fk4nfna4.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>v9wttpbfk9.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>n38lu8286q.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>47vhws6wlr.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>kbd757ywx3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>9t245vhmpl.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>eh6m2bh4zr.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>a2p9lx4jpn.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>22mmun2rn5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4468km3ulz.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>2u9pt9hc89.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>8s468mfl3y.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>klf5c3l5u5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ppxm28t8ap.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ecpz2srf59.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>uw77j35x4d.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>pwa73g5rt2.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>mlmmfzh3r3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>578prtvx9j.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4dzt52r2t5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>e5fvkxwrpn.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>8c4e2ghe7u.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>zq492l623r.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3rd42ekr43.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3qcr597p9d.skadnetwork</string>
</dict>
</array>
</dict> </dict>
</plist> </plist>

View File

@ -10,6 +10,7 @@ import 'package:tone_snap/data/models/ad_config_model.dart';
import 'package:tone_snap/data/storage/music_box.dart'; import 'package:tone_snap/data/storage/music_box.dart';
import 'package:tone_snap/firebase/firebase_analytics_manager.dart'; import 'package:tone_snap/firebase/firebase_analytics_manager.dart';
import 'package:tone_snap/modules/launch/launch_controller.dart'; import 'package:tone_snap/modules/launch/launch_controller.dart';
import 'package:tone_snap/modules/sideb/controllers/music_player_controller.dart';
import 'package:tone_snap/utils/log_util.dart'; import 'package:tone_snap/utils/log_util.dart';
import 'package:tone_snap/utils/obj_util.dart'; import 'package:tone_snap/utils/obj_util.dart';
@ -35,6 +36,9 @@ class InterstitialAdManager {
/// ///
bool isShowingAd = false; bool isShowingAd = false;
/// 广
bool showAdFrontIsPlaying = false;
/// 广 /// 广
void loadAdAll() { void loadAdAll() {
AdConfigModel adConfigModel = MusicBox().getAdConfig(); AdConfigModel adConfigModel = MusicBox().getAdConfig();
@ -90,33 +94,39 @@ class InterstitialAdManager {
/// ///
void _loadFailHandle(String adUnitId, String adScenes) { void _loadFailHandle(String adUnitId, String adScenes) {
AdConfigModel adConfigModel = MusicBox().getAdConfig(); int interval = 0;
var adList = _getAdList(adScenes); if (adScenes != AdScenes.coldLoading.name && adScenes != AdScenes.hotLoading.name) {
if (adList != null) { interval = 15;
var currentItem = adList.firstWhereOrNull((e) => e.identifier == adUnitId); }
if (currentItem != null) { Future.delayed(Duration(seconds: interval), () {
var nextItem = adList.firstWhereOrNull((e) => e.level == currentItem.level! + 1); AdConfigModel adConfigModel = MusicBox().getAdConfig();
if (nextItem != null) { var adList = _getAdList(adScenes);
// id加载失败id if (adList != null) {
loadAd(nextItem.identifier, adScenes); var currentItem = adList.firstWhereOrNull((e) => e.identifier == adUnitId);
} else {
// id都加载失败id
_loadSingleAd(adConfigModel.backup, adScenes);
}
} else {
var currentItem = adConfigModel.backup?.firstWhereOrNull((e) => e.identifier == adUnitId);
if (currentItem != null) { if (currentItem != null) {
var nextItem = adConfigModel.backup?.firstWhereOrNull((e) => e.level == currentItem.level! + 1); var nextItem = adList.firstWhereOrNull((e) => e.level == currentItem.level! + 1);
if (nextItem != null) { if (nextItem != null) {
// id加载失败id
loadAd(nextItem.identifier, adScenes); loadAd(nextItem.identifier, adScenes);
} else { } else {
if (adList.isNotEmpty) { // id都加载失败id
_loadSingleAd(adList, adScenes); _loadSingleAd(adConfigModel.backup, adScenes);
}
} else {
var currentItem = adConfigModel.backup?.firstWhereOrNull((e) => e.identifier == adUnitId);
if (currentItem != null) {
var nextItem = adConfigModel.backup?.firstWhereOrNull((e) => e.level == currentItem.level! + 1);
if (nextItem != null) {
loadAd(nextItem.identifier, adScenes);
} else {
if (adList.isNotEmpty) {
_loadSingleAd(adList, adScenes);
}
} }
} }
} }
} }
} });
} }
List<AdModel>? _getAdList(String adScenes) { List<AdModel>? _getAdList(String adScenes) {
@ -197,6 +207,11 @@ class InterstitialAdManager {
onAdShowedFullScreenContent: (ad) { onAdShowedFullScreenContent: (ad) {
LogUtil.d('$ad onAdShowedFullScreenContent'); LogUtil.d('$ad onAdShowedFullScreenContent');
isShowingAd = true; isShowingAd = true;
showAdFrontIsPlaying = MusicPlayerController.to.isPlaying.value;
if (showAdFrontIsPlaying) {
MusicPlayerController.to.pause();
}
}, },
// 广广 // 广广
onAdImpression: (ad) { onAdImpression: (ad) {
@ -217,11 +232,21 @@ class InterstitialAdManager {
onAdDismissedFullScreenContent: (ad) { onAdDismissedFullScreenContent: (ad) {
LogUtil.d('$ad onAdDismissedFullScreenContent'); LogUtil.d('$ad onAdDismissedFullScreenContent');
isShowingAd = false; isShowingAd = false;
if (showAdFrontIsPlaying) {
MusicPlayerController.to.play();
}
_closeDateTime = DateTime.now(); _closeDateTime = DateTime.now();
ad.dispose(); ad.dispose();
loadAd(_interstitialAdMap[adScenes]?.adUnitId, adScenes);
_interstitialAdMap[adScenes] = null; int interval = 0;
_interstitialAdMap.remove(adScenes); if (adScenes != AdScenes.coldLoading.name && adScenes != AdScenes.hotLoading.name) {
interval = 15;
}
Future.delayed(Duration(seconds: interval), () {
loadAd(_interstitialAdMap[adScenes]?.adUnitId, adScenes);
_interstitialAdMap[adScenes] = null;
_interstitialAdMap.remove(adScenes);
});
if(onTap != null) onTap(); if(onTap != null) onTap();
}, },

View File

@ -17,14 +17,16 @@ class ViewStateWidget extends StatelessWidget {
super.key, super.key,
required this.viewState, required this.viewState,
required this.child, required this.child,
this.cpiBgColor, this.loadColor,
this.loadBgColor,
this.showTryAgain = false, this.showTryAgain = false,
this.onTapTryAgain, this.onTapTryAgain,
}); });
final ViewState viewState; final ViewState viewState;
final Widget child; final Widget child;
final Color? cpiBgColor; final Color? loadColor;
final Color? loadBgColor;
final bool showTryAgain; final bool showTryAgain;
final Function()? onTapTryAgain; final Function()? onTapTryAgain;
@ -34,7 +36,7 @@ class ViewStateWidget extends StatelessWidget {
case ViewState.normal: case ViewState.normal:
return child; return child;
case ViewState.loading: case ViewState.loading:
return loadingView(backgroundColor: cpiBgColor); return loadingView(loadColor: loadColor, loadBgColor: loadBgColor);
case ViewState.empty: case ViewState.empty:
return AppConfig.appSideEnum == AppSideEnum.sideA ? emptyViewA() : emptyViewB( return AppConfig.appSideEnum == AppSideEnum.sideA ? emptyViewA() : emptyViewB(
showTryAgain: showTryAgain, showTryAgain: showTryAgain,
@ -48,14 +50,14 @@ class ViewStateWidget extends StatelessWidget {
/// ///
Widget loadingView({ Widget loadingView({
Color? color, Color? loadColor,
Color? backgroundColor, Color? loadBgColor,
}) { }) {
return Center( return Center(
child: CircularProgressIndicator( child: CircularProgressIndicator(
strokeWidth: 2.w, strokeWidth: 2.w,
color: AppConfig.appSideEnum == AppSideEnum.sideA ? color : seedColor, color: AppConfig.appSideEnum == AppSideEnum.sideB ? loadColor ?? seedColor : loadColor,
backgroundColor: backgroundColor, backgroundColor: loadBgColor,
), ),
); );
} }

View File

@ -11,7 +11,7 @@ class MusicCacheManager {
Config( Config(
key, key,
stalePeriod: const Duration(days: 7), stalePeriod: const Duration(days: 7),
maxNrOfCacheObjects: 30, maxNrOfCacheObjects: 100,
), ),
); );

View File

@ -0,0 +1,17 @@
// Author: fengshengxiong
// Date: 2024/6/26
// Description: facebook管理
import 'package:facebook_app_events/facebook_app_events.dart';
import 'package:tone_snap/utils/log_util.dart';
class FacebookManager {
static Future<void> init() async {
try {
await FacebookAppEvents().setAdvertiserTracking(enabled: true);
await FacebookAppEvents().setAutoLogAppEventsEnabled(true);
} catch (e) {
LogUtil.d(e.toString());
}
}
}

View File

@ -10,10 +10,10 @@ import 'package:tone_snap/utils/log_util.dart';
import 'package:tone_snap/utils/obj_util.dart'; import 'package:tone_snap/utils/obj_util.dart';
class FirebaseRemoteConfigManager { class FirebaseRemoteConfigManager {
static Future<void> getAll() async { static Future<void> getAllConfig() async {
final remoteConfig = FirebaseRemoteConfig.instance; final remoteConfig = FirebaseRemoteConfig.instance;
await remoteConfig.setConfigSettings(RemoteConfigSettings( await remoteConfig.setConfigSettings(RemoteConfigSettings(
fetchTimeout: const Duration(minutes: 1), fetchTimeout: const Duration(seconds: 30),
minimumFetchInterval: Duration.zero, minimumFetchInterval: Duration.zero,
)); ));
bool result = await remoteConfig.fetchAndActivate(); bool result = await remoteConfig.fetchAndActivate();

View File

@ -30,13 +30,13 @@ class AppConfig {
"coldLoading": [ "coldLoading": [
{ {
"level": 1, "level": 1,
"identifier": "ca-app-pub-5684307632319406/5757639118", "identifier": "",
"ad": "AdMob", "ad": "AdMob",
"type": "Insert" "type": "Insert"
}, },
{ {
"level": 2, "level": 2,
"identifier": "ca-app-pub-5684307632319406/5852437064", "identifier": "",
"ad": "AdMob", "ad": "AdMob",
"type": "Insert" "type": "Insert"
} }

View File

@ -25,7 +25,7 @@ class NetworkConnectivityService extends GetxService {
if (!isExecutedTask) { if (!isExecutedTask) {
isExecutedTask = true; isExecutedTask = true;
FirebaseRemoteConfigManager.getAll(); FirebaseRemoteConfigManager.getAllConfig();
InterstitialAdManager().loadAdAll(); InterstitialAdManager().loadAdAll();
// LibraryNativeAdManager().loadNativeAd(); // LibraryNativeAdManager().loadNativeAd();

View File

@ -1,5 +1,3 @@
import 'dart:io';
import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -8,8 +6,10 @@ import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:just_audio_background/just_audio_background.dart';
import 'package:tone_snap/components/base_easyloading.dart'; import 'package:tone_snap/components/base_easyloading.dart';
import 'package:tone_snap/data/storage/hive_storage.dart'; import 'package:tone_snap/data/storage/hive_storage.dart';
import 'package:tone_snap/facebook/facebook_manager.dart';
import 'package:tone_snap/firebase/firebase_crashlytics_manager.dart'; import 'package:tone_snap/firebase/firebase_crashlytics_manager.dart';
import 'package:tone_snap/firebase/firebase_options.dart'; import 'package:tone_snap/firebase/firebase_options.dart';
import 'package:tone_snap/global/app_config.dart'; import 'package:tone_snap/global/app_config.dart';
@ -25,6 +25,9 @@ import 'package:tone_snap/utils/log_util.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
// Hive
await initHive();
// Firebase // Firebase
try { try {
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
@ -35,6 +38,8 @@ void main() async {
LogUtil.e("Firebase initialization error: $e"); LogUtil.e("Firebase initialization error: $e");
} }
await FacebookManager.init();
// 广 SDK // 广 SDK
try { try {
MobileAds.instance.initialize(); MobileAds.instance.initialize();
@ -42,10 +47,17 @@ void main() async {
LogUtil.e("MobileAds initialization error: $e"); LogUtil.e("MobileAds initialization error: $e");
} }
// Hive try {
await initHive(); await JustAudioBackground.init(
androidNotificationChannelId: 'com.ryanheise.bg_demo.channel.audio',
runApp(const MyApp()); androidNotificationChannelName: 'Audio playback',
androidNotificationIcon: 'mipmap/launcher_icon',
// androidNotificationOngoing: true,
androidStopForegroundOnPause: false,
);
} catch (e) {
LogUtil.e(e.toString());
}
// //
SystemChrome.setPreferredOrientations([ SystemChrome.setPreferredOrientations([
@ -53,14 +65,16 @@ void main() async {
DeviceOrientation.portraitDown, DeviceOrientation.portraitDown,
]); ]);
// //
if (Platform.isAndroid) { SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( statusBarColor: Colors.transparent,
statusBarColor: Colors.transparent, statusBarBrightness: Brightness.dark,
systemNavigationBarColor: Colors.black, statusBarIconBrightness: Brightness.dark,
systemNavigationBarIconBrightness: Brightness.light, systemNavigationBarColor: Colors.black,
)); systemNavigationBarIconBrightness: Brightness.light,
} ));
runApp(const MyApp());
} }
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {

View File

@ -92,9 +92,9 @@ class LaunchController extends GetxController with GetSingleTickerProviderStateM
onTap: () { onTap: () {
AppConfig.appSideEnum = AppSideEnum.sideA; AppConfig.appSideEnum = AppSideEnum.sideA;
Get.offNamed(AppRoutes.initialA); Get.offNamed(AppRoutes.initialA);
FirebaseAnalyticsManager.logJumpEvent('A', '版本相同,开关关闭');
}, },
); );
FirebaseAnalyticsManager.logJumpEvent('A', '版本相同,开关关闭');
} }
void _openSideB(String reason) { void _openSideB(String reason) {
@ -105,8 +105,8 @@ class LaunchController extends GetxController with GetSingleTickerProviderStateM
MainController.to.changeTheme(); MainController.to.changeTheme();
Get.offNamed(AppRoutes.initialB); Get.offNamed(AppRoutes.initialB);
MusicBox().putIsOpenedSideB(true); MusicBox().putIsOpenedSideB(true);
FirebaseAnalyticsManager.logJumpEvent('B', reason);
}, },
); );
FirebaseAnalyticsManager.logJumpEvent('B', reason);
} }
} }

View File

@ -8,9 +8,12 @@ import 'dart:io';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:just_audio/just_audio.dart'; import 'package:just_audio/just_audio.dart';
import 'package:just_audio_background/just_audio_background.dart';
import 'package:tone_snap/components/base_easyloading.dart'; import 'package:tone_snap/components/base_easyloading.dart';
import 'package:tone_snap/global/app_config.dart';
import 'package:tone_snap/utils/audio_util.dart'; import 'package:tone_snap/utils/audio_util.dart';
import 'package:tone_snap/utils/log_util.dart'; import 'package:tone_snap/utils/log_util.dart';
import 'package:tone_snap/utils/obj_util.dart';
class PlayerController extends GetxController { class PlayerController extends GetxController {
static PlayerController get to => Get.put(PlayerController()); static PlayerController get to => Get.put(PlayerController());
@ -45,11 +48,15 @@ class PlayerController extends GetxController {
if (this.filePath != filePath) { if (this.filePath != filePath) {
this.filePath = filePath; this.filePath = filePath;
try { try {
final mediaItem = MediaItem(
id: filePath,
title: AppConfig.appName,
);
isReady = false; isReady = false;
if (filePath.contains('assets')) { if (filePath.contains('assets')) {
duration.value = await _player.setAsset(filePath) ?? Duration.zero; duration.value = await _player.setAsset(filePath, tag: mediaItem) ?? Duration.zero;
} else { } else {
duration.value = await _player.setFilePath(filePath) ?? Duration.zero; duration.value = await _player.setFilePath(filePath, tag: mediaItem) ?? Duration.zero;
} }
isReady = true; isReady = true;
} on PlayerException catch (e) { } on PlayerException catch (e) {

View File

@ -5,8 +5,10 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:easy_debounce/easy_debounce.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:just_audio/just_audio.dart'; import 'package:just_audio/just_audio.dart';
import 'package:just_audio_background/just_audio_background.dart';
import 'package:tone_snap/components/base_easyloading.dart'; import 'package:tone_snap/components/base_easyloading.dart';
import 'package:tone_snap/data/api/music_api.dart'; import 'package:tone_snap/data/api/music_api.dart';
import 'package:tone_snap/data/cache/music_cache_manager.dart'; import 'package:tone_snap/data/cache/music_cache_manager.dart';
@ -17,7 +19,6 @@ import 'package:tone_snap/data/storage/music_box.dart';
import 'package:tone_snap/data/storage/offline_box.dart'; import 'package:tone_snap/data/storage/offline_box.dart';
import 'package:tone_snap/firebase/firebase_analytics_manager.dart'; import 'package:tone_snap/firebase/firebase_analytics_manager.dart';
import 'package:tone_snap/modules/sideb/music_bar/music_bar.dart'; import 'package:tone_snap/modules/sideb/music_bar/music_bar.dart';
import 'package:tone_snap/routes/app_routes.dart';
import 'package:tone_snap/utils/audio_util.dart'; import 'package:tone_snap/utils/audio_util.dart';
import 'package:tone_snap/utils/log_util.dart'; import 'package:tone_snap/utils/log_util.dart';
import 'package:tone_snap/utils/num_util.dart'; import 'package:tone_snap/utils/num_util.dart';
@ -106,8 +107,15 @@ class MusicPlayerController extends GetxController {
if (playlist.isNotEmpty) { if (playlist.isNotEmpty) {
FirebaseAnalyticsManager.logPlayerBpv(getMusicModel()?.videoId, getMusicModel()?.title, getMusicModel()?.subtitle); FirebaseAnalyticsManager.logPlayerBpv(getMusicModel()?.videoId, getMusicModel()?.title, getMusicModel()?.subtitle);
resetPlaybackStatus(); resetPlaybackStatus();
Get.currentRoute == AppRoutes.playPage ? MusicBar().hide() : MusicBar().show(); // Get.currentRoute == AppRoutes.playPage ? MusicBar().hide() : MusicBar().show();
try { try {
final mediaItem = MediaItem(
id: ObjUtil.getStr(getMusicModel()?.videoId),
artist: ObjUtil.getStr(getMusicModel()?.subtitle),
title: ObjUtil.getStr(getMusicModel()?.title),
artUri: Uri.parse(ObjUtil.getStr(getMusicModel()?.coverUrl)),
);
DateTime startLoadDateTime = DateTime.now(); DateTime startLoadDateTime = DateTime.now();
var model = OfflineBox().getList().firstWhereOrNull((e) => e.videoId == getMusicModel()?.videoId); var model = OfflineBox().getList().firstWhereOrNull((e) => e.videoId == getMusicModel()?.videoId);
if (model != null && ObjUtil.isNotEmpty(model.localPath)) { if (model != null && ObjUtil.isNotEmpty(model.localPath)) {
@ -118,7 +126,7 @@ class MusicPlayerController extends GetxController {
FirebaseAnalyticsManager.logPlayerBFailAction('本地文件不存在'); FirebaseAnalyticsManager.logPlayerBFailAction('本地文件不存在');
return; return;
} }
await _player.setFilePath(model.localPath!); await _player.setFilePath(model.localPath!, tag: mediaItem);
} else { } else {
// //
var fileInfo = await MusicCacheManager.checkCache(getMusicModel()?.videoId); var fileInfo = await MusicCacheManager.checkCache(getMusicModel()?.videoId);
@ -126,14 +134,14 @@ class MusicPlayerController extends GetxController {
// //
LogUtil.d('读取缓存路径=${fileInfo.file.path}'); LogUtil.d('读取缓存路径=${fileInfo.file.path}');
// 使 // 使
await _player.setFilePath(fileInfo.file.path); await _player.setFilePath(fileInfo.file.path, tag: mediaItem);
} else { } else {
// //
final url = await _getMusicUrl(); final url = await _getMusicUrl();
if (ObjUtil.isEmpty(url)) { if (ObjUtil.isEmpty(url)) {
return; return;
} }
await _player.setUrl(url!); await _player.setUrl(url!, tag: mediaItem);
// //
_cacheManager.downloadFile(url, key: MusicCacheManager.getCacheKey(getMusicModel()!.videoId!)).then((fileInfo) { _cacheManager.downloadFile(url, key: MusicCacheManager.getCacheKey(getMusicModel()!.videoId!)).then((fileInfo) {
LogUtil.d('缓存下载路径=${fileInfo.file.path}'); LogUtil.d('缓存下载路径=${fileInfo.file.path}');
@ -175,6 +183,10 @@ class MusicPlayerController extends GetxController {
/// ///
void _addListening() { void _addListening() {
_player.playbackEventStream.listen((event) {},
onError: (Object e, StackTrace stackTrace) {
LogUtil.e('A stream error occurred: $e');
});
_durationSubscription = _player.durationStream.listen((duration) { _durationSubscription = _player.durationStream.listen((duration) {
totalDuration.value = duration ?? Duration.zero; totalDuration.value = duration ?? Duration.zero;
}); });
@ -265,73 +277,97 @@ class MusicPlayerController extends GetxController {
} }
/// / /// /
Future<void> playPause() async { void playPause() {
if (_player.playing) { if (_player.playing) {
_player.pause(); pause();
} else { } else {
if (processingState.value == ProcessingState.ready) { play();
_player.play();
}
} }
} }
///
void play() {
if (processingState.value == ProcessingState.ready) {
_player.play();
}
}
///
void pause() {
_player.pause();
}
/// ///
Future<void> previousTrack() async { Future<void> previousTrack() async {
if (playlist.length > 1) { // PlatformException
switch(playMode.value) { EasyDebounce.debounce(
case PlayMode.listLoop: 'cutTheSong',
currentIndex.value = (currentIndex.value - 1 + playlist.length) % playlist.length; const Duration(milliseconds: 300),
_startPlay(); () {
break; if (playlist.length > 1) {
case PlayMode.random: switch(playMode.value) {
bool historyExist = false; case PlayMode.listLoop:
for (var i = _playHistory.length - 1; i >= 0; --i) { currentIndex.value = (currentIndex.value - 1 + playlist.length) % playlist.length;
var history = _playHistory[i]; _startPlay();
MusicModel? model = playlist.firstWhereOrNull((e) => e.videoId == history); break;
if (model != null) { case PlayMode.random:
currentIndex.value = playlist.indexOf(model); bool historyExist = false;
_playHistory.remove(history); for (var i = _playHistory.length - 1; i >= 0; --i) {
historyExist = true; var history = _playHistory[i];
MusicModel? model = playlist.firstWhereOrNull((e) => e.videoId == history);
if (model != null) {
currentIndex.value = playlist.indexOf(model);
_playHistory.remove(history);
historyExist = true;
break;
} else {
_playHistory.remove(history);
}
}
if (!historyExist) {
currentIndex.value = _getRandomNumber();
}
_startPlay();
break;
case PlayMode.singleCycle:
currentIndex.value = (currentIndex.value - 1 + playlist.length) % playlist.length;
_startPlay();
break; break;
} else {
_playHistory.remove(history);
}
} }
if (!historyExist) { }
currentIndex.value = _getRandomNumber(); },
} );
_startPlay();
break;
case PlayMode.singleCycle:
currentIndex.value = (currentIndex.value - 1 + playlist.length) % playlist.length;
_startPlay();
break;
}
}
} }
/// ///
Future<void> nextTrack({bool manualSwitch = true}) async { Future<void> nextTrack({bool manualSwitch = true}) async {
if (playlist.length > 1) { // PlatformException
switch(playMode.value) { EasyDebounce.debounce(
case PlayMode.listLoop: 'cutTheSong',
currentIndex.value = (currentIndex.value + 1) % playlist.length; const Duration(milliseconds: 300),
_startPlay(); () {
break; if (playlist.length > 1) {
case PlayMode.random: switch(playMode.value) {
// case PlayMode.listLoop:
_playHistory.add(getMusicModel()!.videoId!); currentIndex.value = (currentIndex.value + 1) % playlist.length;
currentIndex.value = _getRandomNumber(); _startPlay();
_startPlay(); break;
break; case PlayMode.random:
case PlayMode.singleCycle: //
if (manualSwitch) { _playHistory.add(getMusicModel()!.videoId!);
currentIndex.value = (currentIndex.value + 1) % playlist.length; currentIndex.value = _getRandomNumber();
_startPlay(); _startPlay();
break;
case PlayMode.singleCycle:
if (manualSwitch) {
currentIndex.value = (currentIndex.value + 1) % playlist.length;
_startPlay();
}
break;
} }
break; }
} },
} );
} }
/// ///

View File

@ -100,24 +100,32 @@ class MusicBarView extends StatelessWidget {
], ],
), ),
), ),
SizedBox(width: 13.w), SizedBox(width: 3.w),
Obx(() { Obx(() {
return GestureDetector( return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: musicPlayerController.playPause, onTap: musicPlayerController.playPause,
child: Image.asset( child: Padding(
musicPlayerController.isPlaying.value ? Assets.sideBPausePlay : Assets.sideBStartPlay, padding: const EdgeInsets.all(10).w,
width: 24.w, child: Image.asset(
height: 24.w, musicPlayerController.isPlaying.value ? Assets.sideBPausePlay : Assets.sideBStartPlay,
width: 24.w,
height: 24.w,
),
), ),
); );
}), }),
SizedBox(width: 26.w), SizedBox(width: 6.w),
GestureDetector( GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: musicPlayerController.nextTrack, onTap: musicPlayerController.nextTrack,
child: Image.asset( child: Padding(
Assets.sideBMusicBarNext, padding: const EdgeInsets.all(10).w,
width: 24.w, child: Image.asset(
height: 24.w, Assets.sideBMusicBarNext,
width: 24.w,
height: 24.w,
),
), ),
), ),
], ],

View File

@ -108,21 +108,23 @@ class SearchMusicView extends GetView<SearchMusicController> {
spacing: 8.w, spacing: 8.w,
runSpacing: 8.h, runSpacing: 8.h,
children: controller.historyList.map((history) { children: controller.historyList.map((history) {
return InkWell( return ClipRRect(
onTap: () => controller.onTapHistoryItem(history), borderRadius: BorderRadius.circular(30).r,
child: IntrinsicWidth( child: Material(
child: Container( color: const Color(0xFF1F1F1F),
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 4.h), child: InkWell(
decoration: BoxDecoration( onTap: () => controller.onTapHistoryItem(history),
color: const Color(0xFF1F1F1F), child: IntrinsicWidth(
borderRadius: BorderRadius.circular(30).r, child: Container(
), padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 4.h),
alignment: Alignment.center, alignment: Alignment.center,
child: Text( child: Text(
history, history,
style: TextStyle( style: TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 12.sp, fontSize: 12.sp,
),
),
), ),
), ),
), ),

View File

@ -2,13 +2,23 @@
// Date: 2024/6/21 // Date: 2024/6/21
// Description: Item // Description: Item
import 'package:background_downloader/background_downloader.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:tone_snap/components/base_easyloading.dart';
import 'package:tone_snap/components/dialog/remind_dialog.dart';
import 'package:tone_snap/components/network_image_widget.dart'; import 'package:tone_snap/components/network_image_widget.dart';
import 'package:tone_snap/data/models/music_model.dart'; import 'package:tone_snap/data/models/music_model.dart';
import 'package:tone_snap/data/storage/offline_box.dart';
import 'package:tone_snap/generated/assets.dart'; import 'package:tone_snap/generated/assets.dart';
import 'package:tone_snap/global/download_manager.dart';
import 'package:tone_snap/modules/sideb/controllers/music_player_controller.dart';
import 'package:tone_snap/modules/sideb/more_bottom_sheet/more_bottom_sheet_view.dart'; import 'package:tone_snap/modules/sideb/more_bottom_sheet/more_bottom_sheet_view.dart';
import 'package:tone_snap/modules/sideb/offline/offline_controller.dart';
import 'package:tone_snap/modules/sideb/personal_music_library/personal_music_library_controller.dart';
import 'package:tone_snap/modules/sideb/widgets/music_item_marquee_text.dart';
import 'package:tone_snap/res/themes/app_colors.dart';
import 'package:tone_snap/utils/obj_util.dart'; import 'package:tone_snap/utils/obj_util.dart';
class BrowseItemAtv extends StatelessWidget { class BrowseItemAtv extends StatelessWidget {
@ -31,6 +41,7 @@ class BrowseItemAtv extends StatelessWidget {
children: [ children: [
_buildCover(), _buildCover(),
_buildContent(), _buildContent(),
_buildDownload(),
_buildMore(), _buildMore(),
], ],
), ),
@ -57,26 +68,63 @@ class BrowseItemAtv extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Obx(() {
ObjUtil.getStr(musicModel.title), return MusicItemMarqueeText(
maxLines: 1, text: musicModel.title,
overflow: TextOverflow.ellipsis, showMarquee: MusicPlayerController.to.getMusicModel()?.videoId == musicModel.videoId && ObjUtil.isNotEmpty(musicModel.videoId),
style: TextStyle( );
color: Colors.white, }),
fontSize: 14.sp,
),
),
SizedBox(height: 4.h), SizedBox(height: 4.h),
Text( Obx(() {
ObjUtil.getStr(musicModel.subtitle), return MusicItemMarqueeText(
maxLines: 1, text: musicModel.subtitle,
overflow: TextOverflow.ellipsis, isTitle: false,
style: TextStyle( showMarquee: MusicPlayerController.to.getMusicModel()?.videoId == musicModel.videoId && ObjUtil.isNotEmpty(musicModel.videoId),
color: const Color(0xFF666666), );
fontSize: 12.sp, }),
],
),
),
);
}
Widget _buildDownload() {
return ClipOval(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: onTapDownload,
child: Padding(
padding: const EdgeInsets.all(4).w,
child: SizedBox(
width: 24.w,
height: 24.w,
child: GetBuilder<DownloadManager>(
id: DownloadManager.to.downloadStateId,
builder: (_) {
if (OfflineBox().checkDownloaded(musicModel.videoId)) {
return Image.asset(Assets.sideBDownloaded);
} else {
if (DownloadManager.to.getMusicModel(musicModel.videoId)?.taskStatus == TaskStatus.enqueued) {
return CircularProgressIndicator(
color: seedColor,
strokeWidth: 2.w,
);
} else if (DownloadManager.to.getMusicModel(musicModel.videoId)?.taskStatus == TaskStatus.running) {
return CircularProgressIndicator(
value: DownloadManager.to.getMusicModel(musicModel.videoId)?.progress,
backgroundColor: seedColor.withOpacity(0.2),
valueColor: const AlwaysStoppedAnimation<Color>(seedColor),
strokeWidth: 2.w,
);
} else {
return Image.asset(Assets.sideBNotDownload2);
}
}
},
), ),
), ),
], ),
), ),
), ),
); );
@ -101,6 +149,34 @@ class BrowseItemAtv extends StatelessWidget {
); );
} }
void onTapDownload() {
if (OfflineBox().checkDownloaded(musicModel.videoId)) {
Get.dialog(
RemindDialog(
content: 'Confirm to remove this song?',
confirmOnTap: () async {
await OfflineBox().delete(musicModel.videoId!);
DownloadManager.to.updateDownloadState();
BaseEasyLoading.toast('Removed');
if (Get.isRegistered<PersonalMusicLibraryController>()) {
PersonalMusicLibraryController.to.refreshOffline();
}
if (Get.isRegistered<OfflineController>()) {
OfflineController.to.getOfflineList();
}
},
),
);
} else {
if (DownloadManager.to.getMusicModel(musicModel.videoId)?.taskStatus == TaskStatus.enqueued
|| DownloadManager.to.getMusicModel(musicModel.videoId)?.taskStatus == TaskStatus.running) {
DownloadManager.to.cancelDownload(musicModel.videoId);
} else {
DownloadManager.to.downloadMusic(musicModel);
}
}
}
void onTapMore() { void onTapMore() {
Get.bottomSheet( Get.bottomSheet(
MoreBottomSheetView( MoreBottomSheetView(

View File

@ -18,7 +18,8 @@ class WebPageView extends StatelessWidget {
body: Obx(() { body: Obx(() {
return ViewStateWidget( return ViewStateWidget(
viewState: controller.viewState.value, viewState: controller.viewState.value,
cpiBgColor: Colors.white, loadColor: Colors.black,
loadBgColor: Colors.white,
child: WebViewWidget(controller: controller.webViewController), child: WebViewWidget(controller: controller.webViewController),
); );
}), }),

View File

@ -8,6 +8,7 @@ class AudioUtil {
static Future<void> configAudioSession() async { static Future<void> configAudioSession() async {
final session = await AudioSession.instance; final session = await AudioSession.instance;
await session.configure(const AudioSessionConfiguration.music()); await session.configure(const AudioSessionConfiguration.music());
await session.setActive(true);
// await session.configure(AudioSessionConfiguration( // await session.configure(AudioSessionConfiguration(
// avAudioSessionCategory: AVAudioSessionCategory.playback, // avAudioSessionCategory: AVAudioSessionCategory.playback,
// avAudioSessionCategoryOptions: // avAudioSessionCategoryOptions:

View File

@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.0.5+15 version: 1.0.6+17
environment: environment:
sdk: '>=3.4.1 <4.0.0' sdk: '>=3.4.1 <4.0.0'
@ -77,6 +77,7 @@ dependencies:
audio_session: ^0.1.21 audio_session: ^0.1.21
flutter_sound: ^9.4.18 flutter_sound: ^9.4.18
just_audio: ^0.9.39 just_audio: ^0.9.39
just_audio_background: ^0.0.1-beta.13
# ffmpeg_kit_flutter: ^6.0.3 # ffmpeg_kit_flutter: ^6.0.3
ffmpeg_kit_flutter_audio: 6.0.3-LTS ffmpeg_kit_flutter_audio: 6.0.3-LTS
@ -105,6 +106,9 @@ dependencies:
firebase_crashlytics: ^4.0.3 firebase_crashlytics: ^4.0.3
firebase_remote_config: ^5.0.3 firebase_remote_config: ^5.0.3
# facebook
facebook_app_events: ^0.19.2
# 网络 # 网络
connectivity_plus: ^6.0.4 connectivity_plus: ^6.0.4
@ -114,8 +118,12 @@ dependencies:
# 对键盘可见性变化做出反应 # 对键盘可见性变化做出反应
flutter_keyboard_visibility: ^6.0.0 flutter_keyboard_visibility: ^6.0.0
# 进度条
step_progress_indicator: ^1.0.2 step_progress_indicator: ^1.0.2
# 防抖、节流
easy_debounce: ^2.0.3
flutter_launcher_icons: flutter_launcher_icons:
android: "launcher_icon" android: "launcher_icon"
ios: true ios: true