Skip to content

Commit

Permalink
[feature|optimize] Support direct playback of media enclosure in RSS …
Browse files Browse the repository at this point in the history
…(not Torrent); support set playback speed; optimize media screen
  • Loading branch information
SkyD666 committed May 29, 2024
1 parent 88c1f6e commit 4871f1d
Show file tree
Hide file tree
Showing 29 changed files with 483 additions and 198 deletions.
2 changes: 1 addition & 1 deletion 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-beta37"
versionName = "1.1-beta38"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

Expand Down
11 changes: 11 additions & 0 deletions app/src/main/java/com/skyd/anivu/model/bean/EnclosureBean.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,16 @@ data class EnclosureBean(
const val URL_COLUMN = "url"
const val LENGTH_COLUMN = "length"
const val TYPE_COLUMN = "type"

val mediaExtensions = listOf(
".m3u8", ".ogg", ".mp3", ".flac", ".m4v", ".mov", ".avi", ".webm",
".mp4", ".mkv", ".m4a",
)
}

val isMedia: Boolean
get() = type?.startsWith("audio/") == true ||
type?.startsWith("video/") == true ||
type == "application/vnd.apple.mpegurl" ||
mediaExtensions.any { url.endsWith(it) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ import com.skyd.anivu.base.BaseBean

data class LinkEnclosureBean(
val link: String,
) : BaseBean
) : BaseBean {
val isMedia: Boolean
get() = EnclosureBean.mediaExtensions.any { link.endsWith(it) }
}
15 changes: 9 additions & 6 deletions app/src/main/java/com/skyd/anivu/model/worker/download/Util.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,22 @@ import java.io.IOException

fun doIfMagnetOrTorrentLink(
link: String,
onMagnet: (String) -> Unit,
onTorrent: (String) -> Unit,
onUnsupported: (String) -> Unit = {},
onMagnet: ((String) -> Unit)? = null,
onTorrent: ((String) -> Unit)? = null,
onSupported: ((String) -> Unit)? = null,
onUnsupported: ((String) -> Unit)? = null,
) {
if (link.startsWith("magnet:")) {
onMagnet(link)
onMagnet?.invoke(link)
onSupported?.invoke(link)
} else if (
(link.startsWith("http:") || link.startsWith("https:")) &&
link.endsWith(".torrent")
) {
onTorrent(link)
onTorrent?.invoke(link)
onSupported?.invoke(link)
} else {
onUnsupported(link)
onUnsupported?.invoke(link)
}
}

Expand Down
9 changes: 9 additions & 0 deletions app/src/main/java/com/skyd/anivu/ui/activity/PlayActivity.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.skyd.anivu.ui.activity

