Skip to content

Commit

Permalink
[feature|build|fix|chore] Switch to Mpv (#42); fix enclosures won't s…
Browse files Browse the repository at this point in the history
…how issue; update dependencies

* [feature|build] Remove ExoPlayer, use MPV to play videos; update dependencies

* [feature|fix] Support player gestures; fix enclosures won't show issue

* [feature|chore|build] Improve player control UI; remove unused resources; upgrade AGP
  • Loading branch information
SkyD666 authored May 14, 2024
1 parent 7149709 commit 2543a39
Show file tree
Hide file tree
Showing 81 changed files with 2,263 additions and 6,975 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pre_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,4 @@ jobs:
Commit details [here](${{ github.event.head_commit.url }})
run: |
ESCAPED=`python3 -c 'import json,os,urllib.parse; print(urllib.parse.quote(json.dumps(os.environ["COMMIT_MESSAGE"])))'`
curl -v "https://api.telegram.org/bot${BOT_TOKEN}/sendMediaGroup?chat_id=${CHANNEL_ID}&media=%5B%7B%22type%22%3A%22document%22%2C%20%22media%22%3A%22attach%3A%2F%2Fpre_release_arm64_v8%22%7D%2C%7B%22type%22%3A%22document%22%2C%20%22media%22%3A%22attach%3A%2F%2Fpre_release_arm_v7%22%2C%22parse_mode%22%3A%22MarkdownV2%22%2C%22caption%22%3A${ESCAPED}%7D%5D" -F pre_release_arm64_v8="@$PRE_RELEASE_ARM64_V8" -F pre_release_arm_v7="@$PRE_RELEASE_ARM_V7"
curl -v "https://api.telegram.org/bot${BOT_TOKEN}/sendMediaGroup?chat_id=${CHANNEL_ID}&media=%5B%7B%22type%22%3A%22document%22%2C%20%22media%22%3A%22attach%3A%2F%2Fpre_release_arm64_v8%22%2C%22parse_mode%22%3A%22MarkdownV2%22%2C%22caption%22%3A${ESCAPED}%7D%5D" -F pre_release_arm64_v8="@$PRE_RELEASE_ARM64_V8"
47 changes: 32 additions & 15 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ android {
minSdk = 24
targetSdk = 34
versionCode = 16
versionName = "1.1-beta20"
versionName = "1.1-beta24"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

Expand Down Expand Up @@ -92,6 +92,12 @@ android {
)
}
}
androidResources {
ignoreAssetsPatterns += listOf(
"subfont.ttf", // mpv-android
"cacert.pem", // mpv-android
)
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
Expand All @@ -116,7 +122,17 @@ android {
"kotlin-tooling-metadata.json",
"okhttp3/internal/publicsuffix/NOTICE",
)
jniLibs.excludes += mutableSetOf(
"lib/*/libffmpegkit.so", // mpv-android
"lib/*/libffmpegkit_abidetect.so", // mpv-android
)
dex {
// Set to "true" because android:extractNativeLibs
// is set to "true" in AndroidManifest.xml
useLegacyPackaging = true
}
}
// ndkVersion = "26.3.11579264"
}

