diff --git a/CHANGELOG.md b/CHANGELOG.md
index 741cb66d8..32a801e41 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
+### Added
+
+- integrate with OS app language settings on Android >=14
+
## [v1.11.18] - 2024-11-18
### Changed
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DeviceHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DeviceHandler.kt
index 3fe35ae01..47cb4a572 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DeviceHandler.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DeviceHandler.kt
@@ -1,11 +1,14 @@
package deckers.thibault.aves.channel.calls
+import android.app.LocaleConfig
+import android.app.LocaleManager
import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.location.Geocoder
import android.net.Uri
import android.os.Build
+import android.os.LocaleList
import android.provider.MediaStore
import android.provider.Settings
import androidx.core.content.pm.ShortcutManagerCompat
@@ -32,6 +35,7 @@ class DeviceHandler(private val context: Context) : MethodCallHandler {
"getCapabilities" -> defaultScope.launch { safe(call, result, ::getCapabilities) }
"getDefaultTimeZoneRawOffsetMillis" -> safe(call, result, ::getDefaultTimeZoneRawOffsetMillis)
"getLocales" -> safe(call, result, ::getLocales)
+ "setLocaleConfig" -> safe(call, result, ::setLocaleConfig)
"getPerformanceClass" -> safe(call, result, ::getPerformanceClass)
"isLocked" -> safe(call, result, ::isLocked)
"isSystemFilePickerEnabled" -> safe(call, result, ::isSystemFilePickerEnabled)
@@ -88,6 +92,21 @@ class DeviceHandler(private val context: Context) : MethodCallHandler {
result.success(locales)
}
+ private fun setLocaleConfig(call: MethodCall, result: MethodChannel.Result) {
+ val locales = call.argument>("locales")
+ if (locales.isNullOrEmpty()) {
+ result.error("setLocaleConfig-args", "missing arguments", null)
+ return
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ val lm = context.getSystemService(Context.LOCALE_SERVICE) as? LocaleManager
+ lm?.overrideLocaleConfig = LocaleConfig(LocaleList.forLanguageTags(locales.joinToString(",")))
+ }
+
+ result.success(true)
+ }
+
private fun getPerformanceClass(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val performanceClass = Build.VERSION.MEDIA_PERFORMANCE_CLASS
diff --git a/lib/services/device_service.dart b/lib/services/device_service.dart
index 0eac24328..ad702490d 100644
--- a/lib/services/device_service.dart
+++ b/lib/services/device_service.dart
@@ -12,6 +12,8 @@ abstract class DeviceService {
Future> getLocales();
+ Future setLocaleConfig(List locales);
+
Future getPerformanceClass();
Future isLocked();
@@ -80,6 +82,17 @@ class PlatformDeviceService implements DeviceService {
return [];
}
+ @override
+ Future setLocaleConfig(List locales) async {
+ try {
+ await _platform.invokeMethod('setLocaleConfig', {
+ 'locales': locales.map((v) => v.toLanguageTag()).toList(),
+ });
+ } on PlatformException catch (e, stack) {
+ await reportService.recordError(e, stack);
+ }
+ }
+
@override
Future getPerformanceClass() async {
try {
diff --git a/lib/widgets/aves_app.dart b/lib/widgets/aves_app.dart
index e75829d11..cc1179ffd 100644
--- a/lib/widgets/aves_app.dart
+++ b/lib/widgets/aves_app.dart
@@ -502,6 +502,7 @@ class _AvesAppState extends State with WidgetsBindingObserver {
_monitorSettings();
videoControllerFactory.init();
+ unawaited(deviceService.setLocaleConfig(AvesApp.supportedLocales));
unawaited(storageService.deleteTempDirectory());
unawaited(_setupErrorReporting());