mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-07 13:38:13 -08:00
chore: Implement translation callbacks to flutter
This commit is contained in:
parent
e902e2034a
commit
29917bb59f
16 changed files with 681 additions and 43 deletions
|
|
@ -3,6 +3,7 @@ package nl.jknaapen.fladder
|
|||
import NativeVideoActivity
|
||||
import PlayerSettingsPigeon
|
||||
import StartResult
|
||||
import TranslationsPigeon
|
||||
import VideoPlayerApi
|
||||
import VideoPlayerControlsCallback
|
||||
import VideoPlayerListenerCallback
|
||||
|
|
@ -12,6 +13,7 @@ import androidx.activity.result.contract.ActivityResultContracts
|
|||
import com.ryanheise.audioservice.AudioServiceFragmentActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import nl.jknaapen.fladder.objects.PlayerSettingsObject
|
||||
import nl.jknaapen.fladder.objects.TranslationsMessenger
|
||||
import nl.jknaapen.fladder.objects.VideoPlayerObject
|
||||
import nl.jknaapen.fladder.utility.leanBackEnabled
|
||||
|
||||
|
|
@ -37,6 +39,9 @@ class MainActivity : AudioServiceFragmentActivity(), NativeVideoActivity {
|
|||
videoPlayerHost.videoPlayerControls =
|
||||
VideoPlayerControlsCallback(flutterEngine.dartExecutor.binaryMessenger)
|
||||
|
||||
TranslationsMessenger.translation =
|
||||
TranslationsPigeon(flutterEngine.dartExecutor.binaryMessenger)
|
||||
|
||||
PlayerSettingsPigeon.setUp(
|
||||
flutterEngine.dartExecutor.binaryMessenger,
|
||||
api = PlayerSettingsObject
|
||||
|
|
@ -54,9 +59,9 @@ class MainActivity : AudioServiceFragmentActivity(), NativeVideoActivity {
|
|||
StartResult(resultValue = "Cancelled")
|
||||
}
|
||||
|
||||
callback?.invoke(Result.success(startResult))
|
||||
VideoPlayerObject.implementation.player?.stop()
|
||||
VideoPlayerObject.implementation.player?.release()
|
||||
callback?.invoke(Result.success(startResult))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,217 @@
|
|||
// Autogenerated from Pigeon (v26.0.1), do not edit directly.
|
||||
// See also: https://pub.dev/packages/pigeon
|
||||
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
|
||||
|
||||
|
||||
import android.util.Log
|
||||
import io.flutter.plugin.common.BasicMessageChannel
|
||||
import io.flutter.plugin.common.BinaryMessenger
|
||||
import io.flutter.plugin.common.EventChannel
|
||||
import io.flutter.plugin.common.MessageCodec
|
||||
import io.flutter.plugin.common.StandardMethodCodec
|
||||
import io.flutter.plugin.common.StandardMessageCodec
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.nio.ByteBuffer
|
||||
private object TranslationsPigeonPigeonUtils {
|
||||
|
||||
fun createConnectionError(channelName: String): FlutterError {
|
||||
return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "") }
|
||||
}
|
||||
private open class TranslationsPigeonPigeonCodec : StandardMessageCodec() {
|
||||
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
|
||||
return super.readValueOfType(type, buffer)
|
||||
}
|
||||
override fun writeValue(stream: ByteArrayOutputStream, value: Any?) {
|
||||
super.writeValue(stream, value)
|
||||
}
|
||||
}
|
||||
|
||||
/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */
|
||||
class TranslationsPigeon(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") {
|
||||
companion object {
|
||||
/** The codec used by TranslationsPigeon. */
|
||||
val codec: MessageCodec<Any?> by lazy {
|
||||
TranslationsPigeonPigeonCodec()
|
||||
}
|
||||
}
|
||||
fun next(callback: (Result<String>) -> Unit)
|
||||
{
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
val channelName = "dev.flutter.pigeon.nl_jknaapen_fladder.settings.TranslationsPigeon.next$separatedMessageChannelSuffix"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(null) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else if (it[0] == null) {
|
||||
callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")))
|
||||
} else {
|
||||
val output = it[0] as String
|
||||
callback(Result.success(output))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(TranslationsPigeonPigeonUtils.createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun nextVideo(callback: (Result<String>) -> Unit)
|
||||
{
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
val channelName = "dev.flutter.pigeon.nl_jknaapen_fladder.settings.TranslationsPigeon.nextVideo$separatedMessageChannelSuffix"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(null) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else if (it[0] == null) {
|
||||
callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")))
|
||||
} else {
|
||||
val output = it[0] as String
|
||||
callback(Result.success(output))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(TranslationsPigeonPigeonUtils.createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun close(callback: (Result<String>) -> Unit)
|
||||
{
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
val channelName = "dev.flutter.pigeon.nl_jknaapen_fladder.settings.TranslationsPigeon.close$separatedMessageChannelSuffix"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(null) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else if (it[0] == null) {
|
||||
callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")))
|
||||
} else {
|
||||
val output = it[0] as String
|
||||
callback(Result.success(output))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(TranslationsPigeonPigeonUtils.createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun skip(nameArg: String, callback: (Result<String>) -> Unit)
|
||||
{
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
val channelName = "dev.flutter.pigeon.nl_jknaapen_fladder.settings.TranslationsPigeon.skip$separatedMessageChannelSuffix"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(nameArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else if (it[0] == null) {
|
||||
callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")))
|
||||
} else {
|
||||
val output = it[0] as String
|
||||
callback(Result.success(output))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(TranslationsPigeonPigeonUtils.createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun subtitles(callback: (Result<String>) -> Unit)
|
||||
{
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
val channelName = "dev.flutter.pigeon.nl_jknaapen_fladder.settings.TranslationsPigeon.subtitles$separatedMessageChannelSuffix"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(null) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else if (it[0] == null) {
|
||||
callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")))
|
||||
} else {
|
||||
val output = it[0] as String
|
||||
callback(Result.success(output))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(TranslationsPigeonPigeonUtils.createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun off(callback: (Result<String>) -> Unit)
|
||||
{
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
val channelName = "dev.flutter.pigeon.nl_jknaapen_fladder.settings.TranslationsPigeon.off$separatedMessageChannelSuffix"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(null) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else if (it[0] == null) {
|
||||
callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")))
|
||||
} else {
|
||||
val output = it[0] as String
|
||||
callback(Result.success(output))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(TranslationsPigeonPigeonUtils.createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun chapters(countArg: Long, callback: (Result<String>) -> Unit)
|
||||
{
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
val channelName = "dev.flutter.pigeon.nl_jknaapen_fladder.settings.TranslationsPigeon.chapters$separatedMessageChannelSuffix"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(countArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else if (it[0] == null) {
|
||||
callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")))
|
||||
} else {
|
||||
val output = it[0] as String
|
||||
callback(Result.success(output))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(TranslationsPigeonPigeonUtils.createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun nextUpInSeconds(secondsArg: Long, callback: (Result<String>) -> Unit)
|
||||
{
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
val channelName = "dev.flutter.pigeon.nl_jknaapen_fladder.settings.TranslationsPigeon.nextUpInSeconds$separatedMessageChannelSuffix"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(secondsArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else if (it[0] == null) {
|
||||
callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")))
|
||||
} else {
|
||||
val output = it[0] as String
|
||||
callback(Result.success(output))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(TranslationsPigeonPigeonUtils.createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun endsAt(timeArg: String, callback: (Result<String>) -> Unit)
|
||||
{
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
val channelName = "dev.flutter.pigeon.nl_jknaapen_fladder.settings.TranslationsPigeon.endsAt$separatedMessageChannelSuffix"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(timeArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else if (it[0] == null) {
|
||||
callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")))
|
||||
} else {
|
||||
val output = it[0] as String
|
||||
callback(Result.success(output))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(TranslationsPigeonPigeonUtils.createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -66,6 +66,8 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.util.fastCoerceIn
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import kotlinx.coroutines.delay
|
||||
import nl.jknaapen.fladder.objects.Localized
|
||||
import nl.jknaapen.fladder.objects.Translate
|
||||
import nl.jknaapen.fladder.objects.VideoPlayerObject
|
||||
import nl.jknaapen.fladder.utility.capitalize
|
||||
import nl.jknaapen.fladder.utility.formatTime
|
||||
|
|
@ -122,20 +124,23 @@ internal fun ProgressBar(
|
|||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
val progressBarTopLabel = listOf(
|
||||
playableData?.currentItem?.subTitle,
|
||||
endTimeString,
|
||||
)
|
||||
|
||||
val label = progressBarTopLabel.joinToString(separator = " - ")
|
||||
if (label.isNotBlank()) {
|
||||
Text(
|
||||
text = label,
|
||||
style = MaterialTheme.typography.bodyLarge.copy(
|
||||
color = Color.White,
|
||||
fontWeight = FontWeight.Bold
|
||||
),
|
||||
Translate({ Localized.endsAt(endTimeString ?: "", it) }, endTimeString) { translation ->
|
||||
val progressBarTopLabel = listOf(
|
||||
playableData?.currentItem?.subTitle,
|
||||
translation,
|
||||
)
|
||||
|
||||
val label = progressBarTopLabel.filterNot { it.isNullOrBlank() }
|
||||
.joinToString(separator = " - ")
|
||||
if (label.isNotBlank()) {
|
||||
Text(
|
||||
text = label,
|
||||
style = MaterialTheme.typography.bodyLarge.copy(
|
||||
color = Color.White,
|
||||
fontWeight = FontWeight.Bold
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
|
|
|||
|
|
@ -34,7 +34,9 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import nl.jknaapen.fladder.objects.Localized
|
||||
import nl.jknaapen.fladder.objects.PlayerSettingsObject
|
||||
import nl.jknaapen.fladder.objects.Translate
|
||||
import nl.jknaapen.fladder.objects.VideoPlayerObject
|
||||
import nl.jknaapen.fladder.utility.defaultSelected
|
||||
import nl.jknaapen.fladder.utility.leanBackEnabled
|
||||
|
|
@ -135,11 +137,18 @@ internal fun BoxScope.SegmentSkipOverlay(
|
|||
}
|
||||
}
|
||||
}
|
||||
activeSegment?.let {
|
||||
Text(
|
||||
"Skip ${it.name.lowercase()}",
|
||||
style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold)
|
||||
)
|
||||
activeSegment?.let { segment ->
|
||||
Translate({ cb ->
|
||||
Localized.skip(
|
||||
segment.name.lowercase(),
|
||||
cb
|
||||
)
|
||||
}) { translation ->
|
||||
Text(
|
||||
translation,
|
||||
style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ import androidx.compose.ui.focus.focusRequester
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import nl.jknaapen.fladder.objects.Localized
|
||||
import nl.jknaapen.fladder.objects.Translate
|
||||
import nl.jknaapen.fladder.objects.VideoPlayerObject
|
||||
import nl.jknaapen.fladder.utility.clearAudioTrack
|
||||
import nl.jknaapen.fladder.utility.setInternalAudioTrack
|
||||
|
|
@ -82,7 +84,9 @@ fun AudioPicker(
|
|||
},
|
||||
selected = selectedOff
|
||||
) {
|
||||
Text("Off")
|
||||
Translate(Localized::off) {
|
||||
Text(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil3.compose.AsyncImage
|
||||
import nl.jknaapen.fladder.objects.Localized
|
||||
import nl.jknaapen.fladder.objects.Translate
|
||||
import nl.jknaapen.fladder.objects.VideoPlayerObject
|
||||
import nl.jknaapen.fladder.utility.highlightOnFocus
|
||||
|
||||
|
|
@ -78,11 +80,14 @@ internal fun ChapterSelectionSheet(
|
|||
.wrapContentHeight(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Text(
|
||||
"Chapters",
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = Color.White
|
||||
)
|
||||
Translate({ Localized.chapters(chapters.size.toLong(), it) }) {
|
||||
Text(
|
||||
it,
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = Color.White
|
||||
)
|
||||
}
|
||||
|
||||
LazyRow(
|
||||
state = lazyListState,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import androidx.compose.ui.focus.focusRequester
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import nl.jknaapen.fladder.objects.Localized
|
||||
import nl.jknaapen.fladder.objects.Translate
|
||||
import nl.jknaapen.fladder.objects.VideoPlayerObject
|
||||
import nl.jknaapen.fladder.utility.clearSubtitleTrack
|
||||
import nl.jknaapen.fladder.utility.setInternalSubtitleTrack
|
||||
|
|
@ -79,9 +81,9 @@ fun SubtitlePicker(
|
|||
},
|
||||
selected = selectedOff
|
||||
) {
|
||||
Text(
|
||||
text = "Off",
|
||||
)
|
||||
Translate(Localized::off) {
|
||||
Text(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
internalSubTracks.forEachIndexed { index, subtitle ->
|
||||
|
|
|
|||
|
|
@ -45,7 +45,9 @@ import io.github.rabehx.iconsax.filled.Next
|
|||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import nl.jknaapen.fladder.composables.controls.CustomButton
|
||||
import nl.jknaapen.fladder.objects.Localized
|
||||
import nl.jknaapen.fladder.objects.PlayerSettingsObject
|
||||
import nl.jknaapen.fladder.objects.Translate
|
||||
import nl.jknaapen.fladder.objects.VideoPlayerObject
|
||||
import nl.jknaapen.fladder.utility.conditional
|
||||
import nl.jknaapen.fladder.utility.highlightOnFocus
|
||||
|
|
@ -169,13 +171,24 @@ internal fun NextUpOverlay(
|
|||
modifier = Modifier.weight(1f),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
Text(
|
||||
"Next-up in $timeUntilNextVideo seconds",
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
Translate(
|
||||
{
|
||||
Localized.nextUpInSeconds(
|
||||
timeUntilNextVideo.toLong(),
|
||||
callback = it
|
||||
)
|
||||
},
|
||||
key = timeUntilNextVideo,
|
||||
) {
|
||||
Text(
|
||||
it,
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(alignment = Alignment.CenterHorizontally)
|
||||
|
|
@ -199,7 +212,9 @@ internal fun NextUpOverlay(
|
|||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Text("Next")
|
||||
Translate(Localized::next) { value ->
|
||||
Text(value)
|
||||
}
|
||||
Icon(Iconsax.Filled.Next, contentDescription = "Play next video")
|
||||
}
|
||||
}
|
||||
|
|
@ -213,7 +228,9 @@ internal fun NextUpOverlay(
|
|||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Text("Close")
|
||||
Translate(Localized::close) {
|
||||
Text(it)
|
||||
}
|
||||
Icon(Iconsax.Filled.CloseCircle, contentDescription = "Close Icon")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package nl.jknaapen.fladder.objects
|
||||
|
||||
import TranslationsPigeon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
|
||||
val Localized
|
||||
get() = TranslationsMessenger.translation
|
||||
|
||||
internal object TranslationsMessenger {
|
||||
lateinit var translation: TranslationsPigeon
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun Translate(
|
||||
callback: ((Result<String>) -> Unit) -> Unit,
|
||||
key: Any? = Unit,
|
||||
content: @Composable (String) -> Unit
|
||||
) {
|
||||
var value by remember { mutableStateOf<String?>(null) }
|
||||
|
||||
LaunchedEffect(key) {
|
||||
callback { result ->
|
||||
value = result.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
content(value.orEmpty())
|
||||
}
|
||||
|
|
@ -14,7 +14,6 @@ import nl.jknaapen.fladder.VideoPlayerActivity
|
|||
import nl.jknaapen.fladder.messengers.VideoPlayerImplementation
|
||||
import nl.jknaapen.fladder.utility.InternalTrack
|
||||
import java.time.ZoneId
|
||||
import java.time.format.DateTimeFormatter
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.toJavaInstant
|
||||
|
|
@ -43,9 +42,8 @@ object VideoPlayerObject {
|
|||
val remainingMs = (dur - pos).coerceAtLeast(0L)
|
||||
val endInstant = startInstant.toJavaInstant().plusMillis(remainingMs)
|
||||
val endZoned = endInstant.atZone(zone)
|
||||
val formatter = DateTimeFormatter.ofPattern("hh:mm a")
|
||||
|
||||
"ends at ${endZoned.format(formatter)}"
|
||||
endZoned.toOffsetDateTime().toString()
|
||||
}
|
||||
|
||||
val currentSubtitleTrackIndex =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue