diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index 8d1b60f48..b381dc972 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -24,6 +24,10 @@ plugins { } kotlin { + // Required for CMP files/ resources (emoji-data.json) to be packaged as Android assets. + // Without this, Res.readBytes() throws MissingResourceException at runtime. + androidLibrary { androidResources.enable = true } + sourceSets { commonMain.dependencies { implementation(projects.core.common) diff --git a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/emoji/EmojiPickerDialog.kt b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/emoji/EmojiPickerDialog.kt index cbf5e9074..042a55826 100644 --- a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/emoji/EmojiPickerDialog.kt +++ b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/emoji/EmojiPickerDialog.kt @@ -125,6 +125,7 @@ fun EmojiPickerDialog( ) { val viewModel: EmojiPickerViewModel = koinViewModel() val isLoaded by viewModel.isLoaded.collectAsState() + val loadError by viewModel.loadError.collectAsState() var searchQuery by rememberSaveable { mutableStateOf("") } var debouncedQuery by remember { mutableStateOf("") } var selectedCategoryIndex by rememberSaveable { mutableStateOf(0) } @@ -147,7 +148,15 @@ fun EmojiPickerDialog( onDismissRequest = onDismiss, sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), ) { - if (isLoaded) { + if (loadError) { + Box(modifier = Modifier.fillMaxWidth().height(200.dp), contentAlignment = Alignment.Center) { + Text( + text = "Unable to load emoji", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + } else if (isLoaded) { EmojiPickerContent( searchQuery = searchQuery, debouncedQuery = debouncedQuery, diff --git a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/emoji/EmojiPickerViewModel.kt b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/emoji/EmojiPickerViewModel.kt index 4feb31125..c3e1e68f7 100644 --- a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/emoji/EmojiPickerViewModel.kt +++ b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/emoji/EmojiPickerViewModel.kt @@ -18,9 +18,11 @@ package org.meshtastic.core.ui.emoji import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import co.touchlab.kermit.Logger import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch +import org.jetbrains.compose.resources.MissingResourceException import org.koin.core.annotation.KoinViewModel import org.meshtastic.core.repository.CustomEmojiPrefs @@ -41,10 +43,21 @@ internal class EmojiPickerViewModel( val allEmojis: List get() = emojiRepository.all + private val _loadError = MutableStateFlow(false) + val loadError: StateFlow = _loadError + init { viewModelScope.launch { - emojiRepository.preload() - _isLoaded.value = true + try { + emojiRepository.preload() + _isLoaded.value = true + } catch (e: MissingResourceException) { + Logger.e("EmojiPickerViewModel", e) { "Failed to load emoji data" } + _loadError.value = true + } catch (e: IllegalStateException) { + Logger.e("EmojiPickerViewModel", e) { "Failed to load emoji data" } + _loadError.value = true + } } }