import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Build
Expand All @@ -26,6 +27,14 @@ import java.io.File
class PlayActivity : BaseComposeActivity() {
companion object {
const val VIDEO_URI_KEY = "videoUri"

fun play(activity: Activity, uri: Uri) {
activity.startActivity(
Intent(activity, PlayActivity::class.java).apply {
putExtra(VIDEO_URI_KEY, uri)
}
)
}
}

private var player: MPVView? = null
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package com.skyd.anivu.ui.adapter.variety.proxy


import android.net.Uri
import android.view.LayoutInflater
import android.view.ViewGroup
import com.skyd.anivu.databinding.ItemEnclosure1Binding
import com.skyd.anivu.ext.activity
import com.skyd.anivu.ext.copy
import com.skyd.anivu.ext.fileSize
import com.skyd.anivu.ext.gone
import com.skyd.anivu.ext.visible
import com.skyd.anivu.model.bean.EnclosureBean
import com.skyd.anivu.model.worker.download.doIfMagnetOrTorrentLink
import com.skyd.anivu.ui.activity.PlayActivity
import com.skyd.anivu.ui.adapter.variety.Enclosure1ViewHolder
import com.skyd.anivu.ui.adapter.variety.VarietyAdapter

Expand Down Expand Up @@ -34,9 +40,28 @@ class Enclosure1Proxy(
tvEnclosure1Url.setOnClickListener {
data.url.copy(context)
}
btnEnclosure1Download.setOnClickListener {
onDownload(data)
if (data.isMedia) {
btnEnclosure1Play.visible()
btnEnclosure1Play.setOnClickListener {
try {
PlayActivity.play(context.activity, Uri.parse(data.url))
} catch (e: Exception) {
e.printStackTrace()
}
}
} else {
btnEnclosure1Play.gone()
}
doIfMagnetOrTorrentLink(
link = data.url,
onSupported = {
btnEnclosure1Download.visible()
btnEnclosure1Download.setOnClickListener {
onDownload(data)
}
},
onUnsupported = { btnEnclosure1Download.gone() }
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package com.skyd.anivu.ui.adapter.variety.proxy


import android.net.Uri
import android.view.LayoutInflater
import android.view.ViewGroup
import com.skyd.anivu.databinding.ItemLinkEnclosure1Binding
import com.skyd.anivu.ext.activity
import com.skyd.anivu.ext.copy
import com.skyd.anivu.ext.gone
import com.skyd.anivu.ext.visible
import com.skyd.anivu.model.bean.LinkEnclosureBean
import com.skyd.anivu.model.worker.download.doIfMagnetOrTorrentLink
import com.skyd.anivu.ui.activity.PlayActivity
import com.skyd.anivu.ui.adapter.variety.LinkEnclosure1ViewHolder
import com.skyd.anivu.ui.adapter.variety.VarietyAdapter

Expand All @@ -31,9 +37,28 @@ class LinkEnclosure1Proxy(
tvEnclosure1Url.setOnClickListener {
data.link.copy(context)
}
btnEnclosure1Download.setOnClickListener {
onDownload(data)
if (data.isMedia) {
btnEnclosure1Play.visible()
btnEnclosure1Play.setOnClickListener {
try {
PlayActivity.play(context.activity, Uri.parse(data.link))
} catch (e: Exception) {
e.printStackTrace()
}
}
} else {
btnEnclosure1Play.gone()
}
doIfMagnetOrTorrentLink(
link = data.link,
onSupported = {
btnEnclosure1Download.visible()
btnEnclosure1Download.setOnClickListener {
onDownload(data)
}
},
onUnsupported = { btnEnclosure1Download.gone() }
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.take
import javax.inject.Inject

@HiltViewModel
Expand Down
10 changes: 8 additions & 2 deletions app/src/main/java/com/skyd/anivu/ui/fragment/feed/FeedScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
Expand Down Expand Up @@ -445,7 +446,9 @@ private fun EditFeedDialog(
val focusRequester = remember { FocusRequester() }
val keyboard = LocalSoftwareKeyboardController.current
ClipboardTextField(
modifier = Modifier.focusRequester(focusRequester),
modifier = Modifier
.focusRequester(focusRequester)
.fillMaxWidth(),
value = url,
onValueChange = onUrlChange,
autoRequestFocus = false,
Expand All @@ -458,6 +461,7 @@ private fun EditFeedDialog(
)
Spacer(modifier = Modifier.height(10.dp))
ClipboardTextField(
modifier = Modifier.fillMaxWidth(),
value = nickname,
onValueChange = onNicknameChange,
autoRequestFocus = false,
Expand All @@ -478,7 +482,9 @@ private fun EditFeedDialog(
// The `menuAnchor` modifier must be passed to the text field to handle
// expanding/collapsing the menu on click. A read-only text field has
// the anchor type `PrimaryNotEditable`.
modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable),
modifier = Modifier
.menuAnchor(MenuAnchorType.PrimaryNotEditable)
.fillMaxWidth(),
value = group.name,
onValueChange = {},
readOnly = true,
Expand Down
41 changes: 33 additions & 8 deletions app/src/main/java/com/skyd/anivu/ui/fragment/media/Media1Item.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.skyd.anivu.ui.fragment.media

import android.graphics.Bitmap
import android.media.MediaMetadataRetriever
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
Expand All @@ -13,6 +14,7 @@ import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.OpenInNew
import androidx.compose.material.icons.outlined.Delete
Expand All @@ -34,9 +36,12 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.TextUnitType
import androidx.compose.ui.unit.dp
import com.skyd.anivu.R
import com.skyd.anivu.ext.fileSize
Expand All @@ -48,6 +53,7 @@ import com.skyd.anivu.model.bean.VideoBean
import com.skyd.anivu.ui.component.AniVuImage
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.Locale

@Composable
fun Media1Item(
Expand All @@ -63,6 +69,9 @@ fun Media1Item(
val isMedia = rememberSaveable(data) { data.isMedia(context) }
val isDir = rememberSaveable(data) { data.isDir }

val fileNameWithoutExtension = data.name.substringBeforeLast(".")
val fileExtension = data.name.substringAfterLast(".", "")

Column(
modifier = Modifier
.combinedClickable(onLongClick = { expandMenu = true }) {
Expand Down Expand Up @@ -94,27 +103,38 @@ fun Media1Item(
.padding(end = 10.dp)
.heightIn(min = 50.dp)
.fillMaxHeight()
.width(70.dp),
.width(80.dp),
) {
AniVuImage(
model = bitmap,
contentScale = ContentScale.Crop,
)
}
}
Text(text = data.name, maxLines = 3, style = MaterialTheme.typography.titleSmall)
Text(
text = fileNameWithoutExtension,
maxLines = 3,
style = MaterialTheme.typography.titleSmall,
)
}
Spacer(modifier = Modifier.height(6.dp))
Spacer(modifier = Modifier.height(8.dp))
Row(verticalAlignment = Alignment.CenterVertically) {
if (fileExtension.isNotBlank()) {
Text(
modifier = Modifier
.clip(RoundedCornerShape(3.dp))
.background(MaterialTheme.colorScheme.surfaceContainerHighest)
.padding(horizontal = 4.dp),
text = fileExtension.uppercase(Locale.getDefault()),
style = MaterialTheme.typography.labelSmall,
fontSize = TextUnit(10f, TextUnitType.Sp),
)
Spacer(modifier = Modifier.width(12.dp))
}
Text(
text = data.size.fileSize(context),
style = MaterialTheme.typography.labelMedium,
)
Spacer(modifier = Modifier.width(12.dp))
Text(
text = data.date.toDateTimeString(context = context),
style = MaterialTheme.typography.labelMedium,
)
if (isMedia || isDir) {
Spacer(modifier = Modifier.width(12.dp))
Icon(
Expand All @@ -123,6 +143,11 @@ fun Media1Item(
contentDescription = stringResource(id = R.string.video),
)
}
Spacer(modifier = Modifier.weight(1f))
Text(
text = data.date.toDateTimeString(context = context),
style = MaterialTheme.typography.labelMedium,
)
}

DropdownMenu(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.skyd.anivu.ui.fragment.media

import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
Expand Down Expand Up @@ -56,7 +55,6 @@ import com.skyd.anivu.ext.showSnackbar
import com.skyd.anivu.ext.toUri
import com.skyd.anivu.model.bean.VideoBean
import com.skyd.anivu.ui.activity.PlayActivity
import com.skyd.anivu.ui.activity.PlayActivity.Companion.VIDEO_URI_KEY
import com.skyd.anivu.ui.component.AniVuFloatingActionButton
import com.skyd.anivu.ui.component.AniVuTopBar
import com.skyd.anivu.ui.component.AniVuTopBarStyle
Expand Down Expand Up @@ -141,9 +139,10 @@ fun MediaScreen(path: String, hasParentDir: Boolean, viewModel: MediaViewModel =
},
contentWindowInsets = WindowInsets.safeDrawing.run {
val leftPadding = hasParentDir || windowSizeClass.isCompact
val bottomPadding = hasParentDir || !windowSizeClass.isCompact
var sides = WindowInsetsSides.Top + WindowInsetsSides.Right
if (leftPadding) sides += WindowInsetsSides.Left
if (hasParentDir) sides += WindowInsetsSides.Bottom
if (bottomPadding) sides += WindowInsetsSides.Bottom
only(sides)
},
) { innerPadding ->
Expand Down Expand Up @@ -177,11 +176,7 @@ fun MediaScreen(path: String, hasParentDir: Boolean, viewModel: MediaViewModel =
data = mediaListState.list,
contentPadding = innerPadding,
onPlay = {
(context.activity).startActivity(
Intent(context, PlayActivity::class.java).apply {
putExtra(VIDEO_URI_KEY, it.file.toUri(context))
}
)
PlayActivity.play(context.activity, it.file.toUri(context))
},
onOpenDir = {
navController.navigate(
Expand Down Expand Up @@ -232,7 +227,7 @@ private fun MediaList(
LazyVerticalGrid(
modifier = modifier.fillMaxSize(),
contentPadding = contentPadding,
columns = GridCells.Adaptive(300.dp),
columns = GridCells.Adaptive(360.dp),
) {
items(data) { item ->
if (item is VideoBean) {
Expand Down
Loading

0 comments on commit 4871f1d

Please sign in to comment.