tasks.withType(KotlinCompile::class.java).configureEach {
Expand All @@ -139,51 +155,52 @@ tasks.withType(KotlinCompile::class.java).configureEach {

dependencies {

implementation("androidx.core:core-ktx:1.13.0")
implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha13")
implementation("androidx.navigation:navigation-fragment-ktx:2.7.7")
implementation("androidx.navigation:navigation-ui-ktx:2.7.7")
implementation("androidx.navigation:navigation-compose:2.7.7")
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.7.0")
implementation("androidx.compose.ui:ui:1.6.6")
implementation("androidx.compose.material:material:1.6.6")
implementation("androidx.compose.ui:ui:1.6.7")
implementation("androidx.compose.material:material:1.6.7")
implementation("androidx.compose.material3:material3:1.3.0-alpha05")
implementation("androidx.compose.material3:material3-window-size-class:1.2.1")
implementation("androidx.compose.material:material-icons-extended:1.6.6")
implementation("androidx.compose.material:material-icons-extended:1.6.7")
implementation("com.materialkolor:material-kolor:1.4.4")
implementation("androidx.room:room-runtime:2.6.1")
implementation("androidx.room:room-ktx:2.6.1")
implementation("androidx.room:room-paging:2.6.1")
ksp("androidx.room:room-compiler:2.6.1")
implementation("androidx.work:work-runtime-ktx:2.9.0")
implementation("androidx.datastore:datastore-preferences:1.1.0")
implementation("androidx.datastore:datastore-preferences:1.1.1")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.core:core-splashscreen:1.0.1")
implementation("androidx.media3:media3-exoplayer:1.3.1")
implementation("androidx.media3:media3-exoplayer-dash:1.3.1")
implementation("androidx.media3:media3-ui:1.3.1")
implementation("androidx.paging:paging-runtime-ktx:3.2.1")
implementation("androidx.paging:paging-compose:3.3.0-beta01")
implementation("androidx.preference:preference-ktx:1.2.1")
implementation("com.google.code.gson:gson:2.10.1")

implementation("com.google.android.material:material:1.11.0")
implementation("com.google.android.material:material:1.12.0")

implementation("com.google.dagger:hilt-android:2.51")
ksp("com.google.dagger:hilt-android-compiler:2.51")
implementation("com.google.dagger:hilt-android:2.51.1")
ksp("com.google.dagger:hilt-android-compiler:2.51.1")
implementation("androidx.hilt:hilt-navigation-compose:1.2.0")

implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.squareup.okhttp3:okhttp-coroutines-jvm:5.0.0-alpha.12")
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
implementation("com.squareup.retrofit2:retrofit:2.10.0")
implementation("com.squareup.retrofit2:retrofit:2.11.0")
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.7.3")

implementation("com.github.aniyomiorg:aniyomi-mpv-lib:1.15.n")
implementation("com.github.jmir1:ffmpeg-kit:1.14")

implementation("io.coil-kt:coil:2.6.0")
implementation("io.coil-kt:coil-compose:2.6.0")
implementation("io.coil-kt:coil-gif:2.5.0")
implementation("io.coil-kt:coil-gif:2.6.0")
implementation("com.rometools:rome:2.1.0")
implementation("net.dankito.readability4j:readability4j:1.0.8")

Expand Down
8 changes: 7 additions & 1 deletion app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,10 @@ public static final ** CREATOR;
-keep class com.skyd.anivu.ui.component.lazyverticalgrid.adapter.LazyGridAdapter$Proxy { *; }

# Retrofit
-keep, allowobfuscation, allowshrinking interface retrofit2.Call
-keep, allowobfuscation, allowshrinking interface retrofit2.Call

# FFmpeg
-dontwarn com.arthenica.smartexception.java.Exceptions

# MPV
-keep,allowoptimization class is.xyz.mpv.MPVLib { public protected *; }
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:enableOnBackInvokedCallback="true"
android:extractNativeLibs="true"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/com/skyd/anivu/base/BaseActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ abstract class BaseActivity<T : ViewBinding> : AppCompatActivity() {
binding.initView()
}

protected open fun T.initView() {}
protected open fun T.initView() = Unit

protected open fun beforeSetContentView() {}
protected open fun beforeSetContentView() = Unit

private fun initTheme() {
setTheme(ThemePreference.toResId(this))
Expand Down
37 changes: 37 additions & 0 deletions app/src/main/java/com/skyd/anivu/base/BaseComposeActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.skyd.anivu.base

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import com.skyd.anivu.model.preference.SettingsProvider
import com.skyd.anivu.model.preference.appearance.ThemePreference
import com.skyd.anivu.ui.local.LocalDarkMode
import com.skyd.anivu.ui.local.LocalWindowSizeClass
import com.skyd.anivu.ui.theme.AniVuTheme
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
open class BaseComposeActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)

initTheme()
}

fun setContentBase(content: @Composable () -> Unit) = setContent {
CompositionLocalProvider(
LocalWindowSizeClass provides calculateWindowSizeClass(this@BaseComposeActivity)
) {
SettingsProvider { AniVuTheme(darkTheme = LocalDarkMode.current, content) }
}
}

private fun initTheme() {
setTheme(ThemePreference.toResId(this))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ abstract class BaseDialogFragment<T : ViewBinding> : DialogFragment() {
binding.initView()
}

protected open fun T.initView() {}
protected open fun T.initView() = Unit

override fun onDestroyView() {
super.onDestroyView()
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/com/skyd/anivu/config/Const.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,12 @@ object Const {
val TORRENT_RESUME_DATA_DIR = File(appContext.filesDir.path, "TorrentResumeData").apply {
if (!exists()) mkdirs()
}

val MPV_CONFIG_DIR = File("${appContext.filesDir.path}/Mpv", "Config").apply {
if (!exists()) mkdirs()
}

val MPV_CACHE_DIR = File("${appContext.cacheDir.path}/Mpv", "Cache").apply {
if (!exists()) mkdirs()
}
}
12 changes: 7 additions & 5 deletions app/src/main/java/com/skyd/anivu/ext/IOExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ fun InputStream.saveTo(target: File): File {

fun File.md5(): String? {
var bi: BigInteger? = null
try {
runCatching {
val buffer = ByteArray(4096)
var len: Int
val md = MessageDigest.getInstance("MD5")
Expand All @@ -114,10 +114,12 @@ fun File.md5(): String? {
}
val b = md.digest()
bi = BigInteger(1, b)
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}.onFailure {
when (it) {
is NoSuchAlgorithmException -> it.printStackTrace()
is IOException -> it.printStackTrace()
else -> throw it
}
}
return bi?.toString(16)
}
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/skyd/anivu/ext/NumberExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ val Int.sp: Int
Resources.getSystem().displayMetrics
).toInt()

fun Float.toPercentage(): String = "%.2f%%".format(this * 100)
fun Float.toPercentage(format: String = "%.2f%%"): String = format.format(this * 100)

fun Float.toDegrees(): Float = (this * 180 / Math.PI).toFloat()
14 changes: 14 additions & 0 deletions app/src/main/java/com/skyd/anivu/ext/OffsetExt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.skyd.anivu.ext

import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.Saver
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.util.packFloats
import androidx.compose.ui.util.unpackFloat1
import androidx.compose.ui.util.unpackFloat2

fun snapshotStateOffsetSaver() = Saver<MutableState<Offset>, Long>(
save = { state -> packFloats(state.value.x, state.value.y) },
restore = { value -> mutableStateOf(Offset(unpackFloat1(value), unpackFloat2(value))) }
)
121 changes: 121 additions & 0 deletions app/src/main/java/com/skyd/anivu/ext/PointerInputScopeExt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package com.skyd.anivu.ext

import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.calculateCentroid
import androidx.compose.foundation.gestures.calculateCentroidSize
import androidx.compose.foundation.gestures.calculatePan
import androidx.compose.foundation.gestures.calculateRotation
import androidx.compose.foundation.gestures.calculateZoom
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.pointer.PointerInputChange
import androidx.compose.ui.input.pointer.PointerInputScope
import androidx.compose.ui.input.pointer.positionChanged
import androidx.compose.ui.util.fastAny
import androidx.compose.ui.util.fastForEach
import kotlin.math.PI
import kotlin.math.abs


suspend fun PointerInputScope.detectDoubleFingerTransformGestures(
onVerticalDragStart: (Offset) -> Unit = { },
onVerticalDragEnd: () -> Unit = { },
onVerticalDragCancel: () -> Unit = { },
onVerticalDrag: (change: PointerInputChange, dragAmount: Float) -> Unit,
onHorizontalDragStart: (Offset) -> Unit = { },
onHorizontalDragEnd: () -> Unit = { },
onHorizontalDragCancel: () -> Unit = { },
onHorizontalDrag: (change: PointerInputChange, dragAmount: Float) -> Unit,
onGesture: (centroid: Offset, pan: Offset, zoom: Float, rotation: Float) -> Unit,
) {
awaitEachGesture {
var rotation = 0f
var zoom = 1f
var pan = Offset.Zero
var singlePan = Offset.Zero
var pastTouchSlop = false
val touchSlop = viewConfiguration.touchSlop
var lockedToPanZoom = false

var horizontalDrag = false
var verticalDrag = false
var transformDrag = false

val firstDown = awaitFirstDown(requireUnconsumed = false)
var canceled: Boolean

do {
val event = awaitPointerEvent()
canceled = event.changes.fastAny { it.isConsumed }
val count: Int = if (event.changes.size > 2) {
event.changes.takeIf { it.last().id != it.first().id }?.size ?: 1
} else event.changes.size

if (!canceled) {
val zoomChange = event.calculateZoom()
val panChange = event.calculatePan()
val rotationChange = event.calculateRotation()
if (!pastTouchSlop) {
if (count == 1) {
singlePan += panChange
val singlePanMotion = singlePan.getDistance()
if (singlePanMotion > touchSlop) {
pastTouchSlop = true
if (abs(singlePan.x) > abs(singlePan.y)) {
horizontalDrag = true
onHorizontalDragStart(firstDown.position)
} else {
verticalDrag = true
onVerticalDragStart(firstDown.position)
}
}
} else if (count > 1) {
zoom *= zoomChange
rotation += rotationChange
pan += panChange

val centroidSize = event.calculateCentroidSize(useCurrent = false)
val zoomMotion = abs(1 - zoom) * centroidSize
val rotationMotion = abs(rotation * PI.toFloat() * centroidSize / 180f)
val panMotion = pan.getDistance()

if (zoomMotion > touchSlop ||
rotationMotion > touchSlop ||
panMotion > touchSlop
) {
transformDrag = true
pastTouchSlop = true
lockedToPanZoom = rotationMotion < touchSlop
}
}
}
if (pastTouchSlop) {
if (horizontalDrag) {
onHorizontalDrag(event.changes.first(), panChange.x)
} else if (verticalDrag) {
onVerticalDrag(event.changes.first(), panChange.y)
} else if (transformDrag) {
val centroid = event.calculateCentroid(useCurrent = false)
val effectiveRotation = if (lockedToPanZoom) 0f else rotationChange
if (effectiveRotation != 0f ||
zoomChange != 1f ||
panChange != Offset.Zero
) {
onGesture(centroid, panChange, zoomChange, effectiveRotation)
}
}
event.changes.fastForEach {
if (it.positionChanged()) {
it.consume()
}
}
}
}
} while (!canceled && event.changes.fastAny { it.pressed })
if (horizontalDrag) {
if (canceled) onHorizontalDragCancel() else onHorizontalDragEnd()
} else if (verticalDrag) {
if (canceled) onVerticalDragCancel() else onVerticalDragEnd()
}
}
}
Loading

0 comments on commit 2543a39

Please sign in to comment.