fix: Properly localized dates in native player

This commit is contained in:
PartyDonut 2025-10-18 21:15:35 +02:00
parent 829bc3e34c
commit d2b8a855f3
7 changed files with 90 additions and 15 deletions

View file

@ -194,6 +194,26 @@ class TranslationsPigeon(private val binaryMessenger: BinaryMessenger, private v
} }
} }
} }
fun hoursAndMinutes(timeArg: String, callback: (Result<String>) -> Unit)
{
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
val channelName = "dev.flutter.pigeon.nl_jknaapen_fladder.settings.TranslationsPigeon.hoursAndMinutes$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)))
}
}
}
fun endsAt(timeArg: String, callback: (Result<String>) -> Unit) fun endsAt(timeArg: String, callback: (Result<String>) -> Unit)
{ {
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""

View file

@ -74,14 +74,15 @@ import kotlinx.coroutines.delay
import nl.jknaapen.fladder.composables.dialogs.AudioPicker import nl.jknaapen.fladder.composables.dialogs.AudioPicker
import nl.jknaapen.fladder.composables.dialogs.ChapterSelectionSheet import nl.jknaapen.fladder.composables.dialogs.ChapterSelectionSheet
import nl.jknaapen.fladder.composables.dialogs.SubtitlePicker import nl.jknaapen.fladder.composables.dialogs.SubtitlePicker
import nl.jknaapen.fladder.objects.Localized
import nl.jknaapen.fladder.objects.PlayerSettingsObject import nl.jknaapen.fladder.objects.PlayerSettingsObject
import nl.jknaapen.fladder.objects.Translate
import nl.jknaapen.fladder.objects.VideoPlayerObject import nl.jknaapen.fladder.objects.VideoPlayerObject
import nl.jknaapen.fladder.utility.ImmersiveSystemBars import nl.jknaapen.fladder.utility.ImmersiveSystemBars
import nl.jknaapen.fladder.utility.defaultSelected import nl.jknaapen.fladder.utility.defaultSelected
import nl.jknaapen.fladder.utility.leanBackEnabled import nl.jknaapen.fladder.utility.leanBackEnabled
import nl.jknaapen.fladder.utility.visible import nl.jknaapen.fladder.utility.visible
import java.time.ZoneId import java.time.ZoneId
import java.time.format.DateTimeFormatter
import kotlin.time.Clock import kotlin.time.Clock
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime
@ -522,21 +523,34 @@ internal fun RowScope.RightButtons(
} }
} }
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
@kotlin.OptIn(ExperimentalTime::class) @kotlin.OptIn(ExperimentalTime::class)
@Composable @Composable
private fun CurrentTime() { private fun CurrentTime() {
val startInstant = Clock.System.now()
val zone = ZoneId.systemDefault() val zone = ZoneId.systemDefault()
val endInstant = startInstant.toJavaInstant() var currentTime by remember { mutableStateOf(Clock.System.now()) }
val endZoned = endInstant.atZone(zone)
val formatter = DateTimeFormatter.ofPattern("hh:mm a")
Text( LaunchedEffect(Unit) {
endZoned.format(formatter), while (true) {
style = MaterialTheme.typography.titleMedium, currentTime = Clock.System.now()
color = Color.White val delayMs = 60_000L - (currentTime.toEpochMilliseconds() % 60_000L)
) delay(delayMs)
}
}
val endZoned = currentTime.toJavaInstant().atZone(zone)
Translate(
{
Localized.hoursAndMinutes(endZoned.toOffsetDateTime().toString(), it)
},
key = currentTime,
) { time ->
Text(
text = time,
style = MaterialTheme.typography.titleMedium,
color = Color.White
)
}
} }

View file

@ -36,11 +36,11 @@ object VideoPlayerObject {
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
@OptIn(ExperimentalTime::class) @OptIn(ExperimentalTime::class)
val endTime = combine(position, duration) { pos, dur -> val endTime = combine(position, duration) { pos, dur ->
val startInstant = Clock.System.now() val now = Clock.System.now().toJavaInstant()
val zone = ZoneId.systemDefault() val zone = ZoneId.systemDefault()
val remainingMs = (dur - pos).coerceAtLeast(0L) val remainingMs = (dur - pos).coerceAtLeast(0L)
val endInstant = startInstant.toJavaInstant().plusMillis(remainingMs) val endInstant = now.plusMillis(remainingMs)
val endZoned = endInstant.atZone(zone) val endZoned = endInstant.atZone(zone)
endZoned.toOffsetDateTime().toString() endZoned.toOffsetDateTime().toString()

View file

@ -1356,5 +1356,15 @@
"type": "int" "type": "int"
} }
} }
},
"formattedTime": "{time}",
"@formattedTime": {
"description": "Formatted time",
"placeholders": {
"time": {
"type": "DateTime",
"format": "jm"
}
}
} }
} }

View file

@ -59,6 +59,8 @@ abstract class TranslationsPigeon {
String nextUpInSeconds(int seconds); String nextUpInSeconds(int seconds);
String hoursAndMinutes(String time);
String endsAt(String time); String endsAt(String time);
static void setUp(TranslationsPigeon? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { static void setUp(TranslationsPigeon? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) {
@ -233,6 +235,31 @@ abstract class TranslationsPigeon {
}); });
} }
} }
{
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.nl_jknaapen_fladder.settings.TranslationsPigeon.hoursAndMinutes$messageChannelSuffix', pigeonChannelCodec,
binaryMessenger: binaryMessenger);
if (api == null) {
pigeonVar_channel.setMessageHandler(null);
} else {
pigeonVar_channel.setMessageHandler((Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.nl_jknaapen_fladder.settings.TranslationsPigeon.hoursAndMinutes was null.');
final List<Object?> args = (message as List<Object?>?)!;
final String? arg_time = (args[0] as String?);
assert(arg_time != null,
'Argument for dev.flutter.pigeon.nl_jknaapen_fladder.settings.TranslationsPigeon.hoursAndMinutes was null, expected non-null String.');
try {
final String output = api.hoursAndMinutes(arg_time!);
return wrapResponse(result: output);
} on PlatformException catch (e) {
return wrapResponse(error: e);
} catch (e) {
return wrapResponse(error: PlatformException(code: 'error', message: e.toString()));
}
});
}
}
{ {
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.nl_jknaapen_fladder.settings.TranslationsPigeon.endsAt$messageChannelSuffix', pigeonChannelCodec, 'dev.flutter.pigeon.nl_jknaapen_fladder.settings.TranslationsPigeon.endsAt$messageChannelSuffix', pigeonChannelCodec,

View file

@ -78,7 +78,7 @@ class _TranslationsMessgener extends messenger.TranslationsPigeon {
String close() => context.localized.close; String close() => context.localized.close;
@override @override
String endsAt(String time) => context.localized.endsAt(DateTime.parse(time)); String endsAt(String time) => context.localized.endsAt(DateTime.parse(time).toLocal());
@override @override
String next() => context.localized.nextVideo; String next() => context.localized.nextVideo;
@ -97,4 +97,7 @@ class _TranslationsMessgener extends messenger.TranslationsPigeon {
@override @override
String subtitles() => context.localized.subtitles; String subtitles() => context.localized.subtitles;
@override
String hoursAndMinutes(String time) => context.localized.formattedTime(DateTime.parse(time).toLocal());
} }

View file

@ -25,6 +25,7 @@ abstract class TranslationsPigeon {
String chapters(int count); String chapters(int count);
String nextUpInSeconds(int seconds); String nextUpInSeconds(int seconds);
String hoursAndMinutes(String time);
String endsAt(String time); String endsAt(String time);
} }