From 4123eaeccd35d87d3120b834cc76fcc48da0e1d6 Mon Sep 17 00:00:00 2001 From: Thomas Andres Gomez Date: Tue, 24 Oct 2023 14:21:35 +0200 Subject: [PATCH] Update the error management --- .../pixelized/rplexicon/LauncherViewModel.kt | 43 ++++----- .../com/pixelized/rplexicon/MainActivity.kt | 11 ++- .../ui/composable/error/FetchErrorUio.kt | 65 +++++++++---- .../screens/character/CharacterSheetScreen.kt | 13 +-- .../character/CharacterSheetViewModel.kt | 93 +++++++++---------- .../screens/lexicon/list/LexiconViewModel.kt | 4 +- .../location/list/LocationViewModel.kt | 2 +- .../screens/quest/list/QuestListViewModel.kt | 2 +- app/src/main/res/values-fr/strings.xml | 13 ++- app/src/main/res/values/strings.xml | 15 ++- 10 files changed, 152 insertions(+), 109 deletions(-) diff --git a/app/src/main/java/com/pixelized/rplexicon/LauncherViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/LauncherViewModel.kt index 390cf15..f107278 100644 --- a/app/src/main/java/com/pixelized/rplexicon/LauncherViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/LauncherViewModel.kt @@ -12,16 +12,18 @@ import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepositor import com.pixelized.rplexicon.repository.data.character.DescriptionRepository import com.pixelized.rplexicon.repository.data.character.EquipmentRepository import com.pixelized.rplexicon.repository.data.character.InventoryRepository +import com.pixelized.rplexicon.repository.data.character.SkillRepository +import com.pixelized.rplexicon.repository.data.character.SpellRepository import com.pixelized.rplexicon.repository.data.lexicon.LexiconRepository import com.pixelized.rplexicon.repository.data.lexicon.LocationRepository import com.pixelized.rplexicon.repository.data.lexicon.QuestRepository -import com.pixelized.rplexicon.repository.data.character.SkillRepository -import com.pixelized.rplexicon.repository.data.character.SpellRepository +import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio +import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio.Structure.Type import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch import javax.inject.Inject @@ -40,8 +42,8 @@ class LauncherViewModel @Inject constructor( equipmentRepository: EquipmentRepository, ) : ViewModel() { - private val _error = MutableSharedFlow() - val error: SharedFlow get() = _error + private val _error = MutableStateFlow(null) + val error: Flow get() = _error var isLoading by mutableStateOf(true) private set @@ -53,7 +55,7 @@ class LauncherViewModel @Inject constructor( lexiconRepository.fetchLexicon() } catch (exception: Exception) { Log.e(TAG, exception.message, exception) - _error.tryEmit("Lexicon fail to update") + _error.emit(FetchErrorUio.Structure(type = Type.LEXICON)) } } val location = async { @@ -61,7 +63,7 @@ class LauncherViewModel @Inject constructor( locationRepository.fetchLocation() } catch (exception: Exception) { Log.e(TAG, exception.message, exception) - _error.tryEmit("Location fail to update") + _error.emit(FetchErrorUio.Structure(type = Type.LOCATION)) } } val quest = async { @@ -69,7 +71,7 @@ class LauncherViewModel @Inject constructor( questRepository.fetchQuests() } catch (exception: Exception) { Log.e(TAG, exception.message, exception) - _error.tryEmit("Quest fail to update") + _error.emit(FetchErrorUio.Structure(type = Type.QUEST)) } } val characterSheet = async { @@ -77,7 +79,7 @@ class LauncherViewModel @Inject constructor( characterSheetRepository.fetchCharacterSheet() } catch (exception: Exception) { Log.e(TAG, exception.message, exception) - _error.tryEmit("CharacterSheet fail to update") + _error.emit(FetchErrorUio.Structure(type = Type.CHARACTER)) } } val description = async { @@ -85,7 +87,7 @@ class LauncherViewModel @Inject constructor( descriptionRepository.fetchDescription() } catch (exception: Exception) { Log.e(TAG, exception.message, exception) - _error.tryEmit("Skill/Spell description fail to update") + _error.emit(FetchErrorUio.Structure(type = Type.DESCRIPTION)) } } val inventory = async { @@ -93,7 +95,7 @@ class LauncherViewModel @Inject constructor( inventoryRepository.fetchInventory() } catch (exception: Exception) { Log.e(TAG, exception.message, exception) - _error.tryEmit("Inventories fail to update") + _error.emit(FetchErrorUio.Structure(type = Type.INVENTORY)) } } val equipment = async { @@ -101,7 +103,7 @@ class LauncherViewModel @Inject constructor( equipmentRepository.fetchEquipment() } catch (exception: Exception) { Log.e(TAG, exception.message, exception) - _error.tryEmit("Equipments fail to update") + _error.emit(FetchErrorUio.Structure(type = Type.EQUIPMENT)) } } awaitAll(characterSheet) @@ -111,7 +113,7 @@ class LauncherViewModel @Inject constructor( alterationRepository.fetchAlterationSheet(sheets = characterSheetRepository.sheets) } catch (exception: Exception) { Log.e(TAG, exception.message, exception) - _error.tryEmit("Alteration lexicon fail to update") + _error.emit(FetchErrorUio.Structure(type = Type.ALTERATION)) } } val action = async { @@ -119,7 +121,7 @@ class LauncherViewModel @Inject constructor( actionRepository.fetchActions(characters = characterSheetRepository.data.value) } catch (exception: Exception) { Log.e(TAG, exception.message, exception) - _error.tryEmit("Action fail to update") + _error.emit(FetchErrorUio.Structure(type = Type.ACTION)) } } val spell = async { @@ -127,7 +129,7 @@ class LauncherViewModel @Inject constructor( spellRepository.fetchSpells() } catch (exception: Exception) { Log.e(TAG, exception.message, exception) - _error.tryEmit("Spell fail to update") + _error.emit(FetchErrorUio.Structure(type = Type.SPELL)) } } val skill = async { @@ -135,13 +137,12 @@ class LauncherViewModel @Inject constructor( skillRepository.fetchSkills() } catch (exception: Exception) { Log.e(TAG, exception.message, exception) - _error.tryEmit("Skill fail to update") + _error.emit(FetchErrorUio.Structure(type = Type.SKILL)) } } - awaitAll( - lexicon, location, quest, description, inventory, - equipment, alteration, action, spell, skill, - ) + + awaitAll(lexicon, location, quest) + awaitAll(description, inventory, equipment, alteration, action, spell, skill) isLoading = false } diff --git a/app/src/main/java/com/pixelized/rplexicon/MainActivity.kt b/app/src/main/java/com/pixelized/rplexicon/MainActivity.kt index ad31589..d4b785e 100644 --- a/app/src/main/java/com/pixelized/rplexicon/MainActivity.kt +++ b/app/src/main/java/com/pixelized/rplexicon/MainActivity.kt @@ -32,6 +32,7 @@ import androidx.compose.ui.unit.dp import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.WindowCompat import com.pixelized.rplexicon.ui.composable.BlurredOverlayHost +import com.pixelized.rplexicon.ui.composable.error.HandleFetchError import com.pixelized.rplexicon.ui.navigation.ScreenNavHost import com.pixelized.rplexicon.ui.screens.rolls.BlurredRollOverlayHostState import com.pixelized.rplexicon.ui.screens.rolls.RollOverlay @@ -124,6 +125,7 @@ class MainActivity : ComponentActivity() { ), content = { Text( + modifier = Modifier.padding(vertical = 8.dp), color = MaterialTheme.colorScheme.onSurface, text = it.visuals.message, ) @@ -137,11 +139,10 @@ class MainActivity : ComponentActivity() { } } - LaunchedEffect(key1 = "LauncherError") { - launcherViewModel.error.collect { - snack.showSnackbar(message = it) - } - } + HandleFetchError( + snack = snack, + errors = launcherViewModel.error, + ) } } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/composable/error/FetchErrorUio.kt b/app/src/main/java/com/pixelized/rplexicon/ui/composable/error/FetchErrorUio.kt index 5ee87f7..6d15567 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/composable/error/FetchErrorUio.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/composable/error/FetchErrorUio.kt @@ -5,6 +5,7 @@ import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.Stable +import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.platform.LocalContext import com.pixelized.rplexicon.LocalSnack @@ -17,7 +18,23 @@ sealed class FetchErrorUio { data class Firebase(val exception: Exception) : FetchErrorUio() @Stable - data object Structure : FetchErrorUio() + data class Structure(val type: Type) : FetchErrorUio() { + @Stable + enum class Type { + UNKNOWN, + ACTION, + ALTERATION, + CHARACTER, + DESCRIPTION, + EQUIPMENT, + INVENTORY, + SKILL, + SPELL, + LEXICON, + LOCATION, + QUEST, + } + } @Stable data object Default : FetchErrorUio() @@ -25,32 +42,46 @@ sealed class FetchErrorUio { @Composable fun HandleFetchError( - errors: Flow, - onStructureError: suspend (context: Context, snack: SnackbarHostState, error: FetchErrorUio.Structure) -> Unit = { context, snack, _ -> - snack.showSnackbar(message = context.getString(R.string.error_structure)) + snack: SnackbarHostState = LocalSnack.current, + errors: Flow, + onStructureError: suspend (context: Context, snack: SnackbarHostState, error: FetchErrorUio.Structure) -> Unit = { context, snack, error -> + val messageResources = when (error.type) { + FetchErrorUio.Structure.Type.UNKNOWN -> R.string.error_structure_unknowed + FetchErrorUio.Structure.Type.ACTION -> R.string.error_structure_action + FetchErrorUio.Structure.Type.ALTERATION -> R.string.error_structure_alteration + FetchErrorUio.Structure.Type.CHARACTER -> R.string.error_structure_character + FetchErrorUio.Structure.Type.DESCRIPTION -> R.string.error_structure_description + FetchErrorUio.Structure.Type.EQUIPMENT -> R.string.error_structure_equipment + FetchErrorUio.Structure.Type.INVENTORY -> R.string.error_structure_inventory + FetchErrorUio.Structure.Type.SKILL -> R.string.error_structure_skill + FetchErrorUio.Structure.Type.SPELL -> R.string.error_structure_spell + FetchErrorUio.Structure.Type.LEXICON -> R.string.error_structure_lexicon + FetchErrorUio.Structure.Type.LOCATION -> R.string.error_structure_location + FetchErrorUio.Structure.Type.QUEST -> R.string.error_structure_quest + } + snack.showSnackbar(message = context.getString(messageResources)) + }, + onFirebaseError: suspend (context: Context, snack: SnackbarHostState, error: FetchErrorUio.Firebase) -> Unit = { context, snack, error -> + snack.showSnackbar( + message = error.exception.localizedMessage ?: context.getString(R.string.error_generic) + ) }, onDefaultError: suspend (context: Context, snack: SnackbarHostState, error: FetchErrorUio.Default) -> Unit = { context, snack, _ -> snack.showSnackbar(message = context.getString(R.string.error_generic)) }, ) { val context = LocalContext.current - val snack = LocalSnack.current - - val currentOnStructureError = rememberUpdatedState(newValue = onStructureError) - val currentOnDefaultError = rememberUpdatedState(newValue = onDefaultError) + val currentOnStructureError by rememberUpdatedState(newValue = onStructureError) + val currentOnFirebaseError by rememberUpdatedState(newValue = onFirebaseError) + val currentOnDefaultError by rememberUpdatedState(newValue = onDefaultError) LaunchedEffect(key1 = "HandleFetchError") { errors.collect { error -> when (error) { - is FetchErrorUio.Firebase -> Unit - - is FetchErrorUio.Structure -> currentOnStructureError.value.invoke( - context, snack, error, - ) - - is FetchErrorUio.Default -> currentOnDefaultError.value.invoke( - context, snack, error, - ) + is FetchErrorUio.Firebase -> currentOnFirebaseError.invoke(context, snack, error) + is FetchErrorUio.Structure -> currentOnStructureError.invoke(context, snack, error) + is FetchErrorUio.Default -> currentOnDefaultError.invoke(context, snack, error) + else -> Unit } } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/CharacterSheetScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/CharacterSheetScreen.kt index a556422..2906535 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/CharacterSheetScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/CharacterSheetScreen.kt @@ -41,13 +41,11 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.minimumInteractiveComponentSize import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.Stable import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -63,6 +61,7 @@ import com.pixelized.rplexicon.LocalSnack import com.pixelized.rplexicon.NO_WINDOW_INSETS import com.pixelized.rplexicon.R import com.pixelized.rplexicon.ui.composable.Loader +import com.pixelized.rplexicon.ui.composable.error.HandleFetchError import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost import com.pixelized.rplexicon.ui.screens.character.composable.character.ProficiencyUio.ID.* import com.pixelized.rplexicon.ui.screens.character.composable.character.StatUio.ID.* @@ -181,13 +180,9 @@ fun CharacterSheetScreen( }, ) - LaunchedEffect(key1 = "Error") { - viewModel.errors.collect { error -> - snack.showSnackbar( - message = error.exception.localizedMessage ?: "" - ) - } - } + HandleFetchError( + errors = viewModel.error, + ) BackHandler(enabled = sheetState.isVisible) { scope.launch { sheetState.hide() } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/CharacterSheetViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/CharacterSheetViewModel.kt index 4dc96af..9d2eea6 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/CharacterSheetViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/CharacterSheetViewModel.kt @@ -16,6 +16,7 @@ import com.pixelized.rplexicon.repository.data.character.InventoryRepository import com.pixelized.rplexicon.repository.data.character.SkillRepository import com.pixelized.rplexicon.repository.data.character.SpellRepository import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio +import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio.Structure.Type import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.async @@ -42,8 +43,8 @@ class CharacterSheetViewModel @Inject constructor( private val _isLoading = mutableStateOf(false) val isLoading: State get() = _isLoading - private val _error = MutableSharedFlow() - val errors: SharedFlow get() = _error + private val _error = MutableSharedFlow() + val error: SharedFlow get() = _error val character = savedStateHandle.characterSheetArgument.name @@ -63,92 +64,84 @@ class CharacterSheetViewModel @Inject constructor( suspend fun update(force: Boolean, full: Boolean = false) = coroutineScope { _isLoading.value = true val characters = async { - try { - if (force || characterRepository.lastSuccessFullUpdate.shouldUpdate()) { + if (force || characterRepository.lastSuccessFullUpdate.shouldUpdate()) { + try { characterRepository.fetchCharacterSheet() - } else { - Unit + } catch (exception: Exception) { + Log.e(TAG, exception.message, exception) + _error.emit(FetchErrorUio.Structure(type = Type.CHARACTER)) } - } catch (exception: Exception) { - Log.e(TAG, exception.message, exception) } } val description = async { - try { - if (full && (force || characterRepository.lastSuccessFullUpdate.shouldUpdate())) { + if (full && (force || descriptionRepository.lastSuccessFullUpdate.shouldUpdate())) { + try { descriptionRepository.fetchDescription() - } else { - Unit + } catch (exception: Exception) { + Log.e(TAG, exception.message, exception) + _error.emit(FetchErrorUio.Structure(type = Type.DESCRIPTION)) } - } catch (exception: Exception) { - Log.e(TAG, exception.message, exception) } } val inventory = async { - try { - if (force || inventoryRepository.lastSuccessFullUpdate.shouldUpdate()) { + if (force || inventoryRepository.lastSuccessFullUpdate.shouldUpdate()) { + try { inventoryRepository.fetchInventory() - } else { - Unit + } catch (exception: Exception) { + Log.e(TAG, exception.message, exception) + _error.emit(FetchErrorUio.Structure(type = Type.INVENTORY)) } - } catch (exception: Exception) { - Log.e(TAG, exception.message, exception) } } val equipment = async { - try { - if (force || equipmentRepository.lastSuccessFullUpdate.shouldUpdate()) { + if (force || equipmentRepository.lastSuccessFullUpdate.shouldUpdate()) { + try { equipmentRepository.fetchEquipment() - } else { - Unit + } catch (exception: Exception) { + Log.e(TAG, exception.message, exception) + _error.emit(FetchErrorUio.Structure(type = Type.EQUIPMENT)) } - } catch (exception: Exception) { - Log.e(TAG, exception.message, exception) } } awaitAll(characters) val alterations = async { - try { - if (force || alterationRepository.lastSuccessFullUpdate.shouldUpdate()) { + if (force || alterationRepository.lastSuccessFullUpdate.shouldUpdate()) { + try { alterationRepository.fetchAlterationSheet(sheets = characterRepository.sheets) - } else { - Unit + } catch (exception: Exception) { + Log.e(TAG, exception.message, exception) + _error.emit(FetchErrorUio.Structure(type = Type.ALTERATION)) } - } catch (exception: Exception) { - Log.e(TAG, exception.message, exception) } } val actions = async { - try { - if (force || actionRepository.lastSuccessFullUpdate.shouldUpdate()) { + if (force || actionRepository.lastSuccessFullUpdate.shouldUpdate()) { + try { actionRepository.fetchActions(characters = characterRepository.data.value) - } else { - Unit + } catch (exception: Exception) { + Log.e(TAG, exception.message, exception) + _error.emit(FetchErrorUio.Structure(type = Type.ACTION)) } - } catch (exception: Exception) { - Log.e(TAG, exception.message, exception) } } val spells = async { - try { - if (force || spellRepository.lastSuccessFullUpdate.shouldUpdate()) { + if (force || spellRepository.lastSuccessFullUpdate.shouldUpdate()) { + try { spellRepository.fetchSpells() - } else { - Unit + } catch (exception: Exception) { + Log.e(TAG, exception.message, exception) + _error.emit(FetchErrorUio.Structure(type = Type.SPELL)) } - } catch (exception: Exception) { - Log.e(TAG, exception.message, exception) } } val skill = async { - try { - if (force || skillRepository.lastSuccessFullUpdate.shouldUpdate()) { + if (force || skillRepository.lastSuccessFullUpdate.shouldUpdate()) { + try { skillRepository.fetchSkills() - } else { - Unit + } catch (exception: Exception) { + Log.e(TAG, exception.message, exception) + _error.emit(FetchErrorUio.Structure(type = Type.SKILL)) } - } catch (exception: Exception) { - Log.e(TAG, exception.message, exception) } } awaitAll(description, alterations, inventory, equipment, actions, spells, skill) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconViewModel.kt index 9b0eb49..e07e81e 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconViewModel.kt @@ -101,7 +101,7 @@ class LexiconViewModel @Inject constructor( // the data sheet structure is not as expected catch (exception: IncompatibleSheetStructure) { Log.e(TAG, exception.message, exception) - _error.emit(FetchErrorUio.Structure) + _error.emit(FetchErrorUio.Structure(type = FetchErrorUio.Structure.Type.LEXICON)) } // default exception catch (exception: Exception) { @@ -119,7 +119,7 @@ class LexiconViewModel @Inject constructor( // the data sheet structure is not as expected catch (exception: IncompatibleSheetStructure) { Log.e(TAG, exception.message, exception) - _error.emit(FetchErrorUio.Structure) + _error.emit(FetchErrorUio.Structure(type = FetchErrorUio.Structure.Type.CHARACTER)) } // default exception catch (exception: Exception) { diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationViewModel.kt index 5e3a690..531040b 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationViewModel.kt @@ -56,7 +56,7 @@ class LocationViewModel @Inject constructor( // the data sheet structure is not as expected catch (exception: IncompatibleSheetStructure) { Log.e(TAG, exception.message, exception) - _error.emit(FetchErrorUio.Structure) + _error.emit(FetchErrorUio.Structure(type = FetchErrorUio.Structure.Type.LOCATION)) } // default exception catch (exception: Exception) { diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListViewModel.kt index a79bb8e..df1c590 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListViewModel.kt @@ -57,7 +57,7 @@ class QuestListViewModel @Inject constructor( // the data sheet structure is not as expected catch (exception: IncompatibleSheetStructure) { Log.e(TAG, exception.message, exception) - _error.emit(FetchErrorUio.Structure) + _error.emit(FetchErrorUio.Structure(type = FetchErrorUio.Structure.Type.QUEST)) } // default exception catch (exception: Exception) { diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 08c9e88..7547dbb 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -4,7 +4,18 @@ Fermer Une erreur s\'est produite. - La structure du fichier semble avoir changé et n\'est plus compatible avec cette application. + La structure des données semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille d\'actions semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille d\'altération semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille des personnages semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille de description semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille d\'équipement semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille d\'inventaire semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille des talents semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille des sorts semble avoir changé et n\'est plus compatible avec cette application. + La structure du lexique semble avoir changé et n\'est plus compatible avec cette application. + La structure des cartes semble avoir changé et n\'est plus compatible avec cette application. + La structure des quêtes semble avoir changé et n\'est plus compatible avec cette application. SUCCÈS CRITIQUE ÉCHEC CRITIQUE diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 99297c6..bd1db62 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,8 +3,19 @@ Close - An error occur. - The file structure appears to have changed and is no longer compatible with this application + An error occurred. + The file structure appears to have changed and is no longer compatible with this application + The action sheet structure appears to have changed and is no longer compatible with this application + The alteration sheet structure appears to have changed and is no longer compatible with this application + The character sheet structure appears to have changed and is no longer compatible with this application + The description sheet structure appears to have changed and is no longer compatible with this application + The equipment sheet structure appears to have changed and is no longer compatible with this application + The inventory sheet structure appears to have changed and is no longer compatible with this application + The skill sheet structure appears to have changed and is no longer compatible with this application + The spell sheet structure appears to have changed and is no longer compatible with this application + The lexicon sheet structure appears to have changed and is no longer compatible with this application + The location sheet structure appears to have changed and is no longer compatible with this application + The quest sheet structure appears to have changed and is no longer compatible with this application CRITICAL SUCCESS CRITICAL FAILURE