diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 6c9f35c..e7df0ed 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ - - + + android:name="io.flutter.embedding.android.NormalTheme" + android:resource="@style/NormalTheme"/> @@ -35,7 +34,7 @@ This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> + android:value="2"/> - - + + diff --git a/android/app/src/main/kotlin/com/stormg/lumadrama/MainActivity.kt b/android/app/src/main/kotlin/com/stormg/lumadrama/MainActivity.kt index 3fc470e..8f25c38 100644 --- a/android/app/src/main/kotlin/com/stormg/lumadrama/MainActivity.kt +++ b/android/app/src/main/kotlin/com/stormg/lumadrama/MainActivity.kt @@ -5,22 +5,44 @@ package com.stormg.lumadrama import android.content.Intent import android.app.PictureInPictureParams import android.content.res.Configuration +import android.graphics.Bitmap +import android.media.MediaMetadataRetriever +import android.net.Uri import android.os.Build +import android.os.Bundle +import android.os.Handler +import android.os.Looper import android.util.Rational import android.content.pm.PackageManager +import android.view.WindowManager import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel +import java.io.ByteArrayOutputStream +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import java.util.concurrent.atomic.AtomicBoolean class MainActivity : FlutterActivity() { private val shareRequestCode = 9041 + private val thumbnailExecutor: ExecutorService = Executors.newSingleThreadExecutor() + private val thumbnailHandler = Handler(Looper.getMainLooper()) private var pendingShare: MethodChannel.Result? = null private var pipChannel: MethodChannel? = null private var keyboardChannel: MethodChannel? = null + private var thumbnailChannel: MethodChannel? = null private var imeInset = 0 + override fun onCreate(savedInstanceState: Bundle?) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + splashScreen.setOnExitAnimationListener { screen -> screen.remove() } + } + super.onCreate(savedInstanceState) + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + } + override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) pipChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "com.stormg.lumadrama/pip") @@ -79,6 +101,47 @@ class MainActivity : FlutterActivity() { emitImeInset(inset) result.success(inset) } + thumbnailChannel = MethodChannel( + flutterEngine.dartExecutor.binaryMessenger, + "com.stormg.lumadrama/thumbnail" + ) + thumbnailChannel?.setMethodCallHandler { call, result -> + if (call.method != "frame") { + result.notImplemented() + return@setMethodCallHandler + } + val timeMs = (call.argument("timeMs"))?.toLong() + if (timeMs == null) { + result.success(null) + return@setMethodCallHandler + } + val localPath = call.argument("localPath").orEmpty() + val remoteUrl = call.argument("url").orEmpty() + val rawHeaders = call.argument>("headers") + val headers = rawHeaders?.entries + ?.associate { it.key.toString() to it.value.toString() } + .orEmpty() + val responded = AtomicBoolean(false) + val task = thumbnailExecutor.submit { + val bytes = renderThumbnail( + timeMs = timeMs, + localPath = localPath, + remoteUrl = remoteUrl, + headers = headers + ) + thumbnailHandler.post { + if (responded.compareAndSet(false, true)) { + result.success(bytes) + } + } + } + thumbnailHandler.postDelayed({ + if (responded.compareAndSet(false, true)) { + task.cancel(true) + result.success(null) + } + }, thumbnailTimeoutMs) + } val decorView = window.decorView ViewCompat.setOnApplyWindowInsetsListener(decorView) { view, insets -> emitImeInset(insets.getInsets(WindowInsetsCompat.Type.ime()).bottom) @@ -99,6 +162,59 @@ class MainActivity : FlutterActivity() { keyboardChannel?.invokeMethod("insetsChanged", value) } + private fun renderThumbnail( + timeMs: Long, + localPath: String, + remoteUrl: String, + headers: Map + ): ByteArray? { + val retriever = MediaMetadataRetriever() + var frame: Bitmap? = null + var scaled: Bitmap? = null + return try { + when { + localPath.isNotEmpty() -> retriever.setDataSource(normalizeLocalPath(localPath)) + remoteUrl.isNotEmpty() -> retriever.setDataSource(remoteUrl, headers) + else -> return null + } + frame = retriever.getFrameAtTime( + timeMs * 1000, + MediaMetadataRetriever.OPTION_CLOSEST_SYNC + ) + val source = frame ?: return null + scaled = if (source.width > thumbnailMaxWidth) { + val targetHeight = (source.height * thumbnailMaxWidth / source.width) + .coerceAtLeast(1) + Bitmap.createScaledBitmap( + source, + thumbnailMaxWidth, + targetHeight, + true + ) + } else { + source + } + val outputBitmap = scaled ?: source + val output = ByteArrayOutputStream() + val compressed = outputBitmap.compress( + Bitmap.CompressFormat.JPEG, + thumbnailJpegQuality, + output + ) + if (!compressed) return null + output.toByteArray() + } catch (_: Exception) { + null + } finally { + if (scaled != null && scaled !== frame) scaled.recycle() + frame?.recycle() + retriever.release() + } + } + + private fun normalizeLocalPath(path: String): String = + if (path.startsWith("file:")) Uri.parse(path).path ?: path else path + override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) { super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig) pipChannel?.invokeMethod("onPipChanged", isInPictureInPictureMode) @@ -117,6 +233,16 @@ class MainActivity : FlutterActivity() { ViewCompat.setOnApplyWindowInsetsListener(window.decorView, null) keyboardChannel?.setMethodCallHandler(null) keyboardChannel = null + thumbnailChannel?.setMethodCallHandler(null) + thumbnailChannel = null + thumbnailHandler.removeCallbacksAndMessages(null) + thumbnailExecutor.shutdownNow() super.onDestroy() } + + companion object { + private const val thumbnailMaxWidth = 240 + private const val thumbnailJpegQuality = 70 + private const val thumbnailTimeoutMs = 1500L + } } diff --git a/android/app/src/main/res/drawable-hdpi/android12splash.png b/android/app/src/main/res/drawable-hdpi/android12splash.png deleted file mode 100644 index b83ff04..0000000 Binary files a/android/app/src/main/res/drawable-hdpi/android12splash.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png index 958fa59..f74caef 100644 Binary files a/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png and b/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/drawable-hdpi/splash.png b/android/app/src/main/res/drawable-hdpi/splash.png deleted file mode 100644 index f7ad471..0000000 Binary files a/android/app/src/main/res/drawable-hdpi/splash.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-mdpi/android12splash.png b/android/app/src/main/res/drawable-mdpi/android12splash.png deleted file mode 100644 index fdcfb53..0000000 Binary files a/android/app/src/main/res/drawable-mdpi/android12splash.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png index e67ebad..e6ba224 100644 Binary files a/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png and b/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/drawable-mdpi/splash.png b/android/app/src/main/res/drawable-mdpi/splash.png deleted file mode 100644 index b2ebfd8..0000000 Binary files a/android/app/src/main/res/drawable-mdpi/splash.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-night-hdpi/android12splash.png b/android/app/src/main/res/drawable-night-hdpi/android12splash.png deleted file mode 100644 index b83ff04..0000000 Binary files a/android/app/src/main/res/drawable-night-hdpi/android12splash.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-night-mdpi/android12splash.png b/android/app/src/main/res/drawable-night-mdpi/android12splash.png deleted file mode 100644 index fdcfb53..0000000 Binary files a/android/app/src/main/res/drawable-night-mdpi/android12splash.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-night-v21/launch_background.xml b/android/app/src/main/res/drawable-night-v21/launch_background.xml index d933a92..35eaddd 100644 --- a/android/app/src/main/res/drawable-night-v21/launch_background.xml +++ b/android/app/src/main/res/drawable-night-v21/launch_background.xml @@ -1,4 +1,10 @@ + + + + diff --git a/android/app/src/main/res/drawable-night-xhdpi/android12splash.png b/android/app/src/main/res/drawable-night-xhdpi/android12splash.png deleted file mode 100644 index 902356d..0000000 Binary files a/android/app/src/main/res/drawable-night-xhdpi/android12splash.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png b/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png deleted file mode 100644 index b111cdb..0000000 Binary files a/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png b/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png deleted file mode 100644 index 54c03f6..0000000 Binary files a/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-night/launch_background.xml b/android/app/src/main/res/drawable-night/launch_background.xml index d933a92..35eaddd 100644 --- a/android/app/src/main/res/drawable-night/launch_background.xml +++ b/android/app/src/main/res/drawable-night/launch_background.xml @@ -1,4 +1,10 @@ + + + + diff --git a/android/app/src/main/res/drawable-nodpi/splash_brand.png b/android/app/src/main/res/drawable-nodpi/splash_brand.png new file mode 100644 index 0000000..2ca5a39 Binary files /dev/null and b/android/app/src/main/res/drawable-nodpi/splash_brand.png differ diff --git a/android/app/src/main/res/drawable-nodpi/splash_screen.png b/android/app/src/main/res/drawable-nodpi/splash_screen.png new file mode 100644 index 0000000..96e1134 Binary files /dev/null and b/android/app/src/main/res/drawable-nodpi/splash_screen.png differ diff --git a/android/app/src/main/res/drawable-v21/background.png b/android/app/src/main/res/drawable-v21/background.png index 3f0a992..e815fd6 100644 Binary files a/android/app/src/main/res/drawable-v21/background.png and b/android/app/src/main/res/drawable-v21/background.png differ diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml index 3cc4948..35eaddd 100644 --- a/android/app/src/main/res/drawable-v21/launch_background.xml +++ b/android/app/src/main/res/drawable-v21/launch_background.xml @@ -1,9 +1,10 @@ + + - - - - + diff --git a/android/app/src/main/res/drawable-v31/launch_background.xml b/android/app/src/main/res/drawable-v31/launch_background.xml index 515a7fb..35eaddd 100644 --- a/android/app/src/main/res/drawable-v31/launch_background.xml +++ b/android/app/src/main/res/drawable-v31/launch_background.xml @@ -1,6 +1,10 @@ - + + + diff --git a/android/app/src/main/res/drawable-xhdpi/android12splash.png b/android/app/src/main/res/drawable-xhdpi/android12splash.png deleted file mode 100644 index 902356d..0000000 Binary files a/android/app/src/main/res/drawable-xhdpi/android12splash.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png index e36966c..41cd6fd 100644 Binary files a/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png and b/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/splash.png b/android/app/src/main/res/drawable-xhdpi/splash.png deleted file mode 100644 index b01e86c..0000000 Binary files a/android/app/src/main/res/drawable-xhdpi/splash.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-xxhdpi/android12splash.png b/android/app/src/main/res/drawable-xxhdpi/android12splash.png deleted file mode 100644 index b111cdb..0000000 Binary files a/android/app/src/main/res/drawable-xxhdpi/android12splash.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png index 5b61cb8..30e3303 100644 Binary files a/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png and b/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/splash.png b/android/app/src/main/res/drawable-xxhdpi/splash.png deleted file mode 100644 index 5143af8..0000000 Binary files a/android/app/src/main/res/drawable-xxhdpi/splash.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/android12splash.png b/android/app/src/main/res/drawable-xxxhdpi/android12splash.png deleted file mode 100644 index 54c03f6..0000000 Binary files a/android/app/src/main/res/drawable-xxxhdpi/android12splash.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png index 7943abd..bf427ce 100644 Binary files a/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png and b/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/splash.png b/android/app/src/main/res/drawable-xxxhdpi/splash.png deleted file mode 100644 index d255ff4..0000000 Binary files a/android/app/src/main/res/drawable-xxxhdpi/splash.png and /dev/null differ diff --git a/android/app/src/main/res/drawable/background.png b/android/app/src/main/res/drawable/background.png index 3f0a992..e815fd6 100644 Binary files a/android/app/src/main/res/drawable/background.png and b/android/app/src/main/res/drawable/background.png differ diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml index 3cc4948..35eaddd 100644 --- a/android/app/src/main/res/drawable/launch_background.xml +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -1,9 +1,10 @@ + + - - - - + diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index 18d2d58..c79c58a 100644 --- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,5 +1,9 @@ - - + + + + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index 045ed69..81ea1a3 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 36c8583..bb256a1 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index dacd5ff..e89d692 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 66a7a49..ded1644 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index ad7574a..f8dd70e 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/values-night-v31/styles.xml b/android/app/src/main/res/values-night-v31/styles.xml index e4f4e80..13a688d 100644 --- a/android/app/src/main/res/values-night-v31/styles.xml +++ b/android/app/src/main/res/values-night-v31/styles.xml @@ -1,11 +1,15 @@ -