diff --git a/android/app/src/main/kotlin/com/example/PiliPlus/MainActivity.kt b/android/app/src/main/kotlin/com/example/PiliPlus/MainActivity.kt index 7d5fc53f1..3713d1515 100644 --- a/android/app/src/main/kotlin/com/example/PiliPlus/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/PiliPlus/MainActivity.kt @@ -1,17 +1,19 @@ package com.example.piliplus -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugin.common.MethodChannel -import com.ryanheise.audioservice.AudioServiceActivity +import android.app.SearchManager import android.content.ComponentName import android.content.Intent +import android.content.pm.PackageManager import android.content.res.Configuration -import android.net.Uri import android.os.Build import android.os.Bundle +import android.provider.MediaStore import android.provider.Settings import android.view.WindowManager.LayoutParams +import androidx.core.net.toUri +import com.ryanheise.audioservice.AudioServiceActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.MethodChannel import kotlin.system.exitProcess class MainActivity : AudioServiceActivity() { @@ -22,59 +24,85 @@ class MainActivity : AudioServiceActivity() { methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "PiliPlus") methodChannel.setMethodCallHandler { call, result -> - if (call.method == "back") { - back() - } else if (call.method == "biliSendCommAntifraud") { - try { - val action = call.argument("action") ?: 0 - val oid = call.argument("oid") ?: 0L - val type = call.argument("type") ?: 0 - val rpid = call.argument("rpid") ?: 0L - val root = call.argument("root") ?: 0L - val parent = call.argument("parent") ?: 0L - val ctime = call.argument("ctime") ?: 0L - val commentText = call.argument("comment_text") ?: "" - val pictures = call.argument("pictures") - val sourceId = call.argument("source_id") ?: "" - val uid = call.argument("uid") ?: 0L - val cookies = call.argument>("cookies") ?: emptyList() - - val intent = Intent().apply { - component = ComponentName("icu.freedomIntrovert.biliSendCommAntifraud", "icu.freedomIntrovert.biliSendCommAntifraud.ByXposedLaunchedActivity") - putExtra("action", action) - putExtra("oid", oid.toLong()) - putExtra("type", type) - putExtra("rpid", rpid.toLong()) - putExtra("root", root.toLong()) - putExtra("parent", parent.toLong()) - putExtra("ctime", ctime.toLong()) - putExtra("comment_text", commentText) - if(pictures != null) - putExtra("pictures", pictures) - putExtra("source_id", sourceId) - putExtra("uid", uid.toLong()) - putStringArrayListExtra("cookies", ArrayList(cookies)) - } - startActivity(intent) - } catch (e: Exception) {} - } else if (call.method == "linkVerifySettings") { - try { - val intent = Intent(android.provider.Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS, - Uri.parse("package:" + context.packageName)) - context.startActivity(intent) - } catch (t: Throwable) { + when (call.method) { + "back" -> back(); + "biliSendCommAntifraud" -> { try { - val intent = Intent("android.intent.action.MAIN", Uri.parse("package:" + context.packageName)) - intent.setClassName("com.android.settings", "com.android.settings.applications.InstalledAppOpenByDefaultActivity") + val action = call.argument("action") ?: 0 + val oid = call.argument("oid") ?: 0L + val type = call.argument("type") ?: 0 + val rpid = call.argument("rpid") ?: 0L + val root = call.argument("root") ?: 0L + val parent = call.argument("parent") ?: 0L + val ctime = call.argument("ctime") ?: 0L + val commentText = call.argument("comment_text") ?: "" + val pictures = call.argument("pictures") + val sourceId = call.argument("source_id") ?: "" + val uid = call.argument("uid") ?: 0L + val cookies = call.argument>("cookies") ?: emptyList() + + val intent = Intent().apply { + component = ComponentName("icu.freedomIntrovert.biliSendCommAntifraud", "icu.freedomIntrovert.biliSendCommAntifraud.ByXposedLaunchedActivity") + putExtra("action", action) + putExtra("oid", oid.toLong()) + putExtra("type", type) + putExtra("rpid", rpid.toLong()) + putExtra("root", root.toLong()) + putExtra("parent", parent.toLong()) + putExtra("ctime", ctime.toLong()) + putExtra("comment_text", commentText) + if(pictures != null) + putExtra("pictures", pictures) + putExtra("source_id", sourceId) + putExtra("uid", uid.toLong()) + putStringArrayListExtra("cookies", ArrayList(cookies)) + } + startActivity(intent) + } catch (_: Exception) {} + } + "linkVerifySettings" -> { + val uri = ("package:" + context.packageName).toUri() + try { + val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + Intent(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS, uri) + } else { + Intent("android.intent.action.MAIN", uri).setClassName("com.android.settings", + "com.android.settings.applications.InstalledAppOpenByDefaultActivity") + } context.startActivity(intent) - } catch (t2: Throwable) { - val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, - Uri.parse("package:" + context.packageName)) + } catch (_: Throwable) { + val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, uri) context.startActivity(intent) } } - } else { - result.notImplemented() + "music" -> { + val title = call.argument("title") + val intent = Intent(MediaStore.INTENT_ACTION_MEDIA_SEARCH).apply { + putExtra(SearchManager.QUERY, title) + putExtra(MediaStore.EXTRA_MEDIA_TITLE, title) + call.argument("artist")?.let { putExtra(MediaStore.EXTRA_MEDIA_ARTIST, it) } + call.argument("album")?.let { putExtra(MediaStore.EXTRA_MEDIA_ALBUM, it) } + + addCategory(Intent.CATEGORY_DEFAULT) + } + try { + if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) { + startActivity(intent) + result.success(true) + return@setMethodCallHandler + } + } catch (_: Throwable) {} + try { + intent.action = MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH + if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) { + startActivity(intent) + result.success(true) + return@setMethodCallHandler + } + } catch (_: Throwable) {} + result.success(false) + } + else -> result.notImplemented() } } } @@ -109,7 +137,7 @@ class MainActivity : AudioServiceActivity() { override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration?) { super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig) MethodChannel( - flutterEngine!!.getDartExecutor()!!.getBinaryMessenger(), + flutterEngine!!.dartExecutor.binaryMessenger, "floating" ).invokeMethod("onPipChanged", isInPictureInPictureMode) } diff --git a/lib/pages/music/view.dart b/lib/pages/music/view.dart index 8c102f36e..5a872c911 100644 --- a/lib/pages/music/view.dart +++ b/lib/pages/music/view.dart @@ -1,3 +1,4 @@ +import 'dart:io'; import 'dart:math'; import 'package:PiliPlus/common/widgets/badge.dart'; @@ -448,10 +449,8 @@ class _MusicDetailPageState extends CommonDynPageState { crossAxisAlignment: CrossAxisAlignment.start, children: [ GestureDetector( - // TODO: android intent ACTION_MEDIA_SEARCH - onTap: () => Utils.copyText( - item.musicTitle!, - ), + onTap: () => _searchMusic(item), + onLongPress: () => Utils.copyText(item.musicTitle!), behavior: HitTestBehavior.opaque, child: MarqueeText( item.musicTitle!, @@ -493,13 +492,18 @@ class _MusicDetailPageState extends CommonDynPageState { cid: item.mvCid!, aid: item.mvAid, ), - child: ColoredBox( - color: theme.colorScheme.secondaryContainer - .withValues(alpha: 0.5), + child: DecoratedBox( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all( + Radius.circular(4), + ), + color: theme.colorScheme.secondaryContainer + .withValues(alpha: 0.5), + ), child: Padding( padding: const EdgeInsets.symmetric( - vertical: 2, - horizontal: 3, + vertical: 3, + horizontal: 4, ), child: Row( mainAxisSize: MainAxisSize.min, @@ -676,4 +680,18 @@ class _MusicDetailPageState extends CommonDynPageState { ), ); } + + Future _searchMusic(MusicDetail item) async { + final res = + Platform.isAndroid && + (await Utils.channel.invokeMethod('music', { + 'title': item.musicTitle, + 'artist': item.originArtist ?? item.originArtistList, + 'album': item.album, + }) ?? + false); + if (!res) { + Utils.copyText(item.musicTitle!); + } + } } diff --git a/lib/utils/login_utils.dart b/lib/utils/login_utils.dart index a57d06344..32117d8ff 100644 --- a/lib/utils/login_utils.dart +++ b/lib/utils/login_utils.dart @@ -1,6 +1,5 @@ import 'dart:async' show FutureOr; import 'dart:io' show Platform; -import 'dart:math'; import 'package:PiliPlus/grpc/grpc_req.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -21,13 +20,12 @@ import 'package:PiliPlus/utils/accounts/account.dart'; import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage_pref.dart'; +import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart' as web; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; abstract class LoginUtils { - static final random = Random(); - static FutureOr setWebCookie([Account? account]) { if (Platform.isWindows) { return null; @@ -163,7 +161,7 @@ abstract class LoginUtils { static String generateBuvid() { var md5Str = Iterable.generate( 32, - (_) => random.nextInt(16).toRadixString(16), + (_) => Utils.random.nextInt(16).toRadixString(16), ).join().toUpperCase(); return 'XY${md5Str[2]}${md5Str[12]}${md5Str[22]}$md5Str'; } @@ -188,11 +186,11 @@ abstract class LoginUtils { final String randomHex32 = List.generate( 32, - (index) => random.nextInt(16).toRadixString(16), + (index) => Utils.random.nextInt(16).toRadixString(16), ).join(); final String randomHex16 = List.generate( 16, - (index) => random.nextInt(16).toRadixString(16), + (index) => Utils.random.nextInt(16).toRadixString(16), ).join(); final String deviceID = randomHex32 + yyyyMMddHHmmss + randomHex16;