1.新增瀑布流插页广告
2.新增增埋点
This commit is contained in:
parent
da21720c3c
commit
caded892d9
@ -1,5 +1,9 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "com.android.application"
|
id "com.android.application"
|
||||||
|
// START: FlutterFire Configuration
|
||||||
|
id 'com.google.gms.google-services'
|
||||||
|
id 'com.google.firebase.crashlytics'
|
||||||
|
// END: FlutterFire Configuration
|
||||||
id "kotlin-android"
|
id "kotlin-android"
|
||||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||||
id "dev.flutter.flutter-gradle-plugin"
|
id "dev.flutter.flutter-gradle-plugin"
|
||||||
|
|||||||
29
android/app/google-services.json
Normal file
29
android/app/google-services.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "280378307504",
|
||||||
|
"project_id": "tonesnap-and",
|
||||||
|
"storage_bucket": "tonesnap-and.appspot.com"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:280378307504:android:bcee5d63088dcbb7ca5c75",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.tone.music.offline"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyCLEOFjenMfiZKdoKdGh9mylckpIpTn854"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
||||||
@ -48,7 +48,7 @@
|
|||||||
<!--AdMob app ID-->
|
<!--AdMob app ID-->
|
||||||
<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~7113477061"/>
|
android:value="ca-app-pub-5684307632319406~5753747604"/>
|
||||||
</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
|
||||||
|
|||||||
@ -19,6 +19,10 @@ pluginManagement {
|
|||||||
plugins {
|
plugins {
|
||||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
id "com.android.application" version "7.3.0" apply false
|
id "com.android.application" version "7.3.0" apply false
|
||||||
|
// START: FlutterFire Configuration
|
||||||
|
id "com.google.gms.google-services" version "4.3.15" apply false
|
||||||
|
id "com.google.firebase.crashlytics" version "2.8.1" apply false
|
||||||
|
// END: FlutterFire Configuration
|
||||||
// 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
|
id "org.jetbrains.kotlin.android" version "1.9.20" apply false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 = 12;
|
CURRENT_PROJECT_VERSION = 15;
|
||||||
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 = 12;
|
CURRENT_PROJECT_VERSION = 15;
|
||||||
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 = 12;
|
CURRENT_PROJECT_VERSION = 15;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = UH427LWP22;
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = UH427LWP22;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||||
|
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
<!--Flutter View Controller-->
|
<!--Flutter View Controller-->
|
||||||
@ -14,13 +16,14 @@
|
|||||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||||
</layoutGuides>
|
</layoutGuides>
|
||||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</view>
|
</view>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
|
<point key="canvasLocation" x="-16" y="-40"/>
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
</document>
|
</document>
|
||||||
|
|||||||
@ -20,17 +20,17 @@ class AppOpenAdManager {
|
|||||||
|
|
||||||
factory AppOpenAdManager() => _instance;
|
factory AppOpenAdManager() => _instance;
|
||||||
|
|
||||||
|
AppOpenAd? _appOpenAd;
|
||||||
|
bool _isShowingAd = false;
|
||||||
|
|
||||||
/// 加载和显示广告之间允许的最长持续时间
|
/// 加载和显示广告之间允许的最长持续时间
|
||||||
final Duration maxCacheDuration = const Duration(hours: 4);
|
final Duration _maxCacheDuration = const Duration(minutes: 50);
|
||||||
|
|
||||||
/// 跟踪加载时间,这样我们就不会显示过期的广告
|
/// 跟踪加载时间,这样我们就不会显示过期的广告
|
||||||
DateTime? _appOpenLoadTime;
|
DateTime? _appOpenLoadTime;
|
||||||
|
|
||||||
AppOpenAd? _appOpenAd;
|
|
||||||
bool _isShowingAd = false;
|
|
||||||
|
|
||||||
/// 记录关闭时的时间,用于下一次展示时计算时间差
|
/// 记录关闭时的时间,用于下一次展示时计算时间差
|
||||||
DateTime? closeDateTime;
|
DateTime? _closeDateTime;
|
||||||
|
|
||||||
/// 开屏广告单元id
|
/// 开屏广告单元id
|
||||||
final adUnitId = Platform.isAndroid
|
final adUnitId = Platform.isAndroid
|
||||||
@ -41,6 +41,7 @@ class AppOpenAdManager {
|
|||||||
Future<void> loadAd() async {
|
Future<void> loadAd() async {
|
||||||
final List<ConnectivityResult> connectivityResult = await (Connectivity().checkConnectivity());
|
final List<ConnectivityResult> connectivityResult = await (Connectivity().checkConnectivity());
|
||||||
if (connectivityResult.contains(ConnectivityResult.none)) {
|
if (connectivityResult.contains(ConnectivityResult.none)) {
|
||||||
|
LogUtil.d('当前无网络,不加载广告');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isAdAvailable) {
|
if (isAdAvailable) {
|
||||||
@ -87,7 +88,7 @@ class AppOpenAdManager {
|
|||||||
if(onTap != null) onTap();
|
if(onTap != null) onTap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (DateTime.now().subtract(maxCacheDuration).isAfter(_appOpenLoadTime!)) {
|
if (DateTime.now().subtract(_maxCacheDuration).isAfter(_appOpenLoadTime!)) {
|
||||||
LogUtil.d('超过了最大缓存持续时间。正在加载另一个广告');
|
LogUtil.d('超过了最大缓存持续时间。正在加载另一个广告');
|
||||||
_appOpenAd!.dispose();
|
_appOpenAd!.dispose();
|
||||||
_appOpenAd = null;
|
_appOpenAd = null;
|
||||||
@ -95,9 +96,9 @@ class AppOpenAdManager {
|
|||||||
if(onTap != null) onTap();
|
if(onTap != null) onTap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (closeDateTime != null) {
|
if (_closeDateTime != null) {
|
||||||
// 计算时间差
|
// 计算时间差
|
||||||
Duration timeDifference = DateTime.now().difference(closeDateTime!);
|
Duration timeDifference = DateTime.now().difference(_closeDateTime!);
|
||||||
// 获取配置的 openAppEventDuration
|
// 获取配置的 openAppEventDuration
|
||||||
int openAppEventDuration = MusicBox().getOpenAppEventDuration();
|
int openAppEventDuration = MusicBox().getOpenAppEventDuration();
|
||||||
// 检查时间差是否小于10秒
|
// 检查时间差是否小于10秒
|
||||||
@ -130,7 +131,7 @@ class AppOpenAdManager {
|
|||||||
},
|
},
|
||||||
onAdDismissedFullScreenContent: (ad) {
|
onAdDismissedFullScreenContent: (ad) {
|
||||||
LogUtil.d('$ad onAdDismissedFullScreenContent');
|
LogUtil.d('$ad onAdDismissedFullScreenContent');
|
||||||
closeDateTime = DateTime.now();
|
_closeDateTime = DateTime.now();
|
||||||
|
|
||||||
// 显示状态栏(用户关闭广告后)
|
// 显示状态栏(用户关闭广告后)
|
||||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values);
|
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values);
|
||||||
|
|||||||
@ -2,12 +2,16 @@
|
|||||||
// Date: 2024/6/25
|
// Date: 2024/6/25
|
||||||
// Description: 插页广告
|
// Description: 插页广告
|
||||||
|
|
||||||
import 'dart:io' show Platform;
|
|
||||||
|
|
||||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||||
import 'package:flutter/foundation.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:tone_snap/data/enum/ad_scenes.dart';
|
||||||
|
import 'package:tone_snap/data/models/ad_config_model.dart';
|
||||||
|
import 'package:tone_snap/data/storage/music_box.dart';
|
||||||
|
import 'package:tone_snap/firebase/firebase_analytics_manager.dart';
|
||||||
|
import 'package:tone_snap/modules/launch/launch_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';
|
||||||
|
|
||||||
class InterstitialAdManager {
|
class InterstitialAdManager {
|
||||||
InterstitialAdManager._();
|
InterstitialAdManager._();
|
||||||
@ -16,97 +20,208 @@ class InterstitialAdManager {
|
|||||||
|
|
||||||
factory InterstitialAdManager() => _instance;
|
factory InterstitialAdManager() => _instance;
|
||||||
|
|
||||||
|
/// 广告对象Map
|
||||||
|
final Map<String, InterstitialAd?> _interstitialAdMap = {};
|
||||||
|
|
||||||
/// 加载和显示广告之间允许的最长持续时间
|
/// 加载和显示广告之间允许的最长持续时间
|
||||||
final Duration maxCacheDuration = const Duration(hours: 4);
|
final Duration _maxCacheDuration = const Duration(minutes: 50);
|
||||||
|
|
||||||
/// 跟踪加载时间,这样我们就不会显示过期的广告
|
/// 跟踪加载时间,这样我们就不会显示过期的广告
|
||||||
DateTime? _appOpenLoadTime;
|
final Map<String, DateTime?> _appOpenLoadTimeMap = {};
|
||||||
|
|
||||||
InterstitialAd? _interstitialAd;
|
/// 记录关闭时的时间,用于下一次展示时计算时间差
|
||||||
|
DateTime? _closeDateTime;
|
||||||
|
|
||||||
|
/// 是否显示
|
||||||
bool isShowingAd = false;
|
bool isShowingAd = false;
|
||||||
|
|
||||||
/// 插页广告单元id
|
/// 加载所有插页广告位
|
||||||
final adUnitId = Platform.isAndroid
|
void loadAdAll() {
|
||||||
? (kReleaseMode ? '' : 'ca-app-pub-3940256099942544/1033173712')
|
AdConfigModel adConfigModel = MusicBox().getAdConfig();
|
||||||
: (kReleaseMode ? 'ca-app-pub-5684307632319406/2760767691' : 'ca-app-pub-3940256099942544/4411468910');
|
_loadSingleAd(adConfigModel.coldLoading, AdScenes.coldLoading.name);
|
||||||
|
_loadSingleAd(adConfigModel.hotLoading, AdScenes.hotLoading.name);
|
||||||
|
_loadSingleAd(adConfigModel.play, AdScenes.play.name);
|
||||||
|
_loadSingleAd(adConfigModel.download, AdScenes.download.name);
|
||||||
|
_loadSingleAd(adConfigModel.list, AdScenes.list.name);
|
||||||
|
_loadSingleAd(adConfigModel.playCut, AdScenes.playCut.name);
|
||||||
|
_loadSingleAd(adConfigModel.search, AdScenes.search.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 加载单个广告位
|
||||||
|
void _loadSingleAd(List<AdModel>? adList, String adScenes) {
|
||||||
|
if (adList != null && adList.isNotEmpty) {
|
||||||
|
var adModel = adList.reduce((value, element) => element.level! < value.level! ? element : value);
|
||||||
|
loadAd(adModel.identifier, adScenes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 加载广告
|
/// 加载广告
|
||||||
void loadAd() async {
|
void loadAd(String? adUnitId, String adScenes) async {
|
||||||
final List<ConnectivityResult> connectivityResult = await (Connectivity().checkConnectivity());
|
final List<ConnectivityResult> connectivityResult = await (Connectivity().checkConnectivity());
|
||||||
if (connectivityResult.contains(ConnectivityResult.none)) {
|
if (connectivityResult.contains(ConnectivityResult.none)) {
|
||||||
|
LogUtil.d('当前无网络,不加载广告');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isAdAvailable) {
|
if (ObjUtil.isEmpty(adUnitId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
InterstitialAd.load(
|
InterstitialAd.load(
|
||||||
adUnitId: adUnitId,
|
adUnitId: adUnitId!,
|
||||||
request: const AdRequest(),
|
request: const AdRequest(),
|
||||||
adLoadCallback: InterstitialAdLoadCallback(
|
adLoadCallback: InterstitialAdLoadCallback(
|
||||||
onAdLoaded: (ad) {
|
onAdLoaded: (ad) {
|
||||||
LogUtil.d('插页广告加载完成');
|
LogUtil.d('$adScenes:${ad.adUnitId}插页广告加载完成');
|
||||||
_interstitialAd = ad;
|
_interstitialAdMap[adScenes] = ad;
|
||||||
_appOpenLoadTime = DateTime.now();
|
_appOpenLoadTimeMap[adScenes] = DateTime.now();
|
||||||
|
if (adScenes == AdScenes.coldLoading.name) {
|
||||||
|
if (Get.isRegistered<LaunchController>()) {
|
||||||
|
LaunchController.to.editChangeValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onAdFailedToLoad: (LoadAdError error) {
|
onAdFailedToLoad: (LoadAdError error) {
|
||||||
LogUtil.d('插页广告加载失败: $error');
|
LogUtil.d('$adScenes:$adUnitId插页广告加载失败: $error');
|
||||||
|
_loadFailHandle(adUnitId, adScenes);
|
||||||
|
FirebaseAnalyticsManager.logPlayAdsLoadFailure(error.message);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 加载失败处理
|
||||||
|
void _loadFailHandle(String adUnitId, String adScenes) {
|
||||||
|
AdConfigModel adConfigModel = MusicBox().getAdConfig();
|
||||||
|
var adList = _getAdList(adScenes);
|
||||||
|
if (adList != null) {
|
||||||
|
var currentItem = adList.firstWhereOrNull((e) => e.identifier == adUnitId);
|
||||||
|
if (currentItem != null) {
|
||||||
|
var nextItem = adList.firstWhereOrNull((e) => e.level == currentItem.level! + 1);
|
||||||
|
if (nextItem != null) {
|
||||||
|
// 当前id加载失败,加载下一个id
|
||||||
|
loadAd(nextItem.identifier, adScenes);
|
||||||
|
} else {
|
||||||
|
// 对应场景id都加载失败,加载全局id
|
||||||
|
_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) {
|
||||||
|
AdConfigModel adConfigModel = MusicBox().getAdConfig();
|
||||||
|
if (adScenes == AdScenes.coldLoading.name) {
|
||||||
|
return adConfigModel.coldLoading;
|
||||||
|
} else if (adScenes == AdScenes.hotLoading.name) {
|
||||||
|
return adConfigModel.hotLoading;
|
||||||
|
} else if (adScenes == AdScenes.play.name) {
|
||||||
|
return adConfigModel.play;
|
||||||
|
} else if (adScenes == AdScenes.download.name) {
|
||||||
|
return adConfigModel.download;
|
||||||
|
} else if (adScenes == AdScenes.list.name) {
|
||||||
|
return adConfigModel.list;
|
||||||
|
} else if (adScenes == AdScenes.playCut.name) {
|
||||||
|
return adConfigModel.playCut;
|
||||||
|
} else if (adScenes == AdScenes.search.name) {
|
||||||
|
return adConfigModel.search;
|
||||||
|
} else if (adScenes == AdScenes.backup.name) {
|
||||||
|
return adConfigModel.backup;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// 是否可以播放广告
|
/// 是否可以播放广告
|
||||||
bool get isAdAvailable {
|
bool isAdAvailable(String adScenes) {
|
||||||
return _interstitialAd != null;
|
return _interstitialAdMap[adScenes] != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 显示广告(如果存在且尚未显示)
|
/// 显示广告(如果存在且尚未显示)
|
||||||
/// 如果先前缓存的广告已过期,则只加载并缓存新广告
|
/// 如果先前缓存的广告已过期,则只加载并缓存新广告
|
||||||
void showAdIfAvailable({Function()? onTap}) {
|
void showAdIfAvailable(String adScenes, {Function()? onTap}) {
|
||||||
if (!isAdAvailable) {
|
if (!isAdAvailable(adScenes)) {
|
||||||
LogUtil.d('尝试在可用之前显示广告');
|
LogUtil.d('尝试在可用之前显示广告');
|
||||||
loadAd();
|
|
||||||
if(onTap != null) onTap();
|
if(onTap != null) onTap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isShowingAd) {
|
if (isShowingAd) {
|
||||||
LogUtil.d('尝试在已显示广告的情况下显示广告');
|
LogUtil.d('尝试在已显示广告的情况下显示广告');
|
||||||
|
|
||||||
if(onTap != null) onTap();
|
if(onTap != null) onTap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (DateTime.now().subtract(maxCacheDuration).isAfter(_appOpenLoadTime!)) {
|
if (DateTime.now().subtract(_maxCacheDuration).isAfter(_appOpenLoadTimeMap[adScenes]!)) {
|
||||||
LogUtil.d('超过了最大缓存持续时间。正在加载另一个广告');
|
LogUtil.d('超过了最大缓存持续时间。正在加载另一个广告');
|
||||||
_interstitialAd!.dispose();
|
_interstitialAdMap[adScenes]!.dispose();
|
||||||
_interstitialAd = null;
|
loadAd(_interstitialAdMap[adScenes]?.adUnitId, adScenes);
|
||||||
loadAd();
|
_interstitialAdMap[adScenes] = null;
|
||||||
|
_interstitialAdMap.remove(adScenes);
|
||||||
|
|
||||||
if(onTap != null) onTap();
|
if(onTap != null) onTap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (_closeDateTime != null) {
|
||||||
|
// 计算时间差
|
||||||
|
Duration timeDifference = DateTime.now().difference(_closeDateTime!);
|
||||||
|
|
||||||
|
int seconds;
|
||||||
|
if (adScenes == AdScenes.hotLoading.name) {
|
||||||
|
seconds = MusicBox().getOpenAppEventDuration();
|
||||||
|
} else {
|
||||||
|
seconds = MusicBox().getInterstitialEventDuration();
|
||||||
|
}
|
||||||
|
if (timeDifference < Duration(seconds: seconds)) {
|
||||||
|
LogUtil.d('距离上次广告展示未达到插页广告事件间隔时长');
|
||||||
|
|
||||||
|
if(onTap != null) onTap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FirebaseAnalyticsManager.logPlayAdsChanceAction();
|
||||||
|
|
||||||
// 设置 fullScreenContentCallback 并显示广告
|
// 设置 fullScreenContentCallback 并显示广告
|
||||||
_interstitialAd!.fullScreenContentCallback = FullScreenContentCallback(
|
_interstitialAdMap[adScenes]!.fullScreenContentCallback = FullScreenContentCallback(
|
||||||
// 暂停应用程序中的活动或记录广告展示的时间
|
// 暂停应用程序中的活动或记录广告展示的时间
|
||||||
onAdShowedFullScreenContent: (ad) {
|
onAdShowedFullScreenContent: (ad) {
|
||||||
isShowingAd = true;
|
|
||||||
LogUtil.d('$ad onAdShowedFullScreenContent');
|
LogUtil.d('$ad onAdShowedFullScreenContent');
|
||||||
|
isShowingAd = true;
|
||||||
},
|
},
|
||||||
// 更适合用于跟踪广告展示的次数和效果,以及执行与广告展示相关的操作
|
// 更适合用于跟踪广告展示的次数和效果,以及执行与广告展示相关的操作
|
||||||
onAdImpression: (ad) {
|
onAdImpression: (ad) {
|
||||||
LogUtil.d('$ad onAdImpression');
|
LogUtil.d('$ad onAdImpression');
|
||||||
|
FirebaseAnalyticsManager.logPlayAdsShowSuccess(ad);
|
||||||
},
|
},
|
||||||
onAdFailedToShowFullScreenContent: (ad, error) {
|
onAdFailedToShowFullScreenContent: (ad, error) {
|
||||||
LogUtil.d('$ad onAdFailedToShowFullScreenContent: $error');
|
LogUtil.d('$ad onAdFailedToShowFullScreenContent: $error');
|
||||||
isShowingAd = false;
|
isShowingAd = false;
|
||||||
ad.dispose();
|
ad.dispose();
|
||||||
_interstitialAd = null;
|
loadAd(_interstitialAdMap[adScenes]?.adUnitId, adScenes);
|
||||||
|
_interstitialAdMap[adScenes] = null;
|
||||||
|
_interstitialAdMap.remove(adScenes);
|
||||||
|
FirebaseAnalyticsManager.logPlayAdsLoadFailure(error.message);
|
||||||
|
|
||||||
if(onTap != null) onTap();
|
if(onTap != null) onTap();
|
||||||
},
|
},
|
||||||
onAdDismissedFullScreenContent: (ad) {
|
onAdDismissedFullScreenContent: (ad) {
|
||||||
LogUtil.d('$ad onAdDismissedFullScreenContent');
|
LogUtil.d('$ad onAdDismissedFullScreenContent');
|
||||||
isShowingAd = false;
|
isShowingAd = false;
|
||||||
|
_closeDateTime = DateTime.now();
|
||||||
ad.dispose();
|
ad.dispose();
|
||||||
_interstitialAd = null;
|
loadAd(_interstitialAdMap[adScenes]?.adUnitId, adScenes);
|
||||||
loadAd();
|
_interstitialAdMap[adScenes] = null;
|
||||||
|
_interstitialAdMap.remove(adScenes);
|
||||||
|
|
||||||
if(onTap != null) onTap();
|
if(onTap != null) onTap();
|
||||||
},
|
},
|
||||||
@ -114,6 +229,6 @@ class InterstitialAdManager {
|
|||||||
LogUtil.d('$ad onAdClicked');
|
LogUtil.d('$ad onAdClicked');
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
_interstitialAd!.show();
|
_interstitialAdMap[adScenes]!.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
94
lib/ads/library_native_ad_manager.dart
Normal file
94
lib/ads/library_native_ad_manager.dart
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// Author: fengshengxiong
|
||||||
|
// Date: 2024/6/25
|
||||||
|
// Description: 原生广告
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:google_mobile_ads/google_mobile_ads.dart';
|
||||||
|
import 'package:tone_snap/data/enum/ad_scenes.dart';
|
||||||
|
import 'package:tone_snap/data/models/ad_config_model.dart';
|
||||||
|
import 'package:tone_snap/data/storage/music_box.dart';
|
||||||
|
import 'package:tone_snap/res/themes/app_colors.dart';
|
||||||
|
import 'package:tone_snap/utils/log_util.dart';
|
||||||
|
import 'package:tone_snap/utils/obj_util.dart';
|
||||||
|
|
||||||
|
class LibraryNativeAdManager {
|
||||||
|
LibraryNativeAdManager._();
|
||||||
|
|
||||||
|
static final LibraryNativeAdManager _instance = LibraryNativeAdManager._();
|
||||||
|
|
||||||
|
factory LibraryNativeAdManager() => _instance;
|
||||||
|
|
||||||
|
/// 广告对象
|
||||||
|
NativeAd? nativeAd;
|
||||||
|
|
||||||
|
/// 广告是否已加载
|
||||||
|
var nativeAdIsLoaded = false.obs;
|
||||||
|
|
||||||
|
/// 加载广告
|
||||||
|
void loadNativeAd() {
|
||||||
|
AdConfigModel adConfigModel = MusicBox().getAdConfig();
|
||||||
|
if (adConfigModel.library != null && adConfigModel.library!.isNotEmpty) {
|
||||||
|
_loadAd(adConfigModel.library![0].identifier, AdScenes.library.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 加载广告
|
||||||
|
void _loadAd(String? adUnitId, String adScenes) async {
|
||||||
|
if (ObjUtil.isEmpty(adUnitId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nativeAd = NativeAd(
|
||||||
|
adUnitId: adUnitId!,
|
||||||
|
request: const AdRequest(),
|
||||||
|
listener: NativeAdListener(
|
||||||
|
onAdLoaded: (ad) {
|
||||||
|
LogUtil.d('$adScenes:${ad.adUnitId}原生广告加载完成');
|
||||||
|
nativeAdIsLoaded.value = true;
|
||||||
|
},
|
||||||
|
onAdFailedToLoad: (ad, error) {
|
||||||
|
LogUtil.e('$adScenes:${ad.adUnitId}原生广告加载失败: $error');
|
||||||
|
nativeAdIsLoaded.value = false;
|
||||||
|
loadNativeAd();
|
||||||
|
ad.dispose();
|
||||||
|
},
|
||||||
|
onAdClicked: (ad) {},
|
||||||
|
onAdImpression: (ad) {
|
||||||
|
|
||||||
|
},
|
||||||
|
onAdClosed: (ad) {},
|
||||||
|
onAdOpened: (ad) {},
|
||||||
|
onAdWillDismissScreen: (ad) {},
|
||||||
|
onPaidEvent: (ad, valueMicros, precision, currencyCode) {
|
||||||
|
|
||||||
|
},
|
||||||
|
),
|
||||||
|
nativeTemplateStyle: NativeTemplateStyle(
|
||||||
|
templateType: TemplateType.medium,
|
||||||
|
mainBackgroundColor: scaffoldBgColor,
|
||||||
|
cornerRadius: 8.0,
|
||||||
|
callToActionTextStyle: NativeTemplateTextStyle(
|
||||||
|
backgroundColor: seedColor,
|
||||||
|
textColor: Colors.white,
|
||||||
|
style: NativeTemplateFontStyle.bold,
|
||||||
|
size: 16.0,
|
||||||
|
),
|
||||||
|
primaryTextStyle: NativeTemplateTextStyle(
|
||||||
|
textColor: seedColor,
|
||||||
|
style: NativeTemplateFontStyle.bold,
|
||||||
|
size: 14.0,
|
||||||
|
),
|
||||||
|
secondaryTextStyle: NativeTemplateTextStyle(
|
||||||
|
textColor: Colors.white,
|
||||||
|
style: NativeTemplateFontStyle.italic,
|
||||||
|
size: 12.0,
|
||||||
|
),
|
||||||
|
tertiaryTextStyle: NativeTemplateTextStyle(
|
||||||
|
textColor: seedColor,
|
||||||
|
style: NativeTemplateFontStyle.normal,
|
||||||
|
size: 14.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)..load();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,6 +20,7 @@ class MusicApi {
|
|||||||
String? visitorData,
|
String? visitorData,
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
T Function(Map<String, dynamic>)? formJson,
|
T Function(Map<String, dynamic>)? formJson,
|
||||||
|
Function(BaseError baseError)? fail,
|
||||||
bool showLoading = false,
|
bool showLoading = false,
|
||||||
bool showToast = false,
|
bool showToast = false,
|
||||||
}) async {
|
}) async {
|
||||||
@ -47,6 +48,7 @@ class MusicApi {
|
|||||||
queryParameters: queryParameters,
|
queryParameters: queryParameters,
|
||||||
formJson: formJson,
|
formJson: formJson,
|
||||||
success: (data) => model = data,
|
success: (data) => model = data,
|
||||||
|
fail: fail
|
||||||
);
|
);
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
@ -173,6 +175,7 @@ class MusicApi {
|
|||||||
static Future<T?> search<T>({
|
static Future<T?> search<T>({
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
T Function(Map<String, dynamic>)? formJson,
|
T Function(Map<String, dynamic>)? formJson,
|
||||||
|
Function(BaseError baseError)? fail,
|
||||||
bool showLoading = false,
|
bool showLoading = false,
|
||||||
bool showToast = true,
|
bool showToast = true,
|
||||||
}) async {
|
}) async {
|
||||||
@ -199,6 +202,7 @@ class MusicApi {
|
|||||||
queryParameters: queryParameters,
|
queryParameters: queryParameters,
|
||||||
formJson: formJson,
|
formJson: formJson,
|
||||||
success: (data) => model = data,
|
success: (data) => model = data,
|
||||||
|
fail: fail,
|
||||||
);
|
);
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|||||||
15
lib/data/enum/ad_format.dart
Normal file
15
lib/data/enum/ad_format.dart
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Author: fengshengxiong
|
||||||
|
// Date: 2024/6/13
|
||||||
|
// Description: 广告格式
|
||||||
|
|
||||||
|
enum AdFormat {
|
||||||
|
/// 插页
|
||||||
|
insert('Insert'),
|
||||||
|
|
||||||
|
/// 原生
|
||||||
|
native('Native');
|
||||||
|
|
||||||
|
const AdFormat(this.type);
|
||||||
|
|
||||||
|
final String type;
|
||||||
|
}
|
||||||
39
lib/data/enum/ad_scenes.dart
Normal file
39
lib/data/enum/ad_scenes.dart
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Author: fengshengxiong
|
||||||
|
// Date: 2024/6/13
|
||||||
|
// Description: 广告场景
|
||||||
|
|
||||||
|
enum AdScenes {
|
||||||
|
/// 冷启动cold_loading(插页式广告)
|
||||||
|
coldLoading('coldLoading'),
|
||||||
|
|
||||||
|
/// 热启动hot_loading(插页式广告)
|
||||||
|
hotLoading('hotLoading'),
|
||||||
|
|
||||||
|
/// 播放play(插页式广告)
|
||||||
|
play('play'),
|
||||||
|
|
||||||
|
/// 下载download(插页式广告)
|
||||||
|
download('download'),
|
||||||
|
|
||||||
|
/// 列表list(插页式广告)
|
||||||
|
list('list'),
|
||||||
|
|
||||||
|
/// 曲库library(原生高级广告)
|
||||||
|
library('library'),
|
||||||
|
|
||||||
|
/// 切歌play_cut(插页式广告)
|
||||||
|
playCut('playCut'),
|
||||||
|
|
||||||
|
/// 点击搜索search(插页式广告)
|
||||||
|
search('search'),
|
||||||
|
|
||||||
|
/// 搜索结果展示search(原生高级广告)
|
||||||
|
searchResult('searchResult'),
|
||||||
|
|
||||||
|
/// 全局backup(插页式广告)
|
||||||
|
backup('backup');
|
||||||
|
|
||||||
|
const AdScenes(this.name);
|
||||||
|
|
||||||
|
final String name;
|
||||||
|
}
|
||||||
93
lib/data/models/ad_config_model.dart
Normal file
93
lib/data/models/ad_config_model.dart
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// Author: fengshengxiong
|
||||||
|
// Date: 2024/8/6
|
||||||
|
// Description: 广告配置模型
|
||||||
|
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
class AdConfigModel {
|
||||||
|
List<AdModel>? coldLoading;
|
||||||
|
List<AdModel>? hotLoading;
|
||||||
|
List<AdModel>? play;
|
||||||
|
List<AdModel>? download;
|
||||||
|
List<AdModel>? list;
|
||||||
|
List<AdModel>? library;
|
||||||
|
List<AdModel>? playCut;
|
||||||
|
List<AdModel>? search;
|
||||||
|
List<AdModel>? searchResult;
|
||||||
|
List<AdModel>? backup;
|
||||||
|
|
||||||
|
AdConfigModel({
|
||||||
|
this.coldLoading,
|
||||||
|
this.hotLoading,
|
||||||
|
this.play,
|
||||||
|
this.download,
|
||||||
|
this.list,
|
||||||
|
this.library,
|
||||||
|
this.playCut,
|
||||||
|
this.search,
|
||||||
|
this.searchResult,
|
||||||
|
this.backup,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory AdConfigModel.fromJson(String str) => AdConfigModel.fromMap(json.decode(str));
|
||||||
|
|
||||||
|
String toJson() => json.encode(toMap());
|
||||||
|
|
||||||
|
factory AdConfigModel.fromMap(Map<String, dynamic> json) => AdConfigModel(
|
||||||
|
coldLoading: json["coldLoading"] == null ? [] : List<AdModel>.from(json["coldLoading"]!.map((x) => AdModel.fromMap(x))),
|
||||||
|
hotLoading: json["hotLoading"] == null ? [] : List<AdModel>.from(json["hotLoading"]!.map((x) => AdModel.fromMap(x))),
|
||||||
|
play: json["play"] == null ? [] : List<AdModel>.from(json["play"]!.map((x) => AdModel.fromMap(x))),
|
||||||
|
download: json["download"] == null ? [] : List<AdModel>.from(json["download"]!.map((x) => AdModel.fromMap(x))),
|
||||||
|
list: json["list"] == null ? [] : List<AdModel>.from(json["list"]!.map((x) => AdModel.fromMap(x))),
|
||||||
|
library: json["library"] == null ? [] : List<AdModel>.from(json["library"]!.map((x) => AdModel.fromMap(x))),
|
||||||
|
playCut: json["playCut"] == null ? [] : List<AdModel>.from(json["playCut"]!.map((x) => AdModel.fromMap(x))),
|
||||||
|
search: json["search"] == null ? [] : List<AdModel>.from(json["search"]!.map((x) => AdModel.fromMap(x))),
|
||||||
|
searchResult: json["searchResult"] == null ? [] : List<AdModel>.from(json["searchResult"]!.map((x) => AdModel.fromMap(x))),
|
||||||
|
backup: json["backup"] == null ? [] : List<AdModel>.from(json["backup"]!.map((x) => AdModel.fromMap(x))),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() => {
|
||||||
|
"coldLoading": coldLoading == null ? [] : List<dynamic>.from(coldLoading!.map((x) => x.toMap())),
|
||||||
|
"hotLoading": hotLoading == null ? [] : List<dynamic>.from(hotLoading!.map((x) => x.toMap())),
|
||||||
|
"play": play == null ? [] : List<dynamic>.from(play!.map((x) => x.toMap())),
|
||||||
|
"download": download == null ? [] : List<dynamic>.from(download!.map((x) => x.toMap())),
|
||||||
|
"list": list == null ? [] : List<dynamic>.from(list!.map((x) => x.toMap())),
|
||||||
|
"library": library == null ? [] : List<dynamic>.from(library!.map((x) => x.toMap())),
|
||||||
|
"playCut": playCut == null ? [] : List<dynamic>.from(playCut!.map((x) => x.toMap())),
|
||||||
|
"search": search == null ? [] : List<dynamic>.from(search!.map((x) => x.toMap())),
|
||||||
|
"searchResult": searchResult == null ? [] : List<dynamic>.from(searchResult!.map((x) => x.toMap())),
|
||||||
|
"backup": backup == null ? [] : List<dynamic>.from(backup!.map((x) => x.toMap())),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class AdModel {
|
||||||
|
int? level;
|
||||||
|
String? identifier;
|
||||||
|
String? ad;
|
||||||
|
String? type;
|
||||||
|
|
||||||
|
AdModel({
|
||||||
|
this.level,
|
||||||
|
this.identifier,
|
||||||
|
this.ad,
|
||||||
|
this.type,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory AdModel.fromJson(String str) => AdModel.fromMap(json.decode(str));
|
||||||
|
|
||||||
|
String toJson() => json.encode(toMap());
|
||||||
|
|
||||||
|
factory AdModel.fromMap(Map<String, dynamic> json) => AdModel(
|
||||||
|
level: json["level"],
|
||||||
|
identifier: json["identifier"],
|
||||||
|
ad: json["ad"],
|
||||||
|
type: json["type"],
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() => {
|
||||||
|
"level": level,
|
||||||
|
"identifier": identifier,
|
||||||
|
"ad": ad,
|
||||||
|
"type": type,
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -3,10 +3,12 @@
|
|||||||
// Description: 音乐非结构化数据盒子
|
// Description: 音乐非结构化数据盒子
|
||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
import 'package:tone_snap/data/enum/play_mode.dart';
|
import 'package:tone_snap/data/enum/play_mode.dart';
|
||||||
|
import 'package:tone_snap/data/models/ad_config_model.dart';
|
||||||
import 'package:tone_snap/data/storage/hive_storage.dart';
|
import 'package:tone_snap/data/storage/hive_storage.dart';
|
||||||
import 'package:tone_snap/global/app_config.dart';
|
import 'package:tone_snap/global/app_config.dart';
|
||||||
import 'package:tone_snap/utils/log_util.dart';
|
import 'package:tone_snap/utils/log_util.dart';
|
||||||
@ -21,21 +23,24 @@ class MusicBox {
|
|||||||
return _instance;
|
return _instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RemoteConfig openStatus
|
|
||||||
final _openStatusKey = 'openStatusKey';
|
|
||||||
|
|
||||||
/// RemoteConfig dataVersion
|
|
||||||
final _dataVersionKey = 'dataVersionKey';
|
|
||||||
|
|
||||||
/// 是否进入过B面
|
/// 是否进入过B面
|
||||||
final _isOpenedSideBKey = 'isOpenedSideBKey';
|
final _isOpenedSideBKey = 'isOpenedSideBKey';
|
||||||
|
|
||||||
|
/// openStatus
|
||||||
|
final _openStatusKey = 'openStatusKey';
|
||||||
|
|
||||||
|
/// dataVersion
|
||||||
|
final _dataVersionKey = 'dataVersionKey';
|
||||||
|
|
||||||
/// 开屏启动插页事件间隔时长
|
/// 开屏启动插页事件间隔时长
|
||||||
final _openAppEventDurationKey = 'openAppEventDurationKey';
|
final _openAppEventDurationKey = 'openAppEventDurationKey';
|
||||||
|
|
||||||
/// 插页广告事件间隔时长
|
/// 插页广告事件间隔时长
|
||||||
final _interstitialEventDurationKey = 'interstitialEventDurationKey';
|
final _interstitialEventDurationKey = 'interstitialEventDurationKey';
|
||||||
|
|
||||||
|
/// 广告配置
|
||||||
|
final _adMobLevelIDsKey = 'adMobLevelIDsKey';
|
||||||
|
|
||||||
/// 播放模式
|
/// 播放模式
|
||||||
final _playModeKey = 'playModeKey';
|
final _playModeKey = 'playModeKey';
|
||||||
|
|
||||||
@ -46,6 +51,16 @@ class MusicBox {
|
|||||||
/// 注意, main函数中这个盒子已经打开, 可以进行存储操作
|
/// 注意, main函数中这个盒子已经打开, 可以进行存储操作
|
||||||
final _box = Hive.box(musicBox);
|
final _box = Hive.box(musicBox);
|
||||||
|
|
||||||
|
/// 设置是否打开过B面
|
||||||
|
Future<void> putIsOpenedSideB(bool isOpen) async {
|
||||||
|
return await _box.put(_isOpenedSideBKey, isOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取是否打开过B面
|
||||||
|
bool getIsOpenedSideB() {
|
||||||
|
return _box.get(_isOpenedSideBKey, defaultValue: false);
|
||||||
|
}
|
||||||
|
|
||||||
/// 设置 openStatus
|
/// 设置 openStatus
|
||||||
Future<void> putOpenStatus(String openStatus) async {
|
Future<void> putOpenStatus(String openStatus) async {
|
||||||
return await _box.put(_openStatusKey, openStatus);
|
return await _box.put(_openStatusKey, openStatus);
|
||||||
@ -114,16 +129,6 @@ class MusicBox {
|
|||||||
return AppConfig.playerVersion;
|
return AppConfig.playerVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 设置是否打开过B面
|
|
||||||
Future<void> putIsOpenedSideB(bool isOpen) async {
|
|
||||||
return await _box.put(_isOpenedSideBKey, isOpen);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 获取是否打开过B面
|
|
||||||
bool getIsOpenedSideB() {
|
|
||||||
return _box.get(_isOpenedSideBKey, defaultValue: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 设置开屏启动插页事件间隔时长
|
/// 设置开屏启动插页事件间隔时长
|
||||||
Future<void> putOpenAppEventDuration(int time) async {
|
Future<void> putOpenAppEventDuration(int time) async {
|
||||||
return await _box.put(_openAppEventDurationKey, time);
|
return await _box.put(_openAppEventDurationKey, time);
|
||||||
@ -144,6 +149,17 @@ class MusicBox {
|
|||||||
return _box.get(_interstitialEventDurationKey, defaultValue: AppConfig.interstitialEventDuration);
|
return _box.get(_interstitialEventDurationKey, defaultValue: AppConfig.interstitialEventDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 设置广告配置
|
||||||
|
Future<void> putAdConfig(String adConfigStr) async {
|
||||||
|
return await _box.put(_adMobLevelIDsKey, adConfigStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取广告配置
|
||||||
|
AdConfigModel getAdConfig() {
|
||||||
|
var configStr = _box.get(_adMobLevelIDsKey, defaultValue: Platform.isIOS ? AppConfig.adIOSDefaultConfig : AppConfig.adAndroidDefaultConfig);
|
||||||
|
return AdConfigModel.fromJson(configStr);
|
||||||
|
}
|
||||||
|
|
||||||
/// 设置播放模式
|
/// 设置播放模式
|
||||||
Future<void> putPlayMode(PlayMode playMode) async {
|
Future<void> putPlayMode(PlayMode playMode) async {
|
||||||
return await _box.put(_playModeKey, playMode);
|
return await _box.put(_playModeKey, playMode);
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import 'package:tone_snap/data/models/music_model.dart';
|
|||||||
import 'package:tone_snap/data/models/playlist_model.dart';
|
import 'package:tone_snap/data/models/playlist_model.dart';
|
||||||
import 'package:tone_snap/data/storage/hive_storage.dart';
|
import 'package:tone_snap/data/storage/hive_storage.dart';
|
||||||
import 'package:tone_snap/utils/date_util.dart';
|
import 'package:tone_snap/utils/date_util.dart';
|
||||||
|
import 'package:tone_snap/utils/log_util.dart';
|
||||||
|
|
||||||
class PlaylistsBox {
|
class PlaylistsBox {
|
||||||
PlaylistsBox._();
|
PlaylistsBox._();
|
||||||
@ -25,12 +26,13 @@ class PlaylistsBox {
|
|||||||
|
|
||||||
/// 获取列表
|
/// 获取列表
|
||||||
List<PlaylistModel> getList() {
|
List<PlaylistModel> getList() {
|
||||||
return _box.values.toList();
|
var list = _box.values.toList();
|
||||||
}
|
try {
|
||||||
|
list.sort((a, b) => b.milliseconds!.compareTo(a.milliseconds!));
|
||||||
/// 获取倒序列表
|
} catch (e) {
|
||||||
List<PlaylistModel> getReversedList() {
|
LogUtil.e(e.toString());
|
||||||
return _box.values.toList().reversed.toList();
|
}
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 添加数据
|
/// 添加数据
|
||||||
|
|||||||
@ -3,17 +3,291 @@
|
|||||||
// Description: firebase_analytics管理
|
// Description: firebase_analytics管理
|
||||||
|
|
||||||
import 'package:firebase_analytics/firebase_analytics.dart';
|
import 'package:firebase_analytics/firebase_analytics.dart';
|
||||||
|
import 'package:google_mobile_ads/google_mobile_ads.dart';
|
||||||
|
import 'package:tone_snap/utils/log_util.dart';
|
||||||
|
import 'package:tone_snap/utils/obj_util.dart';
|
||||||
|
|
||||||
class FirebaseAnalyticsManager {
|
class FirebaseAnalyticsManager {
|
||||||
static const homeApv = 'home_a_pv';
|
|
||||||
|
|
||||||
/// 埋点
|
/// 埋点
|
||||||
/// name:事件名
|
/// name:事件名
|
||||||
/// parameters:业务参数
|
/// parameters:业务参数
|
||||||
static void logEvent(String eventName, {Map<String, Object>? parameters}) {
|
static void logEvent(String eventName, {Map<String, Object>? parameters}) {
|
||||||
FirebaseAnalytics.instance.logEvent(
|
try {
|
||||||
name: eventName,
|
FirebaseAnalytics.instance.logEvent(
|
||||||
parameters: parameters,
|
name: eventName,
|
||||||
|
parameters: parameters,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
LogUtil.e(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 启动页曝光
|
||||||
|
static void logLaunchPV() {
|
||||||
|
logEvent('launch_pv');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 跳转
|
||||||
|
static void logJumpEvent(String? side, String? reason) {
|
||||||
|
logEvent('jump_event',
|
||||||
|
parameters: {
|
||||||
|
'side': ObjUtil.getStr(side),
|
||||||
|
'reason': ObjUtil.getStr(reason)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A面首页曝光
|
||||||
|
static void logHomeAPV() {
|
||||||
|
logEvent('home_a_pv');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// B面首页曝光
|
||||||
|
static void logHomeBPV() {
|
||||||
|
logEvent('home_b_pv');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 首页资源曝光成功
|
||||||
|
static void logHomeBModuleShowsuccesAction() {
|
||||||
|
logEvent('home_b_module_showsucces_action');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 首页资源曝光失败
|
||||||
|
static void logHomeBModuleFailAction(String? failreason) {
|
||||||
|
logEvent('home_b_module_fail_action',
|
||||||
|
parameters: {
|
||||||
|
'failreason': ObjUtil.getStr(failreason)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 点击首页模块
|
||||||
|
static void logHomeBModuleClick(String? modulename) {
|
||||||
|
logEvent('home_b_module_click',
|
||||||
|
parameters: {
|
||||||
|
'modulename': ObjUtil.getStr(modulename)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// B面我的曝光
|
||||||
|
static void logMeBPV() {
|
||||||
|
logEvent('me_b_pv');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 点击歌曲
|
||||||
|
static void logSongClick(String? songfrom) {
|
||||||
|
logEvent('song_click',
|
||||||
|
parameters: {
|
||||||
|
'songfrom': ObjUtil.getStr(songfrom)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// B面歌曲曝光
|
||||||
|
static void logPlayerBpv(String? videoid, String? videoname, String? artistname) {
|
||||||
|
logEvent('player_b_pv',
|
||||||
|
parameters: {
|
||||||
|
'videoid': ObjUtil.getStr(videoid),
|
||||||
|
'videoname': ObjUtil.getStr(videoname),
|
||||||
|
'artistname': ObjUtil.getStr(artistname),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 统计加载时间
|
||||||
|
static void logPlayerBDelayAction(String? videoid, String? videoname, String? artistname, String? delay) {
|
||||||
|
logEvent('player_b_delay_action',
|
||||||
|
parameters: {
|
||||||
|
'videoid': ObjUtil.getStr(videoid),
|
||||||
|
'videoname': ObjUtil.getStr(videoname),
|
||||||
|
'artistname': ObjUtil.getStr(artistname),
|
||||||
|
'delay': ObjUtil.getStr(delay),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 播放成功
|
||||||
|
static void logPlayerBSuccessAction(String? videoid, String? videoname, String? artistname) {
|
||||||
|
logEvent('player_b_success_action',
|
||||||
|
parameters: {
|
||||||
|
'videoid': ObjUtil.getStr(videoid),
|
||||||
|
'videoname': ObjUtil.getStr(videoname),
|
||||||
|
'artistname': ObjUtil.getStr(artistname),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 播放失败
|
||||||
|
static void logPlayerBFailAction(String? failreason) {
|
||||||
|
logEvent('player_b_fail_action',
|
||||||
|
parameters: {
|
||||||
|
'failreason': ObjUtil.getStr(failreason)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 收藏
|
||||||
|
static void logPlayerBLoveClick(String? videoid, String? videoname, String? artistname) {
|
||||||
|
logEvent('player_b_love_click',
|
||||||
|
parameters: {
|
||||||
|
'videoid': ObjUtil.getStr(videoid),
|
||||||
|
'videoname': ObjUtil.getStr(videoname),
|
||||||
|
'artistname': ObjUtil.getStr(artistname),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 取消收藏
|
||||||
|
static void logPlayerBUnloveClick(String? videoid, String? videoname, String? artistname) {
|
||||||
|
logEvent('player_b_unlove_click',
|
||||||
|
parameters: {
|
||||||
|
'videoid': ObjUtil.getStr(videoid),
|
||||||
|
'videoname': ObjUtil.getStr(videoname),
|
||||||
|
'artistname': ObjUtil.getStr(artistname),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 点击下载
|
||||||
|
static void logPlayerBDownloadClick(String? videoid, String? videoname, String? artistname) {
|
||||||
|
logEvent('player_b_download_click',
|
||||||
|
parameters: {
|
||||||
|
'videoid': ObjUtil.getStr(videoid),
|
||||||
|
'videoname': ObjUtil.getStr(videoname),
|
||||||
|
'artistname': ObjUtil.getStr(artistname),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 下载成功
|
||||||
|
static void logPlayerBDownloadsuccessAction(String? videoid, String? videoname, String? artistname) {
|
||||||
|
logEvent('player_b_downloadsuccess_action',
|
||||||
|
parameters: {
|
||||||
|
'videoid': ObjUtil.getStr(videoid),
|
||||||
|
'videoname': ObjUtil.getStr(videoname),
|
||||||
|
'artistname': ObjUtil.getStr(artistname),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 下载失败
|
||||||
|
static void logPlayerBDownloadfailAction(String? failreason) {
|
||||||
|
logEvent('player_b_downloadfail_action',
|
||||||
|
parameters: {
|
||||||
|
'failreason': ObjUtil.getStr(failreason)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// B面搜索曝光
|
||||||
|
static void logSearchPV() {
|
||||||
|
logEvent('search_pv');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 搜索SUG曝光
|
||||||
|
static void logSearchSugShow() {
|
||||||
|
logEvent('search_sug_show');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 输入搜索内容,点击搜索(包含联想点击)
|
||||||
|
static void logSearchSugClick(String? sugname) {
|
||||||
|
logEvent('search_sug_click',
|
||||||
|
parameters: {
|
||||||
|
'sugname': ObjUtil.getStr(sugname)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 搜索结果曝光
|
||||||
|
static void logSearchResultPV() {
|
||||||
|
logEvent('search_result_pv');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 搜索有结果
|
||||||
|
static void logSearchResultsuccessAction() {
|
||||||
|
logEvent('search_resultsuccess_action');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 搜索无结果
|
||||||
|
static void logSearchResultfailAction(String? failreason) {
|
||||||
|
logEvent('search_resultfail_action',
|
||||||
|
parameters: {
|
||||||
|
'failreason': ObjUtil.getStr(failreason)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 搜索点击
|
||||||
|
static void logSearchFromAction(String? searchfrom) {
|
||||||
|
logEvent('search_from_action',
|
||||||
|
parameters: {
|
||||||
|
'searchfrom': ObjUtil.getStr(searchfrom)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 播放器弹出
|
||||||
|
static void logPlayerBImp() {
|
||||||
|
logEvent('player_b_imp');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 列表加载
|
||||||
|
static void logPlayerBList() {
|
||||||
|
logEvent('player_b_list');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 创建歌单
|
||||||
|
static void logCreateList() {
|
||||||
|
logEvent('create_list');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 曲库点击
|
||||||
|
static void logLibraryClick(String? clickfrom, String? folderclick) {
|
||||||
|
logEvent('library_click',
|
||||||
|
parameters: {
|
||||||
|
'clickfrom': ObjUtil.getStr(clickfrom),
|
||||||
|
'folderclick': ObjUtil.getStr(folderclick)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 广告展示机会
|
||||||
|
static void logPlayAdsChanceAction() {
|
||||||
|
logEvent('play_ads_chance');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 广告加载失败
|
||||||
|
static void logPlayAdsLoadFailure(String? error) {
|
||||||
|
logEvent('play_ads_loadFailure',
|
||||||
|
parameters: {
|
||||||
|
'error': ObjUtil.getStr(error),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 广告展示成功
|
||||||
|
static void logPlayAdsShowSuccess(Ad ad) {
|
||||||
|
var mediation = '';
|
||||||
|
if (ad.responseInfo != null && ad.responseInfo!.responseExtras.isNotEmpty) {
|
||||||
|
mediation = ad.responseInfo!.responseExtras['mediation_group_name'];
|
||||||
|
}
|
||||||
|
logEvent('play_ads_showSuccess',
|
||||||
|
parameters: {
|
||||||
|
'platform': ObjUtil.getStr(ad.responseInfo?.loadedAdapterResponseInfo?.adSourceName),
|
||||||
|
'source': ObjUtil.getStr(ad.responseInfo?.loadedAdapterResponseInfo?.adSourceInstanceName),
|
||||||
|
'unitName': ObjUtil.getStr(mediation),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 广告展示失败
|
||||||
|
static void logPlayAdsShowFailure(String? error) {
|
||||||
|
logEvent('play_ads_showFailure',
|
||||||
|
parameters: {
|
||||||
|
'error': ObjUtil.getStr(error),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,8 +23,8 @@ class DefaultFirebaseOptions {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
switch (defaultTargetPlatform) {
|
switch (defaultTargetPlatform) {
|
||||||
// case TargetPlatform.android:
|
case TargetPlatform.android:
|
||||||
// return android;
|
return android;
|
||||||
case TargetPlatform.iOS:
|
case TargetPlatform.iOS:
|
||||||
return ios;
|
return ios;
|
||||||
case TargetPlatform.macOS:
|
case TargetPlatform.macOS:
|
||||||
@ -49,13 +49,13 @@ class DefaultFirebaseOptions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// static const FirebaseOptions android = FirebaseOptions(
|
static const FirebaseOptions android = FirebaseOptions(
|
||||||
// apiKey: 'AIzaSyDP6CpkN3HMpCofXlToug-hadYpTLEgE0E',
|
apiKey: 'AIzaSyCLEOFjenMfiZKdoKdGh9mylckpIpTn854',
|
||||||
// appId: '1:318284530945:android:c7dd2abf520a9840250700',
|
appId: '1:280378307504:android:bcee5d63088dcbb7ca5c75',
|
||||||
// messagingSenderId: '318284530945',
|
messagingSenderId: '280378307504',
|
||||||
// projectId: 'nowwallpaper',
|
projectId: 'tonesnap-and',
|
||||||
// storageBucket: 'nowwallpaper.appspot.com',
|
storageBucket: 'tonesnap-and.appspot.com',
|
||||||
// );
|
);
|
||||||
|
|
||||||
static const FirebaseOptions ios = FirebaseOptions(
|
static const FirebaseOptions ios = FirebaseOptions(
|
||||||
apiKey: 'AIzaSyADeT4ReAayii_M9tl0GHR6tUlyVTXAaSU',
|
apiKey: 'AIzaSyADeT4ReAayii_M9tl0GHR6tUlyVTXAaSU',
|
||||||
|
|||||||
@ -60,6 +60,12 @@ class FirebaseRemoteConfigManager {
|
|||||||
LogUtil.e(e.toString());
|
LogUtil.e(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取 adMobLevelIDs
|
||||||
|
var adMobLevelIDs = allData['adMobLevelIDs']?.asString();
|
||||||
|
if (ObjUtil.isNotEmpty(adMobLevelIDs)) {
|
||||||
|
await MusicBox().putAdConfig(adMobLevelIDs!);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
LogUtil.e(e.toString());
|
LogUtil.e(e.toString());
|
||||||
|
|||||||
@ -24,5 +24,269 @@ class AppConfig {
|
|||||||
|
|
||||||
/// 所在区域,默认值
|
/// 所在区域,默认值
|
||||||
static String isoCode = 'HK';
|
static String isoCode = 'HK';
|
||||||
|
|
||||||
|
/// iOS广告场景默认配置,level越小价值越高
|
||||||
|
static String adIOSDefaultConfig = '''{
|
||||||
|
"coldLoading": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/5757639118",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/5852437064",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hotLoading": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/3414045794",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/9382223193",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"play": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/9827341094",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/5270553952",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/2060531710",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/1913192057",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/9600110380",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/6079667773",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"library": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/7785036659",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Native"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"playCut": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/8551323416",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/2140422769",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"search": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/8434368376",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/9505312439",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"searchResult": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/1645766617",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Native"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"backup": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/5987502154",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/5361482476",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}''';
|
||||||
|
|
||||||
|
/// Android广告场景默认配置,level越小价值越高
|
||||||
|
static String adAndroidDefaultConfig = '''{
|
||||||
|
"coldLoading": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/2307556684",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/3395973732",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hotLoading": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/2527048534",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/5763116779",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"play": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/4450035105",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/4279113904",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/3136953430",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/7368311678",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/1823871765",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/2536557320",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"library": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/5438052836",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Native"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"playCut": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/5727092792",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/8197708422",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"search": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/4971148979",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/8026787222",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"searchResult": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/6848602773",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Native"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"backup": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/8718822297",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"identifier": "ca-app-pub-5684307632319406/4517483713",
|
||||||
|
"ad": "AdMob",
|
||||||
|
"type": "Insert"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}''';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,8 +3,8 @@
|
|||||||
// Description: 应用程序生命周期反应器
|
// Description: 应用程序生命周期反应器
|
||||||
|
|
||||||
import 'package:google_mobile_ads/google_mobile_ads.dart';
|
import 'package:google_mobile_ads/google_mobile_ads.dart';
|
||||||
import 'package:tone_snap/ads/app_open_ad_manager.dart';
|
|
||||||
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
|
import 'package:tone_snap/data/enum/ad_scenes.dart';
|
||||||
|
|
||||||
class AppLifecycleReactor {
|
class AppLifecycleReactor {
|
||||||
AppLifecycleReactor._();
|
AppLifecycleReactor._();
|
||||||
@ -23,7 +23,7 @@ class AppLifecycleReactor {
|
|||||||
void _onAppStateChanged(AppState appState) {
|
void _onAppStateChanged(AppState appState) {
|
||||||
// 如果应用程序正在恢复前台,尝试显示开屏广告
|
// 如果应用程序正在恢复前台,尝试显示开屏广告
|
||||||
if (appState == AppState.foreground && !InterstitialAdManager().isShowingAd) {
|
if (appState == AppState.foreground && !InterstitialAdManager().isShowingAd) {
|
||||||
AppOpenAdManager().showAdIfAvailable();
|
InterstitialAdManager().showAdIfAvailable(AdScenes.hotLoading.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,11 +5,14 @@
|
|||||||
import 'package:background_downloader/background_downloader.dart';
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tone_snap/ads/interstitial_ad_manager.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/enum/ad_scenes.dart';
|
||||||
import 'package:tone_snap/data/models/music_model.dart';
|
import 'package:tone_snap/data/models/music_model.dart';
|
||||||
import 'package:tone_snap/data/models/player_model.dart';
|
import 'package:tone_snap/data/models/player_model.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/modules/sideb/offline/offline_controller.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/personal_music_library/personal_music_library_controller.dart';
|
||||||
import 'package:tone_snap/utils/date_util.dart';
|
import 'package:tone_snap/utils/date_util.dart';
|
||||||
@ -49,6 +52,11 @@ class DownloadManager extends GetxController {
|
|||||||
break;
|
break;
|
||||||
case TaskStatus.complete:
|
case TaskStatus.complete:
|
||||||
LogUtil.d('音乐下载路径:${await update.task.filePath()}');
|
LogUtil.d('音乐下载路径:${await update.task.filePath()}');
|
||||||
|
FirebaseAnalyticsManager.logPlayerBDownloadsuccessAction(
|
||||||
|
musicModel.videoId,
|
||||||
|
musicModel.title,
|
||||||
|
musicModel.subtitle,
|
||||||
|
);
|
||||||
musicModel.localPath = await update.task.filePath();
|
musicModel.localPath = await update.task.filePath();
|
||||||
OfflineBox().add(musicModel);
|
OfflineBox().add(musicModel);
|
||||||
downloadList.remove(musicModel);
|
downloadList.remove(musicModel);
|
||||||
@ -63,14 +71,17 @@ class DownloadManager extends GetxController {
|
|||||||
case TaskStatus.notFound:
|
case TaskStatus.notFound:
|
||||||
BaseEasyLoading.toast('Download failed');
|
BaseEasyLoading.toast('Download failed');
|
||||||
downloadList.remove(musicModel);
|
downloadList.remove(musicModel);
|
||||||
|
FirebaseAnalyticsManager.logPlayerBDownloadfailAction('404,找不到url');
|
||||||
break;
|
break;
|
||||||
case TaskStatus.failed:
|
case TaskStatus.failed:
|
||||||
BaseEasyLoading.toast('Download failed');
|
BaseEasyLoading.toast('Download failed');
|
||||||
downloadList.remove(musicModel);
|
downloadList.remove(musicModel);
|
||||||
|
FirebaseAnalyticsManager.logPlayerBDownloadfailAction('下载失败');
|
||||||
break;
|
break;
|
||||||
case TaskStatus.canceled:
|
case TaskStatus.canceled:
|
||||||
BaseEasyLoading.toast('Download cancelled');
|
BaseEasyLoading.toast('Download cancelled');
|
||||||
downloadList.remove(musicModel);
|
downloadList.remove(musicModel);
|
||||||
|
FirebaseAnalyticsManager.logPlayerBDownloadfailAction('取消下载');
|
||||||
break;
|
break;
|
||||||
case TaskStatus.waitingToRetry:
|
case TaskStatus.waitingToRetry:
|
||||||
break;
|
break;
|
||||||
@ -89,37 +100,47 @@ class DownloadManager extends GetxController {
|
|||||||
|
|
||||||
/// 下载文件
|
/// 下载文件
|
||||||
void downloadMusic(MusicModel? m) {
|
void downloadMusic(MusicModel? m) {
|
||||||
if (m == null) return;
|
FirebaseAnalyticsManager.logPlayerBDownloadClick(
|
||||||
MusicModel musicModel = m.copyWith();
|
m?.videoId,
|
||||||
musicModel.taskStatus = TaskStatus.enqueued;
|
m?.title,
|
||||||
musicModel.cancelToken = CancelToken();
|
m?.subtitle,
|
||||||
downloadList.add(musicModel);
|
);
|
||||||
updateDownloadState();
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
|
AdScenes.download.name,
|
||||||
|
onTap: () {
|
||||||
|
if (m == null) return;
|
||||||
|
MusicModel musicModel = m.copyWith();
|
||||||
|
musicModel.taskStatus = TaskStatus.enqueued;
|
||||||
|
musicModel.cancelToken = CancelToken();
|
||||||
|
downloadList.add(musicModel);
|
||||||
|
updateDownloadState();
|
||||||
|
|
||||||
_getMusicUrl(musicModel, (url, mimeType) async {
|
_getMusicUrl(musicModel, (url, mimeType) async {
|
||||||
if (ObjUtil.isNotEmpty(url)) {
|
if (ObjUtil.isNotEmpty(url)) {
|
||||||
String extension = mimeType ?? 'mp4';
|
String extension = mimeType ?? 'mp4';
|
||||||
if (ObjUtil.isNotEmpty(mimeType)) {
|
if (ObjUtil.isNotEmpty(mimeType)) {
|
||||||
// 从 mimeType 中提取主类型和子类型
|
// 从 mimeType 中提取主类型和子类型
|
||||||
String type = mimeType!.split(';')[0].trim();
|
String type = mimeType!.split(';')[0].trim();
|
||||||
// 获取文件扩展名
|
// 获取文件扩展名
|
||||||
extension = type.split('/')[1];
|
extension = type.split('/')[1];
|
||||||
}
|
}
|
||||||
final filename = '${musicModel.title}_${DateUtil.getNowTimestamp()}.$extension';
|
final filename = '${musicModel.title}_${DateUtil.getNowTimestamp()}.$extension';
|
||||||
final task = DownloadTask(
|
final task = DownloadTask(
|
||||||
taskId: musicModel.videoId,
|
taskId: musicModel.videoId,
|
||||||
url: url!,
|
url: url!,
|
||||||
filename: filename,
|
filename: filename,
|
||||||
directory: LocalPathUtil.getMusicDownloadDir(),
|
directory: LocalPathUtil.getMusicDownloadDir(),
|
||||||
updates: Updates.statusAndProgress,
|
updates: Updates.statusAndProgress,
|
||||||
requiresWiFi: false,
|
requiresWiFi: false,
|
||||||
retries: 0,
|
retries: 0,
|
||||||
allowPause: false,
|
allowPause: false,
|
||||||
metaData: '',
|
metaData: '',
|
||||||
);
|
);
|
||||||
tq?.add(task);
|
tq?.add(task);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _getMusicUrl(MusicModel musicModel, Function(String? url, String? mimeType) onTap) async {
|
Future<void> _getMusicUrl(MusicModel musicModel, Function(String? url, String? mimeType) onTap) async {
|
||||||
@ -134,6 +155,7 @@ class DownloadManager extends GetxController {
|
|||||||
musicModel.taskStatus = TaskStatus.failed;
|
musicModel.taskStatus = TaskStatus.failed;
|
||||||
musicModel.cancelToken = null;
|
musicModel.cancelToken = null;
|
||||||
}
|
}
|
||||||
|
FirebaseAnalyticsManager.logPlayerBDownloadfailAction('${baseError.code},${baseError.message}');
|
||||||
downloadList.remove(musicModel);
|
downloadList.remove(musicModel);
|
||||||
updateDownloadState();
|
updateDownloadState();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,10 +6,9 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:tone_snap/ads/app_open_ad_manager.dart';
|
|
||||||
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
|
import 'package:tone_snap/ads/library_native_ad_manager.dart';
|
||||||
import 'package:tone_snap/firebase/firebase_remote_config_manager.dart';
|
import 'package:tone_snap/firebase/firebase_remote_config_manager.dart';
|
||||||
import 'package:tone_snap/modules/launch/launch_controller.dart';
|
|
||||||
import 'package:tone_snap/utils/log_util.dart';
|
import 'package:tone_snap/utils/log_util.dart';
|
||||||
|
|
||||||
class NetworkConnectivityService extends GetxService {
|
class NetworkConnectivityService extends GetxService {
|
||||||
@ -22,18 +21,14 @@ class NetworkConnectivityService extends GetxService {
|
|||||||
super.onInit();
|
super.onInit();
|
||||||
subscription = Connectivity().onConnectivityChanged.listen((List<ConnectivityResult> result) {
|
subscription = Connectivity().onConnectivityChanged.listen((List<ConnectivityResult> result) {
|
||||||
LogUtil.d('当前网络连接类型:$result');
|
LogUtil.d('当前网络连接类型:$result');
|
||||||
if (result.contains(ConnectivityResult.wifi) || result.contains(ConnectivityResult.mobile)) {
|
if (!result.contains(ConnectivityResult.none)) {
|
||||||
if (!isExecutedTask) {
|
if (!isExecutedTask) {
|
||||||
isExecutedTask = true;
|
isExecutedTask = true;
|
||||||
|
|
||||||
FirebaseRemoteConfigManager.getAll();
|
FirebaseRemoteConfigManager.getAll();
|
||||||
|
|
||||||
if (Get.isRegistered<LaunchController>()) {
|
InterstitialAdManager().loadAdAll();
|
||||||
LaunchController.to.getIsoCode();
|
// LibraryNativeAdManager().loadNativeAd();
|
||||||
}
|
|
||||||
|
|
||||||
InterstitialAdManager().loadAd();
|
|
||||||
AppOpenAdManager().loadAd();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -20,8 +20,6 @@ import 'package:tone_snap/modules/sideb/music_bar/music_bar_controller.dart';
|
|||||||
import 'package:tone_snap/res/themes/app_themes.dart';
|
import 'package:tone_snap/res/themes/app_themes.dart';
|
||||||
import 'package:tone_snap/routes/app_pages.dart';
|
import 'package:tone_snap/routes/app_pages.dart';
|
||||||
import 'package:tone_snap/routes/app_routes.dart';
|
import 'package:tone_snap/routes/app_routes.dart';
|
||||||
import 'package:tone_snap/utils/file_util.dart';
|
|
||||||
import 'package:tone_snap/utils/local_path_util.dart';
|
|
||||||
import 'package:tone_snap/utils/log_util.dart';
|
import 'package:tone_snap/utils/log_util.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
@ -38,7 +36,11 @@ void main() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 初始化广告 SDK
|
// 初始化广告 SDK
|
||||||
MobileAds.instance.initialize();
|
try {
|
||||||
|
MobileAds.instance.initialize();
|
||||||
|
} catch (e) {
|
||||||
|
LogUtil.e("MobileAds initialization error: $e");
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化Hive
|
// 初始化Hive
|
||||||
await initHive();
|
await initHive();
|
||||||
@ -59,10 +61,6 @@ void main() async {
|
|||||||
systemNavigationBarIconBrightness: Brightness.light,
|
systemNavigationBarIconBrightness: Brightness.light,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除缓存文件
|
|
||||||
FileUtil.deleteAllFilesInDirectory(await LocalPathUtil.getRecordingsDir());
|
|
||||||
FileUtil.deleteAllFilesInDirectory(await LocalPathUtil.getAssetsDir());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
@ -75,7 +73,9 @@ class MyApp extends StatelessWidget {
|
|||||||
navigatorObservers = [
|
navigatorObservers = [
|
||||||
GetObserver((_) {
|
GetObserver((_) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (Get.currentRoute == AppRoutes.playPage) {
|
if (Get.currentRoute == AppRoutes.playPage
|
||||||
|
|| Get.currentRoute == AppRoutes.privacy
|
||||||
|
|| Get.currentRoute == AppRoutes.terms) {
|
||||||
MusicBar().hide();
|
MusicBar().hide();
|
||||||
} else {
|
} else {
|
||||||
if (Get.isRegistered<MusicPlayerController>()) {
|
if (Get.isRegistered<MusicPlayerController>()) {
|
||||||
|
|||||||
@ -2,14 +2,12 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
import 'package:tone_snap/ads/app_open_ad_manager.dart';
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
import 'package:tone_snap/data/api/tikustok_api.dart';
|
import 'package:tone_snap/data/enum/ad_scenes.dart';
|
||||||
import 'package:tone_snap/data/enum/app_side_enum.dart';
|
import 'package:tone_snap/data/enum/app_side_enum.dart';
|
||||||
import 'package:tone_snap/data/models/base_model.dart';
|
|
||||||
import 'package:tone_snap/data/models/isocode_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/global/app_config.dart';
|
import 'package:tone_snap/global/app_config.dart';
|
||||||
import 'package:tone_snap/global/app_lifecycle_reactor.dart';
|
|
||||||
import 'package:tone_snap/global/network_connectivity_service.dart';
|
import 'package:tone_snap/global/network_connectivity_service.dart';
|
||||||
import 'package:tone_snap/modules/sideb/controllers/main_controller.dart';
|
import 'package:tone_snap/modules/sideb/controllers/main_controller.dart';
|
||||||
import 'package:tone_snap/routes/app_routes.dart';
|
import 'package:tone_snap/routes/app_routes.dart';
|
||||||
@ -25,17 +23,12 @@ class LaunchController extends GetxController with GetSingleTickerProviderStateM
|
|||||||
/// 进度每次变化值
|
/// 进度每次变化值
|
||||||
var changeValue = 10;
|
var changeValue = 10;
|
||||||
|
|
||||||
late AppLifecycleReactor _appLifecycleReactor;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
_appLifecycleReactor = AppLifecycleReactor();
|
|
||||||
_appLifecycleReactor.listenToAppStateChanges();
|
|
||||||
|
|
||||||
Get.put(NetworkConnectivityService());
|
|
||||||
|
|
||||||
_startTimer();
|
_startTimer();
|
||||||
|
Get.put(NetworkConnectivityService());
|
||||||
|
FirebaseAnalyticsManager.logLaunchPV();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -46,14 +39,12 @@ class LaunchController extends GetxController with GetSingleTickerProviderStateM
|
|||||||
|
|
||||||
/// 开始定时器
|
/// 开始定时器
|
||||||
void _startTimer() {
|
void _startTimer() {
|
||||||
_timer = Timer.periodic(Duration(milliseconds: changeValue), (Timer t) {
|
_timer = Timer.periodic(const Duration(milliseconds: 10), (Timer t) {
|
||||||
if (currentProcess.value + changeValue >= timeTotal) {
|
if (currentProcess.value + changeValue >= timeTotal) {
|
||||||
currentProcess.value = timeTotal;
|
currentProcess.value = timeTotal;
|
||||||
if (currentProcess >= timeTotal) {
|
_stopTimer();
|
||||||
_stopTimer();
|
_checkEnter();
|
||||||
_checkEnter();
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
currentProcess.value += changeValue;
|
currentProcess.value += changeValue;
|
||||||
});
|
});
|
||||||
@ -67,7 +58,7 @@ class LaunchController extends GetxController with GetSingleTickerProviderStateM
|
|||||||
|
|
||||||
/// 修改进度变化值
|
/// 修改进度变化值
|
||||||
void editChangeValue() {
|
void editChangeValue() {
|
||||||
changeValue = 3000;
|
changeValue = 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 校验开关和版本,决定进A还是B
|
/// 校验开关和版本,决定进A还是B
|
||||||
@ -75,18 +66,18 @@ class LaunchController extends GetxController with GetSingleTickerProviderStateM
|
|||||||
bool isOpenedSideB = MusicBox().getIsOpenedSideB();
|
bool isOpenedSideB = MusicBox().getIsOpenedSideB();
|
||||||
if (isOpenedSideB) {
|
if (isOpenedSideB) {
|
||||||
LogUtil.d('进入过B面');
|
LogUtil.d('进入过B面');
|
||||||
_openSideB();
|
_openSideB('进入过B面');
|
||||||
} else {
|
} else {
|
||||||
bool enter = MusicBox().getEnter();
|
bool enter = MusicBox().getEnter();
|
||||||
String versionCode = await MusicBox().getVersionCode();
|
String versionCode = await MusicBox().getVersionCode();
|
||||||
final packageInfo = await PackageInfo.fromPlatform();
|
final packageInfo = await PackageInfo.fromPlatform();
|
||||||
if (versionCode != packageInfo.version) {
|
if (versionCode != packageInfo.version) {
|
||||||
LogUtil.d('版本不相同,进入B面');
|
LogUtil.d('版本不相同,进入B面');
|
||||||
_openSideB();
|
_openSideB('版本不相同');
|
||||||
} else {
|
} else {
|
||||||
if (enter) {
|
if (enter) {
|
||||||
LogUtil.d('开关:打开');
|
LogUtil.d('开关:打开');
|
||||||
_openSideB();
|
_openSideB('版本相同, 开关打开');
|
||||||
} else {
|
} else {
|
||||||
LogUtil.d('开关:关闭');
|
LogUtil.d('开关:关闭');
|
||||||
_openSideA();
|
_openSideA();
|
||||||
@ -96,26 +87,26 @@ class LaunchController extends GetxController with GetSingleTickerProviderStateM
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _openSideA() {
|
void _openSideA() {
|
||||||
AppOpenAdManager().showAdIfAvailable(onTap: () {
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
AppConfig.appSideEnum = AppSideEnum.sideA;
|
AdScenes.coldLoading.name,
|
||||||
Get.offNamed(AppRoutes.initialA);
|
onTap: () {
|
||||||
});
|
AppConfig.appSideEnum = AppSideEnum.sideA;
|
||||||
|
Get.offNamed(AppRoutes.initialA);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
FirebaseAnalyticsManager.logJumpEvent('A', '版本相同,开关关闭');
|
||||||
}
|
}
|
||||||
|
|
||||||
void _openSideB() {
|
void _openSideB(String reason) {
|
||||||
AppOpenAdManager().showAdIfAvailable(onTap: () {
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
AppConfig.appSideEnum = AppSideEnum.sideB;
|
AdScenes.coldLoading.name,
|
||||||
MainController.to.changeTheme();
|
onTap: () {
|
||||||
Get.offNamed(AppRoutes.initialB);
|
AppConfig.appSideEnum = AppSideEnum.sideB;
|
||||||
MusicBox().putIsOpenedSideB(true);
|
MainController.to.changeTheme();
|
||||||
});
|
Get.offNamed(AppRoutes.initialB);
|
||||||
}
|
MusicBox().putIsOpenedSideB(true);
|
||||||
|
},
|
||||||
/// 获取所在区域
|
);
|
||||||
Future<void> getIsoCode() async {
|
FirebaseAnalyticsManager.logJumpEvent('B', reason);
|
||||||
BaseModel<IsoCodeModel>? model = await TikUsTokApi.getIsoCode();
|
|
||||||
if (model != null && model.success && model.data?.isoCode != null) {
|
|
||||||
AppConfig.isoCode = model.data!.isoCode!;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import 'package:get/get.dart';
|
|||||||
import 'package:step_progress_indicator/step_progress_indicator.dart';
|
import 'package:step_progress_indicator/step_progress_indicator.dart';
|
||||||
import 'package:tone_snap/generated/assets.dart';
|
import 'package:tone_snap/generated/assets.dart';
|
||||||
import 'package:tone_snap/modules/launch/launch_controller.dart';
|
import 'package:tone_snap/modules/launch/launch_controller.dart';
|
||||||
import 'package:tone_snap/res/themes/app_colors.dart';
|
|
||||||
|
|
||||||
class LaunchView extends StatelessWidget {
|
class LaunchView extends StatelessWidget {
|
||||||
LaunchView({super.key});
|
LaunchView({super.key});
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import 'package:ffmpeg_kit_flutter_audio/return_code.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
import 'package:tone_snap/components/base_easyloading.dart';
|
import 'package:tone_snap/components/base_easyloading.dart';
|
||||||
|
import 'package:tone_snap/data/enum/ad_scenes.dart';
|
||||||
import 'package:tone_snap/data/models/voice_model.dart';
|
import 'package:tone_snap/data/models/voice_model.dart';
|
||||||
import 'package:tone_snap/data/storage/my_voice_box.dart';
|
import 'package:tone_snap/data/storage/my_voice_box.dart';
|
||||||
import 'package:tone_snap/generated/assets.dart';
|
import 'package:tone_snap/generated/assets.dart';
|
||||||
@ -46,8 +47,6 @@ class ChangeVoiceController extends GetxController {
|
|||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
InterstitialAdManager().loadAd();
|
|
||||||
|
|
||||||
filePath = Get.arguments;
|
filePath = Get.arguments;
|
||||||
// playerController.setFilePath(filePath);
|
// playerController.setFilePath(filePath);
|
||||||
}
|
}
|
||||||
@ -104,9 +103,10 @@ class ChangeVoiceController extends GetxController {
|
|||||||
|
|
||||||
/// 保存
|
/// 保存
|
||||||
Future<void> save() async {
|
Future<void> save() async {
|
||||||
// 显示插页广告
|
|
||||||
InterstitialAdManager().showAdIfAvailable(
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
|
AdScenes.download.name,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
|
await playerController.startPlay();
|
||||||
// 停止播放
|
// 停止播放
|
||||||
if (playerController.isPlaying.value) playerController.stopPlay();
|
if (playerController.isPlaying.value) playerController.stopPlay();
|
||||||
BaseEasyLoading.loading();
|
BaseEasyLoading.loading();
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
import 'package:tone_snap/components/base_easyloading.dart';
|
import 'package:tone_snap/components/base_easyloading.dart';
|
||||||
|
import 'package:tone_snap/data/enum/ad_scenes.dart';
|
||||||
import 'package:tone_snap/data/models/voice_model.dart';
|
import 'package:tone_snap/data/models/voice_model.dart';
|
||||||
import 'package:tone_snap/generated/assets.dart';
|
import 'package:tone_snap/generated/assets.dart';
|
||||||
import 'package:tone_snap/modules/sidea/controllers/player_controller.dart';
|
import 'package:tone_snap/modules/sidea/controllers/player_controller.dart';
|
||||||
@ -22,22 +24,32 @@ class HomeController extends GetxController {
|
|||||||
];
|
];
|
||||||
|
|
||||||
void onTapItem(VoiceModel item) {
|
void onTapItem(VoiceModel item) {
|
||||||
InitialController.to.currentPlayVoiceModel.value = item;
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
Get.toNamed(AppRoutes.playSound, arguments: item);
|
AdScenes.play.name,
|
||||||
|
onTap: () {
|
||||||
|
InitialController.to.currentPlayVoiceModel.value = item;
|
||||||
|
Get.toNamed(AppRoutes.playSound, arguments: item);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> onTapPlayBarPlay(VoiceModel item) async {
|
Future<void> onTapPlayBarPlay(VoiceModel item) async {
|
||||||
if (isPlayItem(item)) {
|
if (isPlayItem(item)) {
|
||||||
await playerController.pausePlay();
|
await playerController.pausePlay();
|
||||||
} else {
|
} else {
|
||||||
if (!identical(item, InitialController.to.currentPlayVoiceModel.value)) {
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
BaseEasyLoading.loading();
|
AdScenes.play.name,
|
||||||
await playerController.setFilePath(item.path);
|
onTap: () async {
|
||||||
BaseEasyLoading.dismiss();
|
if (!identical(item, InitialController.to.currentPlayVoiceModel.value)) {
|
||||||
InitialController.to.currentPlayVoiceModel.value = item;
|
BaseEasyLoading.loading();
|
||||||
InitialController.to.isFavourite.value = InitialController.to.getIsFavouriteModel() != null;
|
await playerController.setFilePath(item.path);
|
||||||
}
|
BaseEasyLoading.dismiss();
|
||||||
await playerController.startPlay();
|
InitialController.to.currentPlayVoiceModel.value = item;
|
||||||
|
InitialController.to.isFavourite.value = InitialController.to.getIsFavouriteModel() != null;
|
||||||
|
}
|
||||||
|
await playerController.startPlay();
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import 'package:tone_snap/data/models/voice_model.dart';
|
|||||||
import 'package:tone_snap/data/storage/favorite_box.dart';
|
import 'package:tone_snap/data/storage/favorite_box.dart';
|
||||||
import 'package:tone_snap/firebase/firebase_analytics_manager.dart';
|
import 'package:tone_snap/firebase/firebase_analytics_manager.dart';
|
||||||
import 'package:tone_snap/generated/assets.dart';
|
import 'package:tone_snap/generated/assets.dart';
|
||||||
|
import 'package:tone_snap/global/app_lifecycle_reactor.dart';
|
||||||
import 'package:tone_snap/global/app_tracking_transparency_manager.dart';
|
import 'package:tone_snap/global/app_tracking_transparency_manager.dart';
|
||||||
import 'package:tone_snap/modules/sidea/controllers/player_controller.dart';
|
import 'package:tone_snap/modules/sidea/controllers/player_controller.dart';
|
||||||
import 'package:tone_snap/modules/sidea/favourite/favourite_controller.dart';
|
import 'package:tone_snap/modules/sidea/favourite/favourite_controller.dart';
|
||||||
@ -12,6 +13,8 @@ import 'package:tone_snap/modules/sidea/me/me_view.dart';
|
|||||||
import 'package:tone_snap/modules/sidea/my_voice/my_voice_controller.dart';
|
import 'package:tone_snap/modules/sidea/my_voice/my_voice_controller.dart';
|
||||||
import 'package:tone_snap/modules/sidea/settings/settings_view.dart';
|
import 'package:tone_snap/modules/sidea/settings/settings_view.dart';
|
||||||
import 'package:tone_snap/routes/app_routes.dart';
|
import 'package:tone_snap/routes/app_routes.dart';
|
||||||
|
import 'package:tone_snap/utils/file_util.dart';
|
||||||
|
import 'package:tone_snap/utils/local_path_util.dart';
|
||||||
|
|
||||||
class InitialController extends GetxController {
|
class InitialController extends GetxController {
|
||||||
static InitialController get to => Get.find<InitialController>();
|
static InitialController get to => Get.find<InitialController>();
|
||||||
@ -29,17 +32,27 @@ class InitialController extends GetxController {
|
|||||||
/// 是否收藏
|
/// 是否收藏
|
||||||
var isFavourite = false.obs;
|
var isFavourite = false.obs;
|
||||||
|
|
||||||
|
late AppLifecycleReactor _appLifecycleReactor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
AppTrackingTransparencyManager().requestATT();
|
AppTrackingTransparencyManager().requestATT();
|
||||||
|
|
||||||
|
_appLifecycleReactor = AppLifecycleReactor();
|
||||||
|
_appLifecycleReactor.listenToAppStateChanges();
|
||||||
|
|
||||||
pageController = PageController(initialPage: currentIndex.value);
|
pageController = PageController(initialPage: currentIndex.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onReady() async {
|
void onReady() async {
|
||||||
super.onReady();
|
super.onReady();
|
||||||
_addEventLog();
|
// 删除缓存文件
|
||||||
|
FileUtil.deleteAllFilesInDirectory(await LocalPathUtil.getRecordingsDir());
|
||||||
|
FileUtil.deleteAllFilesInDirectory(await LocalPathUtil.getAssetsDir());
|
||||||
|
|
||||||
|
FirebaseAnalyticsManager.logHomeAPV();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -55,10 +68,10 @@ class InitialController extends GetxController {
|
|||||||
} else {
|
} else {
|
||||||
currentIndex.value = index;
|
currentIndex.value = index;
|
||||||
pageController.jumpToPage(index);
|
pageController.jumpToPage(index);
|
||||||
if (index == 0) {
|
|
||||||
_addEventLog();
|
|
||||||
}
|
|
||||||
if (index == 2) _refreshMe();
|
if (index == 2) _refreshMe();
|
||||||
|
if (index == 0) {
|
||||||
|
FirebaseAnalyticsManager.logHomeAPV();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,11 +108,6 @@ class InitialController extends GetxController {
|
|||||||
if (Get.isRegistered<MyVoiceController>()) MyVoiceController.to.getData();
|
if (Get.isRegistered<MyVoiceController>()) MyVoiceController.to.getData();
|
||||||
if (Get.isRegistered<FavouriteController>()) FavouriteController.to.getData();
|
if (Get.isRegistered<FavouriteController>()) FavouriteController.to.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 埋点
|
|
||||||
void _addEventLog() {
|
|
||||||
FirebaseAnalyticsManager.logEvent(FirebaseAnalyticsManager.homeApv);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class PageItem {
|
class PageItem {
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:tone_snap/components/base_easyloading.dart';
|
import 'package:tone_snap/components/base_easyloading.dart';
|
||||||
import 'package:tone_snap/components/dialog/add_playlist_dialog.dart';
|
import 'package:tone_snap/components/dialog/add_playlist_dialog.dart';
|
||||||
@ -19,7 +18,7 @@ class AddToPlaylistBottomSheetController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _getList() {
|
void _getList() {
|
||||||
playlists.value = PlaylistsBox().getReversedList();
|
playlists.value = PlaylistsBox().getList();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMusicModel(MusicModel musicModel) {
|
void setMusicModel(MusicModel musicModel) {
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import 'dart:ffi';
|
|
||||||
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
import 'package:tone_snap/components/base_easyloading.dart';
|
import 'package:tone_snap/components/base_easyloading.dart';
|
||||||
import 'package:tone_snap/components/view_state_widget.dart';
|
import 'package:tone_snap/components/view_state_widget.dart';
|
||||||
import 'package:tone_snap/data/api/music_api.dart';
|
import 'package:tone_snap/data/api/music_api.dart';
|
||||||
|
import 'package:tone_snap/data/enum/ad_scenes.dart';
|
||||||
import 'package:tone_snap/data/models/browse_model.dart';
|
import 'package:tone_snap/data/models/browse_model.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/collect_playlists_box.dart';
|
import 'package:tone_snap/data/storage/collect_playlists_box.dart';
|
||||||
|
import 'package:tone_snap/firebase/firebase_analytics_manager.dart';
|
||||||
import 'package:tone_snap/modules/sideb/collect_playlists/collect_playlists_controller.dart';
|
import 'package:tone_snap/modules/sideb/collect_playlists/collect_playlists_controller.dart';
|
||||||
import 'package:tone_snap/modules/sideb/controllers/music_player_controller.dart';
|
import 'package:tone_snap/modules/sideb/controllers/music_player_controller.dart';
|
||||||
import 'package:tone_snap/routes/app_routes.dart';
|
import 'package:tone_snap/routes/app_routes.dart';
|
||||||
@ -103,6 +104,9 @@ class AlbumSongListController extends GetxController {
|
|||||||
if (thumbnails != null && thumbnails.isNotEmpty) {
|
if (thumbnails != null && thumbnails.isNotEmpty) {
|
||||||
musicModel.coverUrl = thumbnails.last.url;
|
musicModel.coverUrl = thumbnails.last.url;
|
||||||
}
|
}
|
||||||
|
if (ObjUtil.isEmpty(musicModel.coverUrl)) {
|
||||||
|
musicModel.coverUrl = coverUrl.value;
|
||||||
|
}
|
||||||
|
|
||||||
var flexColumns = o.musicResponsiveListItemRenderer?.flexColumns;
|
var flexColumns = o.musicResponsiveListItemRenderer?.flexColumns;
|
||||||
if (flexColumns != null && flexColumns.isNotEmpty) {
|
if (flexColumns != null && flexColumns.isNotEmpty) {
|
||||||
@ -142,21 +146,25 @@ class AlbumSongListController extends GetxController {
|
|||||||
/// 点击播放全部歌曲
|
/// 点击播放全部歌曲
|
||||||
Future<void> onTapPlayAll(bool isShuffle) async {
|
Future<void> onTapPlayAll(bool isShuffle) async {
|
||||||
if (musicList.isNotEmpty) {
|
if (musicList.isNotEmpty) {
|
||||||
int index = 0;
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
if (isShuffle && musicList.length > 1) {
|
AdScenes.play.name,
|
||||||
final n = musicList.indexWhere((e) => e.videoId == musicPlayerController.getMusicModel()?.videoId);
|
onTap: () {
|
||||||
if (n != -1) {
|
int index = 0;
|
||||||
index = NumUtil.getRandomNumberExcludingCurrent(0, musicList.length, n);
|
if (isShuffle && musicList.length > 1) {
|
||||||
} else {
|
final n = musicList.indexWhere((e) => e.videoId == musicPlayerController.getMusicModel()?.videoId);
|
||||||
index = NumUtil.getRandomNumber(0, musicList.length);
|
if (n != -1) {
|
||||||
}
|
index = NumUtil.getRandomNumberExcludingCurrent(0, musicList.length, n);
|
||||||
}
|
} else {
|
||||||
for (var o in musicList) {
|
index = NumUtil.getRandomNumber(0, musicList.length);
|
||||||
if (ObjUtil.isEmpty(o.coverUrl)) {
|
}
|
||||||
o.coverUrl = coverUrl.value;
|
}
|
||||||
}
|
Get.toNamed(AppRoutes.playPage, arguments: {
|
||||||
}
|
'videoId': musicList[index].videoId,
|
||||||
musicPlayerController.playMusic(musicList[index].videoId, playList: musicList);
|
'playList': musicList,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
FirebaseAnalyticsManager.logSongClick('来自专辑/歌单');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,9 +194,15 @@ class AlbumSongListController extends GetxController {
|
|||||||
|
|
||||||
/// 点击列表
|
/// 点击列表
|
||||||
void onTapItem(MusicModel musicModel) {
|
void onTapItem(MusicModel musicModel) {
|
||||||
Get.toNamed(AppRoutes.playPage, arguments: {
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
'videoId': musicModel.videoId,
|
AdScenes.play.name,
|
||||||
'playlistId': musicModel.playlistId,
|
onTap: () {
|
||||||
});
|
Get.toNamed(AppRoutes.playPage, arguments: {
|
||||||
|
'videoId': musicModel.videoId,
|
||||||
|
'playList': musicList,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
FirebaseAnalyticsManager.logSongClick('来自专辑/歌单');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import 'package:tone_snap/data/models/music_model.dart';
|
|||||||
import 'package:tone_snap/data/models/player_model.dart';
|
import 'package:tone_snap/data/models/player_model.dart';
|
||||||
import 'package:tone_snap/data/storage/music_box.dart';
|
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/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/routes/app_routes.dart';
|
||||||
import 'package:tone_snap/utils/audio_util.dart';
|
import 'package:tone_snap/utils/audio_util.dart';
|
||||||
@ -67,6 +68,9 @@ class MusicPlayerController extends GetxController {
|
|||||||
/// 当前播放的歌曲索引
|
/// 当前播放的歌曲索引
|
||||||
var currentIndex = 0.obs;
|
var currentIndex = 0.obs;
|
||||||
|
|
||||||
|
/// 播放成功打点时的videoId,防止同一首歌播放状态监听重复打点
|
||||||
|
String? _logVideoId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
@ -100,15 +104,18 @@ class MusicPlayerController extends GetxController {
|
|||||||
/// 播放歌曲
|
/// 播放歌曲
|
||||||
Future<void> _startPlay() async {
|
Future<void> _startPlay() async {
|
||||||
if (playlist.isNotEmpty) {
|
if (playlist.isNotEmpty) {
|
||||||
|
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 {
|
||||||
|
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)) {
|
||||||
// 有下载
|
// 有下载
|
||||||
LogUtil.d('读取下载路径=${model.localPath}');
|
LogUtil.d('读取下载路径=${model.localPath}');
|
||||||
if (!await File(model.localPath!).exists()) {
|
if (!await File(model.localPath!).exists()) {
|
||||||
BaseEasyLoading.toast('file does not exist');
|
BaseEasyLoading.toast('file does not exist');
|
||||||
|
FirebaseAnalyticsManager.logPlayerBFailAction('本地文件不存在');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await _player.setFilePath(model.localPath!);
|
await _player.setFilePath(model.localPath!);
|
||||||
@ -136,9 +143,20 @@ class MusicPlayerController extends GetxController {
|
|||||||
_cancelListening();
|
_cancelListening();
|
||||||
_addListening();
|
_addListening();
|
||||||
_player.play();
|
_player.play();
|
||||||
|
|
||||||
|
DateTime endLoadDateTime = DateTime.now();
|
||||||
|
// 获取毫秒差
|
||||||
|
int millisecondsDifference = endLoadDateTime.difference(startLoadDateTime).inMilliseconds;
|
||||||
|
FirebaseAnalyticsManager.logPlayerBDelayAction(
|
||||||
|
getMusicModel()?.videoId,
|
||||||
|
getMusicModel()?.title,
|
||||||
|
getMusicModel()?.subtitle,
|
||||||
|
'${millisecondsDifference}ms',
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
LogUtil.e('Play failed: $e');
|
LogUtil.e('Play failed: $e');
|
||||||
BaseEasyLoading.toast('Play failed');
|
BaseEasyLoading.toast('Play failed');
|
||||||
|
FirebaseAnalyticsManager.logPlayerBFailAction(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,6 +218,16 @@ class MusicPlayerController extends GetxController {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (isPlaying.value) {
|
||||||
|
if (_logVideoId != getMusicModel()?.videoId) {
|
||||||
|
_logVideoId = getMusicModel()?.videoId;
|
||||||
|
FirebaseAnalyticsManager.logPlayerBSuccessAction(
|
||||||
|
getMusicModel()?.videoId,
|
||||||
|
getMusicModel()?.title,
|
||||||
|
getMusicModel()?.subtitle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
import 'package:tone_snap/components/view_state_widget.dart';
|
import 'package:tone_snap/components/view_state_widget.dart';
|
||||||
|
import 'package:tone_snap/data/enum/ad_scenes.dart';
|
||||||
import 'package:tone_snap/data/models/music_model.dart';
|
import 'package:tone_snap/data/models/music_model.dart';
|
||||||
import 'package:tone_snap/data/models/playlist_model.dart';
|
import 'package:tone_snap/data/models/playlist_model.dart';
|
||||||
import 'package:tone_snap/data/storage/playlists_box.dart';
|
import 'package:tone_snap/data/storage/playlists_box.dart';
|
||||||
|
import 'package:tone_snap/firebase/firebase_analytics_manager.dart';
|
||||||
import 'package:tone_snap/modules/sideb/controllers/music_player_controller.dart';
|
import 'package:tone_snap/modules/sideb/controllers/music_player_controller.dart';
|
||||||
import 'package:tone_snap/modules/sideb/more_playlist_bottom_sheet/more_playlist_bottom_sheet_view.dart';
|
import 'package:tone_snap/modules/sideb/more_playlist_bottom_sheet/more_playlist_bottom_sheet_view.dart';
|
||||||
import 'package:tone_snap/routes/app_routes.dart';
|
import 'package:tone_snap/routes/app_routes.dart';
|
||||||
@ -64,16 +67,25 @@ class CustomPlaylistController extends GetxController {
|
|||||||
|
|
||||||
Future<void> onTapPlayAll(bool isShuffle) async {
|
Future<void> onTapPlayAll(bool isShuffle) async {
|
||||||
if (musicList.isNotEmpty) {
|
if (musicList.isNotEmpty) {
|
||||||
int index = 0;
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
if (isShuffle && musicList.length > 1) {
|
AdScenes.play.name,
|
||||||
final n = musicList.indexWhere((e) => e.videoId == musicPlayerController.getMusicModel()?.videoId);
|
onTap: () {
|
||||||
if (n != -1) {
|
int index = 0;
|
||||||
index = NumUtil.getRandomNumberExcludingCurrent(0, musicList.length, n);
|
if (isShuffle && musicList.length > 1) {
|
||||||
} else {
|
final n = musicList.indexWhere((e) => e.videoId == musicPlayerController.getMusicModel()?.videoId);
|
||||||
index = NumUtil.getRandomNumber(0, musicList.length);
|
if (n != -1) {
|
||||||
}
|
index = NumUtil.getRandomNumberExcludingCurrent(0, musicList.length, n);
|
||||||
}
|
} else {
|
||||||
musicPlayerController.playMusic(musicList[index].videoId, playList: musicList);
|
index = NumUtil.getRandomNumber(0, musicList.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Get.toNamed(AppRoutes.playPage, arguments: {
|
||||||
|
'videoId': musicList[index].videoId,
|
||||||
|
'playList': musicList,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
FirebaseAnalyticsManager.logSongClick('来自自建歌单列表');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,9 +115,15 @@ class CustomPlaylistController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onTapItem(MusicModel musicModel) {
|
void onTapItem(MusicModel musicModel) {
|
||||||
Get.toNamed(AppRoutes.playPage, arguments: {
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
'videoId': musicModel.videoId,
|
AdScenes.play.name,
|
||||||
'playList': musicList.toList(),
|
onTap: () {
|
||||||
});
|
Get.toNamed(AppRoutes.playPage, arguments: {
|
||||||
|
'videoId': musicModel.videoId,
|
||||||
|
'playList': musicList,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
FirebaseAnalyticsManager.logSongClick('来自自建歌单列表');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,21 @@
|
|||||||
import 'package:easy_refresh/easy_refresh.dart';
|
import 'package:easy_refresh/easy_refresh.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
import 'package:tone_snap/components/view_state_widget.dart';
|
import 'package:tone_snap/components/view_state_widget.dart';
|
||||||
import 'package:tone_snap/data/api/music_api.dart';
|
import 'package:tone_snap/data/api/music_api.dart';
|
||||||
|
import 'package:tone_snap/data/api/tikustok_api.dart';
|
||||||
|
import 'package:tone_snap/data/enum/ad_scenes.dart';
|
||||||
import 'package:tone_snap/data/enum/music_type.dart';
|
import 'package:tone_snap/data/enum/music_type.dart';
|
||||||
|
import 'package:tone_snap/data/models/base_model.dart';
|
||||||
import 'package:tone_snap/data/models/browse_group_model.dart';
|
import 'package:tone_snap/data/models/browse_group_model.dart';
|
||||||
import 'package:tone_snap/data/models/browse_model.dart';
|
import 'package:tone_snap/data/models/browse_model.dart';
|
||||||
|
import 'package:tone_snap/data/models/isocode_model.dart';
|
||||||
import 'package:tone_snap/data/models/music_model.dart';
|
import 'package:tone_snap/data/models/music_model.dart';
|
||||||
|
import 'package:tone_snap/data/network/base_error.dart';
|
||||||
|
import 'package:tone_snap/firebase/firebase_analytics_manager.dart';
|
||||||
|
import 'package:tone_snap/global/app_config.dart';
|
||||||
import 'package:tone_snap/routes/app_routes.dart';
|
import 'package:tone_snap/routes/app_routes.dart';
|
||||||
|
import 'package:tone_snap/utils/obj_util.dart';
|
||||||
|
|
||||||
class HomeController extends GetxController {
|
class HomeController extends GetxController {
|
||||||
static HomeController get to => Get.find<HomeController>();
|
static HomeController get to => Get.find<HomeController>();
|
||||||
@ -42,13 +50,29 @@ class HomeController extends GetxController {
|
|||||||
firstBrowse();
|
firstBrowse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 获取所在区域
|
||||||
|
Future<void> _getIsoCode() async {
|
||||||
|
BaseModel<IsoCodeModel>? model = await TikUsTokApi.getIsoCode();
|
||||||
|
if (model != null && model.success && model.data?.isoCode != null) {
|
||||||
|
AppConfig.isoCode = model.data!.isoCode!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 首次请求
|
/// 首次请求
|
||||||
Future<void> firstBrowse() async {
|
Future<void> firstBrowse() async {
|
||||||
|
await _getIsoCode();
|
||||||
Map<String, dynamic> queryParameters = {
|
Map<String, dynamic> queryParameters = {
|
||||||
'prettyPrint': false,
|
'prettyPrint': false,
|
||||||
'browseId': 'FEmusic_home'
|
'browseId': 'FEmusic_home'
|
||||||
};
|
};
|
||||||
BrowseModel? browseModel = await MusicApi.browse<BrowseModel>(queryParameters: queryParameters, formJson: BrowseModel.fromMap);
|
BrowseModel? browseModel = await MusicApi.browse<BrowseModel>(
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
formJson: BrowseModel.fromMap,
|
||||||
|
fail: (BaseError baseError) {
|
||||||
|
refreshController.finishRefresh(IndicatorResult.fail);
|
||||||
|
FirebaseAnalyticsManager.logHomeBModuleFailAction('${baseError.code},${baseError.message}');
|
||||||
|
},
|
||||||
|
);
|
||||||
if (browseModel != null) {
|
if (browseModel != null) {
|
||||||
refreshController.finishRefresh();
|
refreshController.finishRefresh();
|
||||||
|
|
||||||
@ -65,8 +89,11 @@ class HomeController extends GetxController {
|
|||||||
clickTrackingParams = continuations[0].nextContinuationData?.clickTrackingParams;
|
clickTrackingParams = continuations[0].nextContinuationData?.clickTrackingParams;
|
||||||
}
|
}
|
||||||
_reBrowse(continuation: continuation, clickTrackingParams: clickTrackingParams);
|
_reBrowse(continuation: continuation, clickTrackingParams: clickTrackingParams);
|
||||||
} else {
|
if (groupList.isNotEmpty) {
|
||||||
refreshController.finishRefresh(IndicatorResult.fail);
|
FirebaseAnalyticsManager.logHomeBModuleShowsuccesAction();
|
||||||
|
} else {
|
||||||
|
FirebaseAnalyticsManager.logHomeBModuleFailAction('无数据');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
viewState.value = groupList.isNotEmpty ? ViewState.normal : ViewState.empty;
|
viewState.value = groupList.isNotEmpty ? ViewState.normal : ViewState.empty;
|
||||||
}
|
}
|
||||||
@ -80,7 +107,11 @@ class HomeController extends GetxController {
|
|||||||
'itct': clickTrackingParams,
|
'itct': clickTrackingParams,
|
||||||
'prettyPrint': false
|
'prettyPrint': false
|
||||||
};
|
};
|
||||||
BrowseModel? browseModel = await MusicApi.browse<BrowseModel>(visitorData: visitorData, queryParameters: queryParameters, formJson: BrowseModel.fromMap);
|
BrowseModel? browseModel = await MusicApi.browse<BrowseModel>(
|
||||||
|
visitorData: visitorData,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
formJson: BrowseModel.fromMap,
|
||||||
|
);
|
||||||
if (browseModel != null) {
|
if (browseModel != null) {
|
||||||
_extractAssemblyData(browseModel);
|
_extractAssemblyData(browseModel);
|
||||||
|
|
||||||
@ -191,6 +222,7 @@ class HomeController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void openSearch() {
|
void openSearch() {
|
||||||
|
FirebaseAnalyticsManager.logSearchFromAction('来自首页');
|
||||||
Get.toNamed(AppRoutes.searchResult);
|
Get.toNamed(AppRoutes.searchResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,11 +230,18 @@ class HomeController extends GetxController {
|
|||||||
Get.toNamed(AppRoutes.setting);
|
Get.toNamed(AppRoutes.setting);
|
||||||
}
|
}
|
||||||
|
|
||||||
void openPlayPage(MusicModel musicModel) {
|
void openPlayPage(BrowseGroupModel browseGroupModel, MusicModel musicModel) {
|
||||||
Get.toNamed(AppRoutes.playPage, arguments: {
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
'videoId': musicModel.videoId,
|
AdScenes.play.name,
|
||||||
'playlistId': musicModel.playlistId,
|
onTap: () {
|
||||||
});
|
Get.toNamed(AppRoutes.playPage, arguments: {
|
||||||
|
'videoId': musicModel.videoId,
|
||||||
|
'playlistId': musicModel.playlistId,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
FirebaseAnalyticsManager.logHomeBModuleClick(ObjUtil.getStr(browseGroupModel.groupTitle));
|
||||||
|
FirebaseAnalyticsManager.logSongClick('来自首页');
|
||||||
}
|
}
|
||||||
|
|
||||||
void openAlbumSong(BrowseGroupModel browseGroupModel, MusicModel musicModel) {
|
void openAlbumSong(BrowseGroupModel browseGroupModel, MusicModel musicModel) {
|
||||||
@ -214,5 +253,6 @@ class HomeController extends GetxController {
|
|||||||
'title': musicModel.title,
|
'title': musicModel.title,
|
||||||
'subtitle': musicModel.subtitle,
|
'subtitle': musicModel.subtitle,
|
||||||
});
|
});
|
||||||
|
FirebaseAnalyticsManager.logHomeBModuleClick(ObjUtil.getStr(browseGroupModel.groupTitle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -154,7 +154,7 @@ class HomeView extends GetView<HomeController> {
|
|||||||
final musicModel = browseGroupModel.browseList![index];
|
final musicModel = browseGroupModel.browseList![index];
|
||||||
return BrowseItemAtv(
|
return BrowseItemAtv(
|
||||||
musicModel: musicModel,
|
musicModel: musicModel,
|
||||||
onTap: () => controller.openPlayPage(musicModel),
|
onTap: () => controller.openPlayPage(browseGroupModel, musicModel),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tone_snap/firebase/firebase_analytics_manager.dart';
|
||||||
import 'package:tone_snap/generated/assets.dart';
|
import 'package:tone_snap/generated/assets.dart';
|
||||||
|
import 'package:tone_snap/global/app_lifecycle_reactor.dart';
|
||||||
import 'package:tone_snap/global/app_tracking_transparency_manager.dart';
|
import 'package:tone_snap/global/app_tracking_transparency_manager.dart';
|
||||||
import 'package:tone_snap/modules/sideb/home/home_view.dart';
|
import 'package:tone_snap/modules/sideb/home/home_view.dart';
|
||||||
import 'package:tone_snap/modules/sideb/personal_music_library/personal_music_library_controller.dart';
|
import 'package:tone_snap/modules/sideb/personal_music_library/personal_music_library_controller.dart';
|
||||||
@ -17,11 +19,19 @@ class InitialController extends GetxController {
|
|||||||
];
|
];
|
||||||
var currentIndex = 0.obs;
|
var currentIndex = 0.obs;
|
||||||
|
|
||||||
|
late AppLifecycleReactor _appLifecycleReactor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
AppTrackingTransparencyManager().requestATT();
|
AppTrackingTransparencyManager().requestATT();
|
||||||
|
|
||||||
|
_appLifecycleReactor = AppLifecycleReactor();
|
||||||
|
_appLifecycleReactor.listenToAppStateChanges();
|
||||||
|
|
||||||
pageController = PageController(initialPage: currentIndex.value);
|
pageController = PageController(initialPage: currentIndex.value);
|
||||||
|
|
||||||
|
FirebaseAnalyticsManager.logHomeBPV();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -33,12 +43,18 @@ class InitialController extends GetxController {
|
|||||||
Future<void> onBottomAppBarItemChanged(int index) async {
|
Future<void> onBottomAppBarItemChanged(int index) async {
|
||||||
currentIndex.value = index;
|
currentIndex.value = index;
|
||||||
pageController.jumpToPage(index);
|
pageController.jumpToPage(index);
|
||||||
|
if (index == 0) {
|
||||||
|
FirebaseAnalyticsManager.logHomeBPV();
|
||||||
|
}
|
||||||
|
if (index == 1) {
|
||||||
|
FirebaseAnalyticsManager.logSearchPV();
|
||||||
|
}
|
||||||
if (index == 2) {
|
if (index == 2) {
|
||||||
if (Get.isRegistered<PersonalMusicLibraryController>()) {
|
if (Get.isRegistered<PersonalMusicLibraryController>()) {
|
||||||
PersonalMusicLibraryController.to.refreshLoveSongs();
|
PersonalMusicLibraryController.to.refreshLoveSongs();
|
||||||
PersonalMusicLibraryController.to.refreshOffline();
|
PersonalMusicLibraryController.to.refreshOffline();
|
||||||
}
|
}
|
||||||
|
FirebaseAnalyticsManager.logMeBPV();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
import 'package:tone_snap/components/view_state_widget.dart';
|
import 'package:tone_snap/components/view_state_widget.dart';
|
||||||
|
import 'package:tone_snap/data/enum/ad_scenes.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/love_songs_box.dart';
|
import 'package:tone_snap/data/storage/love_songs_box.dart';
|
||||||
|
import 'package:tone_snap/firebase/firebase_analytics_manager.dart';
|
||||||
import 'package:tone_snap/routes/app_routes.dart';
|
import 'package:tone_snap/routes/app_routes.dart';
|
||||||
|
|
||||||
class LoveSongsController extends GetxController {
|
class LoveSongsController extends GetxController {
|
||||||
@ -21,9 +24,15 @@ class LoveSongsController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onTapItem(MusicModel musicModel) {
|
void onTapItem(MusicModel musicModel) {
|
||||||
Get.toNamed(AppRoutes.playPage, arguments: {
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
'videoId': musicModel.videoId,
|
AdScenes.play.name,
|
||||||
'playList': LoveSongsBox().getReversedList(),
|
onTap: () {
|
||||||
});
|
Get.toNamed(AppRoutes.playPage, arguments: {
|
||||||
|
'videoId': musicModel.videoId,
|
||||||
|
'playList': loveList,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
FirebaseAnalyticsManager.logSongClick('来自收藏列表');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import 'package:tone_snap/data/models/music_model.dart';
|
|||||||
import 'package:tone_snap/data/storage/love_songs_box.dart';
|
import 'package:tone_snap/data/storage/love_songs_box.dart';
|
||||||
import 'package:tone_snap/data/storage/offline_box.dart';
|
import 'package:tone_snap/data/storage/offline_box.dart';
|
||||||
import 'package:tone_snap/data/storage/playlists_box.dart';
|
import 'package:tone_snap/data/storage/playlists_box.dart';
|
||||||
|
import 'package:tone_snap/firebase/firebase_analytics_manager.dart';
|
||||||
import 'package:tone_snap/global/download_manager.dart';
|
import 'package:tone_snap/global/download_manager.dart';
|
||||||
import 'package:tone_snap/modules/sideb/add_to_playlist_bottom_sheet/add_to_playlist_bottom_sheet_view.dart';
|
import 'package:tone_snap/modules/sideb/add_to_playlist_bottom_sheet/add_to_playlist_bottom_sheet_view.dart';
|
||||||
import 'package:tone_snap/modules/sideb/custom_playlist/custom_playlist_controller.dart';
|
import 'package:tone_snap/modules/sideb/custom_playlist/custom_playlist_controller.dart';
|
||||||
@ -33,9 +34,19 @@ class MoreBottomSheetController extends GetxController {
|
|||||||
void onTapLove() async {
|
void onTapLove() async {
|
||||||
if (ObjUtil.isEmpty(musicModel.videoId)) return;
|
if (ObjUtil.isEmpty(musicModel.videoId)) return;
|
||||||
if (isLove.value) {
|
if (isLove.value) {
|
||||||
|
FirebaseAnalyticsManager.logPlayerBUnloveClick(
|
||||||
|
musicModel.videoId,
|
||||||
|
musicModel.title,
|
||||||
|
musicModel.subtitle,
|
||||||
|
);
|
||||||
await LoveSongsBox().delete(musicModel.videoId!);
|
await LoveSongsBox().delete(musicModel.videoId!);
|
||||||
BaseEasyLoading.toast('Removed');
|
BaseEasyLoading.toast('Removed');
|
||||||
} else {
|
} else {
|
||||||
|
FirebaseAnalyticsManager.logPlayerBLoveClick(
|
||||||
|
musicModel.videoId,
|
||||||
|
musicModel.title,
|
||||||
|
musicModel.subtitle,
|
||||||
|
);
|
||||||
await LoveSongsBox().add(musicModel.copyWith());
|
await LoveSongsBox().add(musicModel.copyWith());
|
||||||
BaseEasyLoading.toast('Collected');
|
BaseEasyLoading.toast('Collected');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
|
import 'package:tone_snap/data/enum/ad_scenes.dart';
|
||||||
import 'package:tone_snap/routes/app_routes.dart';
|
import 'package:tone_snap/routes/app_routes.dart';
|
||||||
|
|
||||||
class MusicBarController extends GetxController with GetSingleTickerProviderStateMixin {
|
class MusicBarController extends GetxController with GetSingleTickerProviderStateMixin {
|
||||||
@ -28,8 +30,13 @@ class MusicBarController extends GetxController with GetSingleTickerProviderStat
|
|||||||
|
|
||||||
/// 打开播放页面
|
/// 打开播放页面
|
||||||
void openPlayPage() {
|
void openPlayPage() {
|
||||||
Get.toNamed(AppRoutes.playPage, arguments: {
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
'isFormMusicBar': true,
|
AdScenes.play.name,
|
||||||
});
|
onTap: () {
|
||||||
|
Get.toNamed(AppRoutes.playPage, arguments: {
|
||||||
|
'isFormMusicBar': true,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
import 'package:tone_snap/components/view_state_widget.dart';
|
import 'package:tone_snap/components/view_state_widget.dart';
|
||||||
|
import 'package:tone_snap/data/enum/ad_scenes.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/data/storage/offline_box.dart';
|
||||||
|
import 'package:tone_snap/firebase/firebase_analytics_manager.dart';
|
||||||
import 'package:tone_snap/routes/app_routes.dart';
|
import 'package:tone_snap/routes/app_routes.dart';
|
||||||
|
|
||||||
class OfflineController extends GetxController {
|
class OfflineController extends GetxController {
|
||||||
@ -21,9 +24,15 @@ class OfflineController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onTapItem(MusicModel model) {
|
void onTapItem(MusicModel model) {
|
||||||
Get.toNamed(AppRoutes.playPage, arguments: {
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
'videoId': model.videoId,
|
AdScenes.play.name,
|
||||||
'playList': OfflineBox().getReversedList(),
|
onTap: () {
|
||||||
});
|
Get.toNamed(AppRoutes.playPage, arguments: {
|
||||||
|
'videoId': model.videoId,
|
||||||
|
'playList': offlineList,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
FirebaseAnalyticsManager.logSongClick('来自离线列表');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
|
import 'package:tone_snap/data/enum/ad_scenes.dart';
|
||||||
import 'package:tone_snap/data/storage/love_songs_box.dart';
|
import 'package:tone_snap/data/storage/love_songs_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/modules/sideb/collect_playlists/collect_playlists_view.dart';
|
import 'package:tone_snap/modules/sideb/collect_playlists/collect_playlists_view.dart';
|
||||||
import 'package:tone_snap/modules/sideb/playlists/playlists_view.dart';
|
import 'package:tone_snap/modules/sideb/playlists/playlists_view.dart';
|
||||||
import 'package:tone_snap/routes/app_routes.dart';
|
import 'package:tone_snap/routes/app_routes.dart';
|
||||||
|
|
||||||
|
import '../../../ads/library_native_ad_manager.dart';
|
||||||
|
|
||||||
class PersonalMusicLibraryController extends GetxController with GetSingleTickerProviderStateMixin {
|
class PersonalMusicLibraryController extends GetxController with GetSingleTickerProviderStateMixin {
|
||||||
static PersonalMusicLibraryController get to => Get.find<PersonalMusicLibraryController>();
|
static PersonalMusicLibraryController get to => Get.find<PersonalMusicLibraryController>();
|
||||||
var loveSongsCoverUrl = ''.obs;
|
var loveSongsCoverUrl = ''.obs;
|
||||||
@ -32,19 +37,37 @@ class PersonalMusicLibraryController extends GetxController with GetSingleTicker
|
|||||||
@override
|
@override
|
||||||
void onClose() {
|
void onClose() {
|
||||||
tabController.dispose();
|
tabController.dispose();
|
||||||
|
LibraryNativeAdManager().nativeAd?.dispose();
|
||||||
super.onClose();
|
super.onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTapModule(int index) {
|
void onTapModule(int index) {
|
||||||
|
String routeName;
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
Get.toNamed(AppRoutes.loveSongs);
|
routeName = AppRoutes.loveSongs;
|
||||||
}
|
FirebaseAnalyticsManager.logLibraryClick(
|
||||||
if (index == 1) {
|
'曲库页面',
|
||||||
Get.toNamed(AppRoutes.artists);
|
'收藏歌曲',
|
||||||
}
|
);
|
||||||
if (index == 2) {
|
} else if (index == 1) {
|
||||||
Get.toNamed(AppRoutes.offline);
|
routeName = AppRoutes.artists;
|
||||||
|
FirebaseAnalyticsManager.logLibraryClick(
|
||||||
|
'曲库页面',
|
||||||
|
'收藏艺术家',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
routeName = AppRoutes.offline;
|
||||||
|
FirebaseAnalyticsManager.logLibraryClick(
|
||||||
|
'曲库页面',
|
||||||
|
'离线列表',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
|
AdScenes.list.name,
|
||||||
|
onTap: () {
|
||||||
|
Get.toNamed(routeName);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void refreshLoveSongs() {
|
void refreshLoveSongs() {
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
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:google_mobile_ads/google_mobile_ads.dart';
|
||||||
|
import 'package:tone_snap/ads/library_native_ad_manager.dart';
|
||||||
import 'package:tone_snap/components/keep_alive_wrapper.dart';
|
import 'package:tone_snap/components/keep_alive_wrapper.dart';
|
||||||
import 'package:tone_snap/components/my_custom_indicator.dart';
|
import 'package:tone_snap/components/my_custom_indicator.dart';
|
||||||
import 'package:tone_snap/components/network_image_widget.dart';
|
import 'package:tone_snap/components/network_image_widget.dart';
|
||||||
@ -20,12 +22,14 @@ class PersonalMusicLibraryView extends GetView<PersonalMusicLibraryController> {
|
|||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
_buildPageBg(),
|
_buildPageBg(),
|
||||||
SafeArea(
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
_buildModule(),
|
_buildModule(),
|
||||||
|
// _buildAdWidget(),
|
||||||
_buildTabBar(),
|
_buildTabBar(),
|
||||||
_buildTabBarView(),
|
_buildTabBarView(),
|
||||||
],
|
],
|
||||||
@ -57,9 +61,25 @@ class PersonalMusicLibraryView extends GetView<PersonalMusicLibraryController> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildAdWidget() {
|
||||||
|
return Obx(() {
|
||||||
|
if (LibraryNativeAdManager().nativeAdIsLoaded.value
|
||||||
|
&& LibraryNativeAdManager().nativeAd != null) {
|
||||||
|
return Container(
|
||||||
|
width: 1.sw,
|
||||||
|
height: 320.h,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||||
|
child: AdWidget(ad: LibraryNativeAdManager().nativeAd!),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildModule() {
|
Widget _buildModule() {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.symmetric(vertical: 28.h, horizontal: 16.w),
|
padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 16.w),
|
||||||
child: Row(
|
child: Row(
|
||||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
import 'package:background_downloader/background_downloader.dart';
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
import 'package:tone_snap/components/base_easyloading.dart';
|
import 'package:tone_snap/components/base_easyloading.dart';
|
||||||
import 'package:tone_snap/components/dialog/remind_dialog.dart';
|
import 'package:tone_snap/components/dialog/remind_dialog.dart';
|
||||||
import 'package:tone_snap/data/api/music_api.dart';
|
import 'package:tone_snap/data/api/music_api.dart';
|
||||||
|
import 'package:tone_snap/data/enum/ad_scenes.dart';
|
||||||
import 'package:tone_snap/data/models/music_model.dart';
|
import 'package:tone_snap/data/models/music_model.dart';
|
||||||
import 'package:tone_snap/data/models/next_model.dart';
|
import 'package:tone_snap/data/models/next_model.dart';
|
||||||
import 'package:tone_snap/data/storage/love_songs_box.dart';
|
import 'package:tone_snap/data/storage/love_songs_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/global/download_manager.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/controllers/music_player_controller.dart';
|
||||||
import 'package:tone_snap/modules/sideb/personal_music_library/personal_music_library_controller.dart';
|
import 'package:tone_snap/modules/sideb/personal_music_library/personal_music_library_controller.dart';
|
||||||
@ -30,9 +33,13 @@ class PlayPageController extends GetxController {
|
|||||||
musicPlayerController.playlist.clear();
|
musicPlayerController.playlist.clear();
|
||||||
musicPlayerController.resetPlaybackStatus();
|
musicPlayerController.resetPlaybackStatus();
|
||||||
playList = await _next(videoId, playlistId);
|
playList = await _next(videoId, playlistId);
|
||||||
|
if (playList.isNotEmpty) {
|
||||||
|
FirebaseAnalyticsManager.logPlayerBList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
musicPlayerController.playMusic(videoId, playList: playList);
|
musicPlayerController.playMusic(videoId, playList: playList);
|
||||||
}
|
}
|
||||||
|
FirebaseAnalyticsManager.logPlayerBImp();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 获取播放列表
|
/// 获取播放列表
|
||||||
@ -91,9 +98,19 @@ class PlayPageController extends GetxController {
|
|||||||
if (ObjUtil.isEmpty(musicPlayerController.getMusicModel()?.videoId)) return;
|
if (ObjUtil.isEmpty(musicPlayerController.getMusicModel()?.videoId)) return;
|
||||||
final isLove = LoveSongsBox().checkLove(musicPlayerController.getMusicModel()!.videoId);
|
final isLove = LoveSongsBox().checkLove(musicPlayerController.getMusicModel()!.videoId);
|
||||||
if (isLove) {
|
if (isLove) {
|
||||||
|
FirebaseAnalyticsManager.logPlayerBUnloveClick(
|
||||||
|
musicPlayerController.getMusicModel()?.videoId,
|
||||||
|
musicPlayerController.getMusicModel()?.title,
|
||||||
|
musicPlayerController.getMusicModel()?.subtitle,
|
||||||
|
);
|
||||||
await LoveSongsBox().delete(musicPlayerController.getMusicModel()!.videoId!);
|
await LoveSongsBox().delete(musicPlayerController.getMusicModel()!.videoId!);
|
||||||
BaseEasyLoading.toast('Removed');
|
BaseEasyLoading.toast('Removed');
|
||||||
} else {
|
} else {
|
||||||
|
FirebaseAnalyticsManager.logPlayerBLoveClick(
|
||||||
|
musicPlayerController.getMusicModel()?.videoId,
|
||||||
|
musicPlayerController.getMusicModel()?.title,
|
||||||
|
musicPlayerController.getMusicModel()?.subtitle,
|
||||||
|
);
|
||||||
await LoveSongsBox().add(musicPlayerController.getMusicModel()!.copyWith());
|
await LoveSongsBox().add(musicPlayerController.getMusicModel()!.copyWith());
|
||||||
BaseEasyLoading.toast('Collected');
|
BaseEasyLoading.toast('Collected');
|
||||||
}
|
}
|
||||||
@ -103,6 +120,7 @@ class PlayPageController extends GetxController {
|
|||||||
update([loveStateId]);
|
update([loveStateId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 下载
|
||||||
void onTapDownload() {
|
void onTapDownload() {
|
||||||
if (OfflineBox().checkDownloaded(musicPlayerController.getMusicModel()?.videoId)) {
|
if (OfflineBox().checkDownloaded(musicPlayerController.getMusicModel()?.videoId)) {
|
||||||
Get.dialog(
|
Get.dialog(
|
||||||
@ -141,4 +159,24 @@ class PlayPageController extends GetxController {
|
|||||||
musicPlayerController.currentIndex.value--;
|
musicPlayerController.currentIndex.value--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 点击上一首
|
||||||
|
void onTapPreviousTrack() {
|
||||||
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
|
AdScenes.playCut.name,
|
||||||
|
onTap: () {
|
||||||
|
musicPlayerController.previousTrack();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 点击下一首
|
||||||
|
void onTapNextTrack() {
|
||||||
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
|
AdScenes.playCut.name,
|
||||||
|
onTap: () {
|
||||||
|
musicPlayerController.nextTrack();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -355,7 +355,7 @@ class PlayPageView extends StatelessWidget {
|
|||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: musicPlayerController.previousTrack,
|
onTap: controller.onTapPreviousTrack,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(10).w,
|
padding: const EdgeInsets.all(10).w,
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
@ -411,7 +411,7 @@ class PlayPageView extends StatelessWidget {
|
|||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: musicPlayerController.nextTrack,
|
onTap: controller.onTapNextTrack,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(10).w,
|
padding: const EdgeInsets.all(10).w,
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import 'package:tone_snap/components/dialog/add_playlist_dialog.dart';
|
|||||||
import 'package:tone_snap/components/view_state_widget.dart';
|
import 'package:tone_snap/components/view_state_widget.dart';
|
||||||
import 'package:tone_snap/data/models/playlist_model.dart';
|
import 'package:tone_snap/data/models/playlist_model.dart';
|
||||||
import 'package:tone_snap/data/storage/playlists_box.dart';
|
import 'package:tone_snap/data/storage/playlists_box.dart';
|
||||||
|
import 'package:tone_snap/firebase/firebase_analytics_manager.dart';
|
||||||
|
|
||||||
class PlaylistsController extends GetxController {
|
class PlaylistsController extends GetxController {
|
||||||
static PlaylistsController get to => Get.find<PlaylistsController>();
|
static PlaylistsController get to => Get.find<PlaylistsController>();
|
||||||
@ -24,7 +25,7 @@ class PlaylistsController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void getList() {
|
void getList() {
|
||||||
playLists.value = PlaylistsBox().getReversedList();
|
playLists.value = PlaylistsBox().getList();
|
||||||
viewState.value = playLists.isNotEmpty ? ViewState.normal : ViewState.empty;
|
viewState.value = playLists.isNotEmpty ? ViewState.normal : ViewState.empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,6 +36,7 @@ class PlaylistsController extends GetxController {
|
|||||||
onTap: (value) async {
|
onTap: (value) async {
|
||||||
await PlaylistsBox().add(value);
|
await PlaylistsBox().add(value);
|
||||||
getList();
|
getList();
|
||||||
|
FirebaseAnalyticsManager.logCreateList();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.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/routes/app_routes.dart';
|
import 'package:tone_snap/routes/app_routes.dart';
|
||||||
|
|
||||||
class SearchMusicController extends GetxController {
|
class SearchMusicController extends GetxController {
|
||||||
@ -27,6 +28,7 @@ class SearchMusicController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void openSearch() {
|
void openSearch() {
|
||||||
|
FirebaseAnalyticsManager.logSearchFromAction('来自搜索页面');
|
||||||
Get.toNamed(AppRoutes.searchResult);
|
Get.toNamed(AppRoutes.searchResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
import 'package:tone_snap/components/view_state_widget.dart';
|
import 'package:tone_snap/components/view_state_widget.dart';
|
||||||
import 'package:tone_snap/data/api/music_api.dart';
|
import 'package:tone_snap/data/api/music_api.dart';
|
||||||
|
import 'package:tone_snap/data/enum/ad_scenes.dart';
|
||||||
import 'package:tone_snap/data/enum/music_type.dart';
|
import 'package:tone_snap/data/enum/music_type.dart';
|
||||||
import 'package:tone_snap/data/models/music_model.dart';
|
import 'package:tone_snap/data/models/music_model.dart';
|
||||||
import 'package:tone_snap/data/models/search_result_model.dart';
|
import 'package:tone_snap/data/models/search_result_model.dart';
|
||||||
import 'package:tone_snap/data/models/search_result_tabbar_model.dart';
|
import 'package:tone_snap/data/models/search_result_tabbar_model.dart';
|
||||||
import 'package:tone_snap/data/models/search_suggestions_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/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/modules/sideb/search_music/search_music_controller.dart';
|
import 'package:tone_snap/modules/sideb/search_music/search_music_controller.dart';
|
||||||
import 'package:tone_snap/modules/sideb/search_result_child/search_result_child_controller.dart';
|
import 'package:tone_snap/modules/sideb/search_result_child/search_result_child_controller.dart';
|
||||||
import 'package:tone_snap/modules/sideb/search_result_child/search_result_child_view.dart';
|
import 'package:tone_snap/modules/sideb/search_result_child/search_result_child_view.dart';
|
||||||
@ -83,6 +87,9 @@ class SearchResultController extends GetxController with GetTickerProviderStateM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
searchSuggestionsViewState.value = ViewState.normal;
|
searchSuggestionsViewState.value = ViewState.normal;
|
||||||
|
if (searchSuggestionsList.isNotEmpty) {
|
||||||
|
FirebaseAnalyticsManager.logSearchSugShow();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanTextEditingController() {
|
void cleanTextEditingController() {
|
||||||
@ -114,6 +121,8 @@ class SearchResultController extends GetxController with GetTickerProviderStateM
|
|||||||
if (ObjUtil.isEmpty(textEditingController.text)) {
|
if (ObjUtil.isEmpty(textEditingController.text)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
FirebaseAnalyticsManager.logSearchSugClick(value);
|
||||||
|
await _cleanTab();
|
||||||
if (isSearchSuggestionsItem) {
|
if (isSearchSuggestionsItem) {
|
||||||
textEditingController.text = value;
|
textEditingController.text = value;
|
||||||
}
|
}
|
||||||
@ -121,11 +130,19 @@ class SearchResultController extends GetxController with GetTickerProviderStateM
|
|||||||
if (Get.isRegistered<SearchMusicController>()) {
|
if (Get.isRegistered<SearchMusicController>()) {
|
||||||
SearchMusicController.to.getList();
|
SearchMusicController.to.getList();
|
||||||
}
|
}
|
||||||
await _cleanTab();
|
|
||||||
searchResultViewState.value = ViewState.loading;
|
searchResultViewState.value = ViewState.loading;
|
||||||
await _searchPreviewResult(value);
|
await _searchPreviewResult(value);
|
||||||
searchResultViewState.value = tabs.length > 1 ? ViewState.normal : ViewState.empty;
|
if (tabs.isNotEmpty) {
|
||||||
tabController.value = TabController(length: tabs.length, vsync: this);
|
FirebaseAnalyticsManager.logSearchResultPV();
|
||||||
|
FirebaseAnalyticsManager.logSearchResultsuccessAction();
|
||||||
|
}
|
||||||
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
|
AdScenes.search.name,
|
||||||
|
onTap: () {
|
||||||
|
searchResultViewState.value = tabs.isNotEmpty ? ViewState.normal : ViewState.empty;
|
||||||
|
tabController.value = TabController(length: tabs.length, vsync: this);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _searchPreviewResult(String keyword) async {
|
Future<void> _searchPreviewResult(String keyword) async {
|
||||||
@ -133,7 +150,13 @@ class SearchResultController extends GetxController with GetTickerProviderStateM
|
|||||||
'prettyPrint': false,
|
'prettyPrint': false,
|
||||||
'query': keyword
|
'query': keyword
|
||||||
};
|
};
|
||||||
SearchResultModel? searchResultModel = await MusicApi.search<SearchResultModel>(queryParameters: queryParameters, formJson: SearchResultModel.fromMap);
|
SearchResultModel? searchResultModel = await MusicApi.search<SearchResultModel>(
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
formJson: SearchResultModel.fromMap,
|
||||||
|
fail: (BaseError baseError) {
|
||||||
|
FirebaseAnalyticsManager.logSearchResultfailAction('${baseError.code},${baseError.message}');
|
||||||
|
},
|
||||||
|
);
|
||||||
if (searchResultModel != null) {
|
if (searchResultModel != null) {
|
||||||
var tabs = searchResultModel.contents?.tabbedSearchResultsRenderer?.tabs;
|
var tabs = searchResultModel.contents?.tabbedSearchResultsRenderer?.tabs;
|
||||||
if (tabs != null && tabs.isNotEmpty) {
|
if (tabs != null && tabs.isNotEmpty) {
|
||||||
@ -266,6 +289,9 @@ class SearchResultController extends GetxController with GetTickerProviderStateM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.tabs.isEmpty) {
|
||||||
|
FirebaseAnalyticsManager.logSearchResultfailAction('无数据');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import 'package:easy_refresh/easy_refresh.dart';
|
import 'package:easy_refresh/easy_refresh.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
import 'package:tone_snap/components/view_state_widget.dart';
|
import 'package:tone_snap/components/view_state_widget.dart';
|
||||||
import 'package:tone_snap/data/api/music_api.dart';
|
import 'package:tone_snap/data/api/music_api.dart';
|
||||||
|
import 'package:tone_snap/data/enum/ad_scenes.dart';
|
||||||
import 'package:tone_snap/data/enum/music_type.dart';
|
import 'package:tone_snap/data/enum/music_type.dart';
|
||||||
import 'package:tone_snap/data/models/music_model.dart';
|
import 'package:tone_snap/data/models/music_model.dart';
|
||||||
import 'package:tone_snap/data/models/search_result_model.dart';
|
import 'package:tone_snap/data/models/search_result_model.dart';
|
||||||
@ -183,10 +185,15 @@ class SearchResultChildController extends GetxController {
|
|||||||
|
|
||||||
void onTapItem(MusicModel musicModel) {
|
void onTapItem(MusicModel musicModel) {
|
||||||
if (musicModel.musicType == MusicType.musicVideoTypeAtv.name) {
|
if (musicModel.musicType == MusicType.musicVideoTypeAtv.name) {
|
||||||
Get.toNamed(AppRoutes.playPage, arguments: {
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
'videoId': musicModel.videoId,
|
AdScenes.play.name,
|
||||||
'playlistId': musicModel.playlistId,
|
onTap: () {
|
||||||
});
|
Get.toNamed(AppRoutes.playPage, arguments: {
|
||||||
|
'videoId': musicModel.videoId,
|
||||||
|
'playlistId': musicModel.playlistId,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
} else if (musicModel.musicType == MusicType.musicPageTypeAlbum.name
|
} else if (musicModel.musicType == MusicType.musicPageTypeAlbum.name
|
||||||
|| musicModel.musicType == MusicType.musicPageTypePlaylist.name) {
|
|| musicModel.musicType == MusicType.musicPageTypePlaylist.name) {
|
||||||
Get.toNamed(AppRoutes.albumSongList, arguments: {
|
Get.toNamed(AppRoutes.albumSongList, arguments: {
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:tone_snap/ads/interstitial_ad_manager.dart';
|
||||||
|
import 'package:tone_snap/data/enum/ad_scenes.dart';
|
||||||
import 'package:tone_snap/data/enum/music_type.dart';
|
import 'package:tone_snap/data/enum/music_type.dart';
|
||||||
import 'package:tone_snap/data/models/music_model.dart';
|
import 'package:tone_snap/data/models/music_model.dart';
|
||||||
import 'package:tone_snap/routes/app_routes.dart';
|
import 'package:tone_snap/routes/app_routes.dart';
|
||||||
@ -6,10 +8,15 @@ import 'package:tone_snap/routes/app_routes.dart';
|
|||||||
class SearchResultChildOptimumController extends GetxController {
|
class SearchResultChildOptimumController extends GetxController {
|
||||||
void onTapItem(MusicModel musicModel) {
|
void onTapItem(MusicModel musicModel) {
|
||||||
if (musicModel.musicType == MusicType.musicVideoTypeAtv.name) {
|
if (musicModel.musicType == MusicType.musicVideoTypeAtv.name) {
|
||||||
Get.toNamed(AppRoutes.playPage, arguments: {
|
InterstitialAdManager().showAdIfAvailable(
|
||||||
'videoId': musicModel.videoId,
|
AdScenes.play.name,
|
||||||
'playlistId': musicModel.playlistId,
|
onTap: () {
|
||||||
});
|
Get.toNamed(AppRoutes.playPage, arguments: {
|
||||||
|
'videoId': musicModel.videoId,
|
||||||
|
'playlistId': musicModel.playlistId,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
} else if (musicModel.musicType == MusicType.musicPageTypeAlbum.name
|
} else if (musicModel.musicType == MusicType.musicPageTypeAlbum.name
|
||||||
|| musicModel.musicType == MusicType.musicPageTypePlaylist.name) {
|
|| musicModel.musicType == MusicType.musicPageTypePlaylist.name) {
|
||||||
Get.toNamed(AppRoutes.albumSongList, arguments: {
|
Get.toNamed(AppRoutes.albumSongList, arguments: {
|
||||||
|
|||||||
@ -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.4+14
|
version: 1.0.5+15
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.4.1 <4.0.0'
|
sdk: '>=3.4.1 <4.0.0'
|
||||||
@ -100,7 +100,7 @@ dependencies:
|
|||||||
google_mobile_ads: ^5.1.0
|
google_mobile_ads: ^5.1.0
|
||||||
|
|
||||||
# Firebase
|
# Firebase
|
||||||
firebase_core: ^3.2.0
|
firebase_core: ^3.3.0
|
||||||
firebase_analytics: ^11.2.0
|
firebase_analytics: ^11.2.0
|
||||||
firebase_crashlytics: ^4.0.3
|
firebase_crashlytics: ^4.0.3
|
||||||
firebase_remote_config: ^5.0.3
|
firebase_remote_config: ^5.0.3
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user