Rework the data update throughout the app.
This commit is contained in:
parent
cbe945d7f5
commit
b36cb9b601
19 changed files with 323 additions and 121 deletions
|
|
@ -0,0 +1,99 @@
|
||||||
|
package com.pixelized.rplexicon
|
||||||
|
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.pixelized.rplexicon.repository.data.ActionRepository
|
||||||
|
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
||||||
|
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
||||||
|
import com.pixelized.rplexicon.repository.data.LexiconRepository
|
||||||
|
import com.pixelized.rplexicon.repository.data.LocationRepository
|
||||||
|
import com.pixelized.rplexicon.repository.data.QuestRepository
|
||||||
|
import com.pixelized.rplexicon.repository.data.SpellRepository
|
||||||
|
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.launch
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class LauncherViewModel @Inject constructor(
|
||||||
|
lexiconRepository: LexiconRepository,
|
||||||
|
locationRepository: LocationRepository,
|
||||||
|
questRepository: QuestRepository,
|
||||||
|
alterationRepository: AlterationRepository,
|
||||||
|
characterSheetRepository: CharacterSheetRepository,
|
||||||
|
actionRepository: ActionRepository,
|
||||||
|
spellRepository: SpellRepository,
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
|
private val _error = MutableSharedFlow<String>()
|
||||||
|
val error: SharedFlow<String> get() = _error
|
||||||
|
|
||||||
|
var isLoading by mutableStateOf(true)
|
||||||
|
private set
|
||||||
|
|
||||||
|
init {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val lexicon = async {
|
||||||
|
try {
|
||||||
|
lexiconRepository.fetchLexicon()
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
_error.tryEmit("Lexicon fail to update")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val location = async {
|
||||||
|
try {
|
||||||
|
locationRepository.fetchLocation()
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
_error.tryEmit("Location fail to update")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val quest = async {
|
||||||
|
try {
|
||||||
|
questRepository.fetchQuests()
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
_error.tryEmit("Quest fail to update")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val alteration = async {
|
||||||
|
try {
|
||||||
|
alterationRepository.fetchAlterationSheet()
|
||||||
|
alterationRepository.fetchStatusSheet()
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
_error.tryEmit("Alteration fail to update")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val characterSheet = async {
|
||||||
|
try {
|
||||||
|
characterSheetRepository.fetchCharacterSheet()
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
_error.tryEmit("CharacterSheet fail to update")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
awaitAll(lexicon, location, quest, alteration, characterSheet)
|
||||||
|
|
||||||
|
val action = async {
|
||||||
|
try {
|
||||||
|
actionRepository.fetchActions()
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
_error.tryEmit("Action fail to update")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val spell = async {
|
||||||
|
try {
|
||||||
|
spellRepository.fetchSpells()
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
_error.tryEmit("Spell fail to update")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
awaitAll(action, spell)
|
||||||
|
|
||||||
|
isLoading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.activity.viewModels
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
|
|
@ -15,6 +16,7 @@ import androidx.compose.material3.SnackbarHost
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.compositionLocalOf
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.staticCompositionLocalOf
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
|
|
@ -22,6 +24,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.pixelized.rplexicon.ui.composable.BlurredOverlayHost
|
import com.pixelized.rplexicon.ui.composable.BlurredOverlayHost
|
||||||
import com.pixelized.rplexicon.ui.navigation.ScreenNavHost
|
import com.pixelized.rplexicon.ui.navigation.ScreenNavHost
|
||||||
import com.pixelized.rplexicon.ui.screens.rolls.BlurredRollOverlayHostState
|
import com.pixelized.rplexicon.ui.screens.rolls.BlurredRollOverlayHostState
|
||||||
|
|
@ -45,6 +48,9 @@ val NO_WINDOW_INSETS = WindowInsets(0, 0, 0, 0)
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
|
private val launcherViewModel: LauncherViewModel by viewModels()
|
||||||
|
private val rollViewModel: RollOverlayViewModel by viewModels()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
|
@ -53,19 +59,19 @@ class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
// splashscreen management
|
// splashscreen management
|
||||||
installSplashScreen().apply {
|
installSplashScreen().apply {
|
||||||
setKeepOnScreenCondition { false }
|
setKeepOnScreenCondition { launcherViewModel.isLoading }
|
||||||
}
|
}
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
LexiconTheme {
|
LexiconTheme {
|
||||||
val rollViewModel = hiltViewModel<RollOverlayViewModel>()
|
val snack = remember { SnackbarHostState() }
|
||||||
val overlay = rememberBlurredRollOverlayHostState(
|
val overlay = rememberBlurredRollOverlayHostState(
|
||||||
viewModel = rollViewModel,
|
viewModel = rollViewModel,
|
||||||
)
|
)
|
||||||
|
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalActivity provides this,
|
LocalActivity provides this,
|
||||||
LocalSnack provides remember { SnackbarHostState() },
|
LocalSnack provides snack,
|
||||||
LocalRollOverlay provides overlay,
|
LocalRollOverlay provides overlay,
|
||||||
) {
|
) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
|
@ -101,6 +107,12 @@ class MainActivity : ComponentActivity() {
|
||||||
overlay.hideOverlay()
|
overlay.hideOverlay()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(key1 = "LauncherError") {
|
||||||
|
launcherViewModel.error.collect {
|
||||||
|
snack.showSnackbar(message = it)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.pixelized.rplexicon.repository.data
|
||||||
import com.pixelized.rplexicon.repository.parser.AttackParser
|
import com.pixelized.rplexicon.repository.parser.AttackParser
|
||||||
import com.pixelized.rplexicon.model.Attack
|
import com.pixelized.rplexicon.model.Attack
|
||||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||||
|
import com.pixelized.rplexicon.utilitary.Update
|
||||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
@ -18,6 +19,9 @@ class ActionRepository @Inject constructor(
|
||||||
private val _data = MutableStateFlow<Map<String, List<Attack>>>(emptyMap())
|
private val _data = MutableStateFlow<Map<String, List<Attack>>>(emptyMap())
|
||||||
val data: StateFlow<Map<String, List<Attack>>> get() = _data
|
val data: StateFlow<Map<String, List<Attack>>> get() = _data
|
||||||
|
|
||||||
|
var lastSuccessFullUpdate: Update = Update.INITIAL
|
||||||
|
private set
|
||||||
|
|
||||||
fun find(name: String?): List<Attack>? {
|
fun find(name: String?): List<Attack>? {
|
||||||
return name?.let { _data.value[it] }
|
return name?.let { _data.value[it] }
|
||||||
}
|
}
|
||||||
|
|
@ -31,6 +35,7 @@ class ActionRepository @Inject constructor(
|
||||||
charactersSheets = characterSheetRepository.data.value
|
charactersSheets = characterSheetRepository.data.value
|
||||||
)
|
)
|
||||||
_data.emit(data)
|
_data.emit(data)
|
||||||
|
lastSuccessFullUpdate = Update.currentTime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ import com.pixelized.rplexicon.model.Alteration
|
||||||
import com.pixelized.rplexicon.model.Counter
|
import com.pixelized.rplexicon.model.Counter
|
||||||
import com.pixelized.rplexicon.model.Property
|
import com.pixelized.rplexicon.model.Property
|
||||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||||
|
import com.pixelized.rplexicon.utilitary.Update
|
||||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
@ -29,6 +30,12 @@ class AlterationRepository @Inject constructor(
|
||||||
private val _counter = MutableStateFlow<Map<String, List<Counter>>>(emptyMap())
|
private val _counter = MutableStateFlow<Map<String, List<Counter>>>(emptyMap())
|
||||||
val counter: StateFlow<Map<String, List<Counter>>> get() = _counter
|
val counter: StateFlow<Map<String, List<Counter>>> get() = _counter
|
||||||
|
|
||||||
|
var lastAlterationSuccessFullUpdate: Update = Update.INITIAL
|
||||||
|
private set
|
||||||
|
|
||||||
|
var lastStatusSuccessFullUpdate: Update = Update.INITIAL
|
||||||
|
private set
|
||||||
|
|
||||||
fun getAlterations(character: String): List<Alteration> {
|
fun getAlterations(character: String): List<Alteration> {
|
||||||
return assignedAlterations.value[character]?.mapNotNull { alterationName ->
|
return assignedAlterations.value[character]?.mapNotNull { alterationName ->
|
||||||
alterationsLexicon.value.firstOrNull { it.name == alterationName }
|
alterationsLexicon.value.firstOrNull { it.name == alterationName }
|
||||||
|
|
@ -49,6 +56,7 @@ class AlterationRepository @Inject constructor(
|
||||||
val request = sheet.get(Sheet.Character.ID, Sheet.Character.ALTERATION)
|
val request = sheet.get(Sheet.Character.ID, Sheet.Character.ALTERATION)
|
||||||
val data = alterationParser.parse(value = request.execute())
|
val data = alterationParser.parse(value = request.execute())
|
||||||
_alterationsLexicon.emit(data)
|
_alterationsLexicon.emit(data)
|
||||||
|
lastAlterationSuccessFullUpdate = Update.currentTime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,6 +68,7 @@ class AlterationRepository @Inject constructor(
|
||||||
_assignedAlterations.emit(status)
|
_assignedAlterations.emit(status)
|
||||||
val counter = counterParser.parse(values = request.execute())
|
val counter = counterParser.parse(values = request.execute())
|
||||||
_counter.emit(counter)
|
_counter.emit(counter)
|
||||||
|
lastStatusSuccessFullUpdate = Update.currentTime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package com.pixelized.rplexicon.repository.data
|
||||||
import com.pixelized.rplexicon.repository.parser.CharacterSheetParser
|
import com.pixelized.rplexicon.repository.parser.CharacterSheetParser
|
||||||
import com.pixelized.rplexicon.model.CharacterSheet
|
import com.pixelized.rplexicon.model.CharacterSheet
|
||||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||||
|
import com.pixelized.rplexicon.utilitary.Update
|
||||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
@ -17,6 +18,13 @@ class CharacterSheetRepository @Inject constructor(
|
||||||
private val _data = MutableStateFlow<Map<String, CharacterSheet>>(emptyMap())
|
private val _data = MutableStateFlow<Map<String, CharacterSheet>>(emptyMap())
|
||||||
val data: StateFlow<Map<String, CharacterSheet>> get() = _data
|
val data: StateFlow<Map<String, CharacterSheet>> get() = _data
|
||||||
|
|
||||||
|
var lastSuccessFullUpdate: Update = Update.INITIAL
|
||||||
|
private set
|
||||||
|
|
||||||
|
fun haveSheet(name: String?): Boolean {
|
||||||
|
return _data.value.containsKey(name)
|
||||||
|
}
|
||||||
|
|
||||||
fun find(name: String?): CharacterSheet? {
|
fun find(name: String?): CharacterSheet? {
|
||||||
return name?.let { _data.value[name] }
|
return name?.let { _data.value[name] }
|
||||||
}
|
}
|
||||||
|
|
@ -27,6 +35,7 @@ class CharacterSheetRepository @Inject constructor(
|
||||||
val request = sheet.get(Sheet.Character.ID, Sheet.Character.CHARACTER)
|
val request = sheet.get(Sheet.Character.ID, Sheet.Character.CHARACTER)
|
||||||
val data = characterSheetParser.parse(value = request.execute())
|
val data = characterSheetParser.parse(value = request.execute())
|
||||||
_data.emit(data)
|
_data.emit(data)
|
||||||
|
lastSuccessFullUpdate = Update.currentTime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package com.pixelized.rplexicon.repository.data
|
||||||
import com.pixelized.rplexicon.repository.parser.LexiconParser
|
import com.pixelized.rplexicon.repository.parser.LexiconParser
|
||||||
import com.pixelized.rplexicon.model.Lexicon
|
import com.pixelized.rplexicon.model.Lexicon
|
||||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||||
|
import com.pixelized.rplexicon.utilitary.Update
|
||||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
@ -17,6 +18,9 @@ class LexiconRepository @Inject constructor(
|
||||||
private val _data = MutableStateFlow<List<Lexicon>>(emptyList())
|
private val _data = MutableStateFlow<List<Lexicon>>(emptyList())
|
||||||
val data: StateFlow<List<Lexicon>> get() = _data
|
val data: StateFlow<List<Lexicon>> get() = _data
|
||||||
|
|
||||||
|
var lastSuccessFullUpdate: Update = Update.INITIAL
|
||||||
|
private set
|
||||||
|
|
||||||
fun findId(name: String?): Int? {
|
fun findId(name: String?): Int? {
|
||||||
return name?.let { _data.value.firstOrNull { item -> item.name == it }?.id }
|
return name?.let { _data.value.firstOrNull { item -> item.name == it }?.id }
|
||||||
}
|
}
|
||||||
|
|
@ -27,6 +31,8 @@ class LexiconRepository @Inject constructor(
|
||||||
val request = sheet.get(Sheet.Lexicon.ID, Sheet.Lexicon.LEXICON)
|
val request = sheet.get(Sheet.Lexicon.ID, Sheet.Lexicon.LEXICON)
|
||||||
val data = lexiconParser.parse(data = request.execute())
|
val data = lexiconParser.parse(data = request.execute())
|
||||||
_data.tryEmit(data)
|
_data.tryEmit(data)
|
||||||
|
|
||||||
|
lastSuccessFullUpdate = Update.currentTime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ import com.pixelized.rplexicon.repository.parser.LocationParser
|
||||||
import com.pixelized.rplexicon.repository.parser.MarqueeParser
|
import com.pixelized.rplexicon.repository.parser.MarqueeParser
|
||||||
import com.pixelized.rplexicon.model.Location
|
import com.pixelized.rplexicon.model.Location
|
||||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||||
|
import com.pixelized.rplexicon.utilitary.Update
|
||||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
|
|
@ -22,6 +23,9 @@ class LocationRepository @Inject constructor(
|
||||||
private val _data = MutableStateFlow<List<Location>>(emptyList())
|
private val _data = MutableStateFlow<List<Location>>(emptyList())
|
||||||
val data: StateFlow<List<Location>> get() = _data
|
val data: StateFlow<List<Location>> get() = _data
|
||||||
|
|
||||||
|
var lastSuccessFullUpdate: Update = Update.INITIAL
|
||||||
|
private set
|
||||||
|
|
||||||
fun findId(name: String?): Int? {
|
fun findId(name: String?): Int? {
|
||||||
return name?.let { _data.value.firstOrNull { item -> item.name == it }?.id }
|
return name?.let { _data.value.firstOrNull { item -> item.name == it }?.id }
|
||||||
}
|
}
|
||||||
|
|
@ -34,6 +38,7 @@ class LocationRepository @Inject constructor(
|
||||||
async { sheet.get(Sheet.Lexicon.ID, Sheet.Lexicon.MARQUEE).execute() },
|
async { sheet.get(Sheet.Lexicon.ID, Sheet.Lexicon.MARQUEE).execute() },
|
||||||
)
|
)
|
||||||
updateData(map = map, marquee = marquee)
|
updateData(map = map, marquee = marquee)
|
||||||
|
lastSuccessFullUpdate = Update.currentTime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.google.api.services.sheets.v4.model.ValueRange
|
||||||
import com.pixelized.rplexicon.repository.parser.QuestParser
|
import com.pixelized.rplexicon.repository.parser.QuestParser
|
||||||
import com.pixelized.rplexicon.model.Quest
|
import com.pixelized.rplexicon.model.Quest
|
||||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||||
|
import com.pixelized.rplexicon.utilitary.Update
|
||||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
@ -18,12 +19,16 @@ class QuestRepository @Inject constructor(
|
||||||
private val _data = MutableStateFlow<List<Quest>>(emptyList())
|
private val _data = MutableStateFlow<List<Quest>>(emptyList())
|
||||||
val data: StateFlow<List<Quest>> get() = _data
|
val data: StateFlow<List<Quest>> get() = _data
|
||||||
|
|
||||||
|
var lastSuccessFullUpdate: Update = Update.INITIAL
|
||||||
|
private set
|
||||||
|
|
||||||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||||
suspend fun fetchQuests() {
|
suspend fun fetchQuests() {
|
||||||
googleRepository.fetch { sheet ->
|
googleRepository.fetch { sheet ->
|
||||||
val request = sheet.get(Sheet.Lexicon.ID, Sheet.Lexicon.QUEST_JOURNAL)
|
val request = sheet.get(Sheet.Lexicon.ID, Sheet.Lexicon.QUEST_JOURNAL)
|
||||||
val data = request.execute()
|
val data = request.execute()
|
||||||
updateData(data = data)
|
updateData(data = data)
|
||||||
|
lastSuccessFullUpdate = Update.currentTime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import com.pixelized.rplexicon.repository.parser.spell.SpellBookParser
|
||||||
import com.pixelized.rplexicon.model.AssignedSpell
|
import com.pixelized.rplexicon.model.AssignedSpell
|
||||||
import com.pixelized.rplexicon.model.Spell
|
import com.pixelized.rplexicon.model.Spell
|
||||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||||
|
import com.pixelized.rplexicon.utilitary.Update
|
||||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
|
|
@ -23,6 +24,9 @@ class SpellRepository @Inject constructor(
|
||||||
private val _spells = MutableStateFlow<Map<String, List<AssignedSpell>>>(emptyMap())
|
private val _spells = MutableStateFlow<Map<String, List<AssignedSpell>>>(emptyMap())
|
||||||
val spells: StateFlow<Map<String, List<AssignedSpell>>> get() = _spells
|
val spells: StateFlow<Map<String, List<AssignedSpell>>> get() = _spells
|
||||||
|
|
||||||
|
var lastSuccessFullUpdate: Update = Update.INITIAL
|
||||||
|
private set
|
||||||
|
|
||||||
fun findAssignedSpells(character: String?): List<AssignedSpell>? {
|
fun findAssignedSpells(character: String?): List<AssignedSpell>? {
|
||||||
return character?.let { _spells.value[it] }
|
return character?.let { _spells.value[it] }
|
||||||
}
|
}
|
||||||
|
|
@ -42,6 +46,7 @@ class SpellRepository @Inject constructor(
|
||||||
val assignedSpells = assignedSpellParser.parse(data = magic, spells = spellsBook)
|
val assignedSpells = assignedSpellParser.parse(data = magic, spells = spellsBook)
|
||||||
this@SpellRepository.spellsBook = spellsBook
|
this@SpellRepository.spellsBook = spellsBook
|
||||||
_spells.emit(assignedSpells)
|
_spells.emit(assignedSpells)
|
||||||
|
lastSuccessFullUpdate = Update.currentTime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -91,7 +91,7 @@ fun CharacterSheetScreen(
|
||||||
)
|
)
|
||||||
val refresh = rememberPullRefreshState(
|
val refresh = rememberPullRefreshState(
|
||||||
refreshing = false,
|
refreshing = false,
|
||||||
onRefresh = { scope.launch { viewModel.update() } },
|
onRefresh = { scope.launch { viewModel.update(force = true) } },
|
||||||
)
|
)
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
|
@ -107,7 +107,7 @@ fun CharacterSheetScreen(
|
||||||
sheetState = sheetState,
|
sheetState = sheetState,
|
||||||
refreshState = refresh,
|
refreshState = refresh,
|
||||||
onRefresh = {
|
onRefresh = {
|
||||||
scope.launch { viewModel.update() }
|
scope.launch { viewModel.update(force = true) }
|
||||||
},
|
},
|
||||||
onBack = {
|
onBack = {
|
||||||
screen.popBackStack()
|
screen.popBackStack()
|
||||||
|
|
|
||||||
|
|
@ -41,53 +41,79 @@ class CharacterSheetViewModel @Inject constructor(
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
characterRepository.data.collect { sheets ->
|
launch {
|
||||||
_header.value = withContext(Dispatchers.Default) {
|
characterRepository.data.collect { sheets ->
|
||||||
headerFactory.convert(model = sheets.getValue(character))
|
_header.value = withContext(Dispatchers.Default) {
|
||||||
|
headerFactory.convert(model = sheets.getValue(character))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
launch {
|
||||||
|
update(force = false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun update() = coroutineScope {
|
suspend fun update(force: Boolean) = coroutineScope {
|
||||||
_isLoading.value = true
|
_isLoading.value = true
|
||||||
val characterRequest = async {
|
val characterRequest = async {
|
||||||
try {
|
try {
|
||||||
characterRepository.fetchCharacterSheet()
|
if (force || characterRepository.lastSuccessFullUpdate.shouldUpdate()) {
|
||||||
actionRepository.fetchActions()
|
characterRepository.fetchCharacterSheet()
|
||||||
} catch (exception: Exception) {
|
} else {
|
||||||
Log.e(TAG, exception.message, exception)
|
Unit
|
||||||
}
|
}
|
||||||
}
|
|
||||||
val statusRequest = async {
|
|
||||||
try {
|
|
||||||
alterationRepository.fetchStatusSheet()
|
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.e(TAG, exception.message, exception)
|
Log.e(TAG, exception.message, exception)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val alterationRequest = async {
|
val alterationRequest = async {
|
||||||
try {
|
try {
|
||||||
alterationRepository.fetchAlterationSheet()
|
if (force || alterationRepository.lastAlterationSuccessFullUpdate.shouldUpdate()) {
|
||||||
|
alterationRepository.fetchAlterationSheet()
|
||||||
|
} else {
|
||||||
|
Unit
|
||||||
|
}
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.e(TAG, exception.message, exception)
|
Log.e(TAG, exception.message, exception)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val statusRequest = async {
|
||||||
|
try {
|
||||||
|
if (force || alterationRepository.lastStatusSuccessFullUpdate.shouldUpdate()) {
|
||||||
|
alterationRepository.fetchStatusSheet()
|
||||||
|
} else {
|
||||||
|
Unit
|
||||||
|
}
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
Log.e(TAG, exception.message, exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
awaitAll(characterRequest, statusRequest, alterationRequest)
|
||||||
|
|
||||||
val actionRequest = async {
|
val actionRequest = async {
|
||||||
try {
|
try {
|
||||||
actionRepository.fetchActions()
|
if (force || actionRepository.lastSuccessFullUpdate.shouldUpdate()) {
|
||||||
|
actionRepository.fetchActions()
|
||||||
|
} else {
|
||||||
|
Unit
|
||||||
|
}
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.e(TAG, exception.message, exception)
|
Log.e(TAG, exception.message, exception)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val spellRequest = async {
|
val spellRequest = async {
|
||||||
try {
|
try {
|
||||||
spellRepository.fetchSpells()
|
if (force || spellRepository.lastSuccessFullUpdate.shouldUpdate()) {
|
||||||
|
spellRepository.fetchSpells()
|
||||||
|
} else {
|
||||||
|
Unit
|
||||||
|
}
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.e(TAG, exception.message, exception)
|
Log.e(TAG, exception.message, exception)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
awaitAll(characterRequest, statusRequest, alterationRequest, actionRequest, spellRequest)
|
awaitAll(actionRequest, spellRequest)
|
||||||
_isLoading.value = false
|
_isLoading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.pixelized.rplexicon.R
|
import com.pixelized.rplexicon.R
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
|
import com.pixelized.rplexicon.utilitary.LOS_FULL
|
||||||
import com.pixelized.rplexicon.utilitary.LOS_HOLLOW
|
import com.pixelized.rplexicon.utilitary.LOS_HOLLOW
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.cell
|
import com.pixelized.rplexicon.utilitary.extentions.cell
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||||
|
|
@ -38,6 +39,7 @@ data class LexiconItemUio(
|
||||||
val diminutive: String?,
|
val diminutive: String?,
|
||||||
@StringRes val gender: Int,
|
@StringRes val gender: Int,
|
||||||
@StringRes val race: Int,
|
@StringRes val race: Int,
|
||||||
|
val isPlayingCharacter: Boolean = false,
|
||||||
val placeholder: Boolean = false,
|
val placeholder: Boolean = false,
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
@ -48,6 +50,7 @@ data class LexiconItemUio(
|
||||||
diminutive: String? = null,
|
diminutive: String? = null,
|
||||||
@StringRes gender: Int = R.string.gender_female_short,
|
@StringRes gender: Int = R.string.gender_female_short,
|
||||||
@StringRes race: Int = R.string.race_half_orc,
|
@StringRes race: Int = R.string.race_half_orc,
|
||||||
|
isPlayingCharacter: Boolean = false,
|
||||||
placeholder: Boolean = false,
|
placeholder: Boolean = false,
|
||||||
) = LexiconItemUio(
|
) = LexiconItemUio(
|
||||||
id = id,
|
id = id,
|
||||||
|
|
@ -55,6 +58,7 @@ data class LexiconItemUio(
|
||||||
diminutive = diminutive,
|
diminutive = diminutive,
|
||||||
gender = gender,
|
gender = gender,
|
||||||
race = race,
|
race = race,
|
||||||
|
isPlayingCharacter = isPlayingCharacter,
|
||||||
placeholder = placeholder,
|
placeholder = placeholder,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -79,7 +83,7 @@ fun LexiconItem(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.alignByBaseline()
|
.alignByBaseline()
|
||||||
.placeholder { item.placeholder },
|
.placeholder { item.placeholder },
|
||||||
text = LOS_HOLLOW,
|
text = if (item.isPlayingCharacter) LOS_FULL else LOS_HOLLOW,
|
||||||
)
|
)
|
||||||
|
|
||||||
FlowRow(
|
FlowRow(
|
||||||
|
|
@ -172,6 +176,7 @@ private class LexiconItemPreviewProvider : PreviewParameterProvider<LexiconItemU
|
||||||
name = "Mundas-Naltum-Brulkhai-Arauishi",
|
name = "Mundas-Naltum-Brulkhai-Arauishi",
|
||||||
diminutive = "Mun-Nalt-Bru-Arahi",
|
diminutive = "Mun-Nalt-Bru-Arahi",
|
||||||
placeholder = false,
|
placeholder = false,
|
||||||
|
isPlayingCharacter = true,
|
||||||
),
|
),
|
||||||
LexiconItemUio.preview(
|
LexiconItemUio.preview(
|
||||||
name = "Brulkhai",
|
name = "Brulkhai",
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ fun LexiconScreen(
|
||||||
refreshing = false,
|
refreshing = false,
|
||||||
onRefresh = {
|
onRefresh = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
viewModel.updateLexicon()
|
viewModel.updateLexicon(force = true)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -91,7 +91,7 @@ fun LexiconScreen(
|
||||||
HandleFetchError(
|
HandleFetchError(
|
||||||
errors = viewModel.error,
|
errors = viewModel.error,
|
||||||
onPermissionGranted = {
|
onPermissionGranted = {
|
||||||
viewModel.updateLexicon()
|
viewModel.updateLexicon(force = true)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -27,9 +28,6 @@ import javax.inject.Inject
|
||||||
class LexiconViewModel @Inject constructor(
|
class LexiconViewModel @Inject constructor(
|
||||||
private val lexiconRepository: LexiconRepository,
|
private val lexiconRepository: LexiconRepository,
|
||||||
private val characterSheetRepository: CharacterSheetRepository,
|
private val characterSheetRepository: CharacterSheetRepository,
|
||||||
private val alterationRepository: AlterationRepository,
|
|
||||||
private val actionRepository: ActionRepository,
|
|
||||||
private val spellRepository: SpellRepository,
|
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _isLoading = mutableStateOf(false)
|
private val _isLoading = mutableStateOf(false)
|
||||||
|
|
@ -43,98 +41,97 @@ class LexiconViewModel @Inject constructor(
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
lexiconRepository.data.collect { items ->
|
launch {
|
||||||
_items.value = items.map { item ->
|
lexiconRepository.data.collect { items ->
|
||||||
LexiconItemUio(
|
_items.value = items
|
||||||
id = item.id,
|
.sortedBy { it.name }
|
||||||
name = item.name,
|
.sortedBy { !characterSheetRepository.haveSheet(it.name) }
|
||||||
diminutive = item.diminutive?.takeIf { it.isNotBlank() }?.let { "./ $it" },
|
.map { item ->
|
||||||
gender = when (item.gender) {
|
LexiconItemUio(
|
||||||
Lexicon.Gender.MALE -> R.string.gender_male_short
|
id = item.id,
|
||||||
Lexicon.Gender.FEMALE -> R.string.gender_female_short
|
name = item.name,
|
||||||
Lexicon.Gender.UNDETERMINED -> R.string.gender_undetermined_short
|
diminutive = item.diminutive?.takeIf { it.isNotBlank() }
|
||||||
},
|
?.let { "./ $it" },
|
||||||
race = when (item.race) {
|
gender = when (item.gender) {
|
||||||
Lexicon.Race.ELF -> R.string.race_elf
|
Lexicon.Gender.MALE -> R.string.gender_male_short
|
||||||
Lexicon.Race.HALFLING -> R.string.race_halfling
|
Lexicon.Gender.FEMALE -> R.string.gender_female_short
|
||||||
Lexicon.Race.HUMAN -> R.string.race_human
|
Lexicon.Gender.UNDETERMINED -> R.string.gender_undetermined_short
|
||||||
Lexicon.Race.DWARF -> R.string.race_dwarf
|
},
|
||||||
Lexicon.Race.HALF_ELF -> R.string.race_half_elf
|
race = when (item.race) {
|
||||||
Lexicon.Race.HALF_ORC -> R.string.race_half_orc
|
Lexicon.Race.ELF -> R.string.race_elf
|
||||||
Lexicon.Race.DRAGONBORN -> R.string.race_dragonborn
|
Lexicon.Race.HALFLING -> R.string.race_halfling
|
||||||
Lexicon.Race.GNOME -> R.string.race_gnome
|
Lexicon.Race.HUMAN -> R.string.race_human
|
||||||
Lexicon.Race.TIEFLING -> R.string.race_tiefling
|
Lexicon.Race.DWARF -> R.string.race_dwarf
|
||||||
Lexicon.Race.AARAKOCRA -> R.string.race_aarakocra
|
Lexicon.Race.HALF_ELF -> R.string.race_half_elf
|
||||||
Lexicon.Race.GENASI -> R.string.race_genasi
|
Lexicon.Race.HALF_ORC -> R.string.race_half_orc
|
||||||
Lexicon.Race.DEEP_GNOME -> R.string.race_deep_gnome
|
Lexicon.Race.DRAGONBORN -> R.string.race_dragonborn
|
||||||
Lexicon.Race.GOLIATH -> R.string.race_goliath
|
Lexicon.Race.GNOME -> R.string.race_gnome
|
||||||
Lexicon.Race.UNDETERMINED -> R.string.race_undetermined
|
Lexicon.Race.TIEFLING -> R.string.race_tiefling
|
||||||
},
|
Lexicon.Race.AARAKOCRA -> R.string.race_aarakocra
|
||||||
)
|
Lexicon.Race.GENASI -> R.string.race_genasi
|
||||||
}.sortedBy { it.name }
|
Lexicon.Race.DEEP_GNOME -> R.string.race_deep_gnome
|
||||||
}
|
Lexicon.Race.GOLIATH -> R.string.race_goliath
|
||||||
}
|
Lexicon.Race.UNDETERMINED -> R.string.race_undetermined
|
||||||
|
},
|
||||||
viewModelScope.launch {
|
isPlayingCharacter = characterSheetRepository.haveSheet(item.name)
|
||||||
_isLoading.value = true
|
)
|
||||||
val characterRequest = async {
|
}
|
||||||
try {
|
|
||||||
characterSheetRepository.fetchCharacterSheet()
|
|
||||||
actionRepository.fetchActions()
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
Log.e(TAG, exception.message, exception)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val alterationRequest = async {
|
launch {
|
||||||
try {
|
updateLexicon(force = false)
|
||||||
alterationRepository.fetchAlterationSheet()
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
Log.e(TAG, exception.message, exception)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val statusRequest = async {
|
|
||||||
try {
|
|
||||||
alterationRepository.fetchStatusSheet()
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
Log.e(TAG, exception.message, exception)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val magicRequest = async {
|
|
||||||
try {
|
|
||||||
spellRepository.fetchSpells()
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
Log.e(TAG, exception.message, exception)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val lexiconRequest = async {
|
|
||||||
fetchLexicon()
|
|
||||||
}
|
|
||||||
awaitAll(
|
|
||||||
characterRequest,
|
|
||||||
alterationRequest,
|
|
||||||
statusRequest,
|
|
||||||
lexiconRequest,
|
|
||||||
magicRequest,
|
|
||||||
)
|
|
||||||
_isLoading.value = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateLexicon() {
|
suspend fun updateLexicon(force: Boolean) = coroutineScope {
|
||||||
_isLoading.value = true
|
_isLoading.value = true
|
||||||
fetchLexicon()
|
val lexicon = async {
|
||||||
|
fetchLexicon(force = force)
|
||||||
|
}
|
||||||
|
val sheets = async {
|
||||||
|
fetchCharacterSheet(force = force)
|
||||||
|
}
|
||||||
|
awaitAll(lexicon, sheets)
|
||||||
_isLoading.value = false
|
_isLoading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun fetchLexicon() {
|
private suspend fun fetchLexicon(force: Boolean) {
|
||||||
try {
|
try {
|
||||||
lexiconRepository.fetchLexicon()
|
if (force || lexiconRepository.lastSuccessFullUpdate.shouldUpdate()) {
|
||||||
|
lexiconRepository.fetchLexicon()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// user need to accept OAuth2 permission.
|
// user need to accept OAuth2 permission.
|
||||||
catch (exception: UserRecoverableAuthIOException) {
|
catch (exception: UserRecoverableAuthIOException) {
|
||||||
Log.e(TAG, exception.message, exception)
|
Log.e(TAG, exception.message, exception)
|
||||||
_error.emit(FetchErrorUio.Permission(intent = exception.intent))
|
_error.emit(FetchErrorUio.Permission(intent = exception.intent))
|
||||||
} catch (exception: IncompatibleSheetStructure) {
|
}
|
||||||
|
// the data sheet structure is not as expected
|
||||||
|
catch (exception: IncompatibleSheetStructure) {
|
||||||
|
Log.e(TAG, exception.message, exception)
|
||||||
|
_error.emit(FetchErrorUio.Structure)
|
||||||
|
}
|
||||||
|
// default exception
|
||||||
|
catch (exception: Exception) {
|
||||||
|
Log.e(TAG, exception.message, exception)
|
||||||
|
_error.emit(FetchErrorUio.Default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun fetchCharacterSheet(force: Boolean) {
|
||||||
|
try {
|
||||||
|
if (force || characterSheetRepository.lastSuccessFullUpdate.shouldUpdate()) {
|
||||||
|
characterSheetRepository.fetchCharacterSheet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// user need to accept OAuth2 permission.
|
||||||
|
catch (exception: UserRecoverableAuthIOException) {
|
||||||
|
Log.e(TAG, exception.message, exception)
|
||||||
|
_error.emit(FetchErrorUio.Permission(intent = exception.intent))
|
||||||
|
}
|
||||||
|
// the data sheet structure is not as expected
|
||||||
|
catch (exception: IncompatibleSheetStructure) {
|
||||||
Log.e(TAG, exception.message, exception)
|
Log.e(TAG, exception.message, exception)
|
||||||
_error.emit(FetchErrorUio.Structure)
|
_error.emit(FetchErrorUio.Structure)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package com.pixelized.rplexicon.ui.screens.location.list
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import androidx.compose.animation.AnimatedContent
|
import androidx.compose.animation.AnimatedContent
|
||||||
import androidx.compose.animation.ExperimentalAnimationApi
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
|
@ -48,7 +47,7 @@ fun LocationScreen(
|
||||||
refreshing = false,
|
refreshing = false,
|
||||||
onRefresh = {
|
onRefresh = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
viewModel.fetchLocation()
|
viewModel.update(force = true)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -67,7 +66,7 @@ fun LocationScreen(
|
||||||
HandleFetchError(
|
HandleFetchError(
|
||||||
errors = viewModel.error,
|
errors = viewModel.error,
|
||||||
onPermissionGranted = {
|
onPermissionGranted = {
|
||||||
viewModel.fetchLocation()
|
viewModel.update(force = true)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,15 +42,17 @@ class LocationViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
launch {
|
launch {
|
||||||
fetchLocation()
|
update(force = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun fetchLocation() {
|
suspend fun update(force: Boolean) {
|
||||||
|
_isLoading.value = true
|
||||||
try {
|
try {
|
||||||
_isLoading.value = true
|
if (force || repository.lastSuccessFullUpdate.shouldUpdate()) {
|
||||||
repository.fetchLocation()
|
repository.fetchLocation()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// user need to accept OAuth2 permission.
|
// user need to accept OAuth2 permission.
|
||||||
catch (exception: UserRecoverableAuthIOException) {
|
catch (exception: UserRecoverableAuthIOException) {
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,6 @@ package com.pixelized.rplexicon.ui.screens.quest.list
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import androidx.compose.animation.AnimatedContent
|
import androidx.compose.animation.AnimatedContent
|
||||||
import androidx.compose.animation.ExperimentalAnimationApi
|
|
||||||
import androidx.compose.animation.fadeIn
|
|
||||||
import androidx.compose.animation.fadeOut
|
|
||||||
import androidx.compose.animation.togetherWith
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
|
@ -51,7 +47,7 @@ fun QuestListScreen(
|
||||||
refreshing = false,
|
refreshing = false,
|
||||||
onRefresh = {
|
onRefresh = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
viewModel.fetchQuests()
|
viewModel.update(force = true)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -70,7 +66,7 @@ fun QuestListScreen(
|
||||||
HandleFetchError(
|
HandleFetchError(
|
||||||
errors = viewModel.error,
|
errors = viewModel.error,
|
||||||
onPermissionGranted = {
|
onPermissionGranted = {
|
||||||
viewModel.fetchQuests()
|
viewModel.update(force = true)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,15 +43,17 @@ class QuestListViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
launch {
|
launch {
|
||||||
fetchQuests()
|
update(force = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun fetchQuests() {
|
suspend fun update(force: Boolean) {
|
||||||
|
_isLoading.value = true
|
||||||
try {
|
try {
|
||||||
_isLoading.value = true
|
if (force || repository.lastSuccessFullUpdate.shouldUpdate()) {
|
||||||
repository.fetchQuests()
|
repository.fetchQuests()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// user need to accept OAuth2 permission.
|
// user need to accept OAuth2 permission.
|
||||||
catch (exception: UserRecoverableAuthIOException) {
|
catch (exception: UserRecoverableAuthIOException) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.pixelized.rplexicon.utilitary
|
||||||
|
|
||||||
|
|
||||||
|
@JvmInline
|
||||||
|
value class Update(private val value: Long) {
|
||||||
|
|
||||||
|
fun shouldUpdate(): Boolean {
|
||||||
|
return System.currentTimeMillis() - value > DELTA
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val DELTA = 5 * 60 * 1000
|
||||||
|
|
||||||
|
val INITIAL = Update(0)
|
||||||
|
|
||||||
|
fun currentTime(): Update {
|
||||||
|
return Update(System.currentTimeMillis())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue