Convert the AdventureDetailScreen to flow instead of snapshot.

This commit is contained in:
Andres Gomez, Thomas (ITDV RL) 2024-06-21 14:06:50 +02:00
parent acb76e72cf
commit e62b558c21
4 changed files with 106 additions and 51 deletions

View file

@ -17,8 +17,10 @@ import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -32,7 +34,7 @@ class AdventureRepository @Inject constructor(
private val adventureStoryLineParser: AdventureStoryLineParser, private val adventureStoryLineParser: AdventureStoryLineParser,
private val adventureDboFactory: AdventureDboFactory, private val adventureDboFactory: AdventureDboFactory,
) { ) {
val adventure = database.adventureDao().let { database -> private val adventures = database.adventureDao().let { database ->
combine( combine(
database.getBooksFlow(), database.getBooksFlow(),
database.getStoriesFlow(), database.getStoriesFlow(),
@ -50,6 +52,31 @@ class AdventureRepository @Inject constructor(
) )
} }
fun bookFlow(): Flow<List<Adventure>> {
return adventures
}
fun storyFlow(
bookTitle: String,
): Flow<List<Adventure>> {
return adventures.map { adventures ->
adventures.filter { adventure ->
adventure.bookTitle == bookTitle
}
}
}
fun adventureFlow(
bookTitle: String,
adventureTitle: String,
): Flow<Adventure?> {
return adventures.map { adventures ->
adventures.firstOrNull { adventure ->
adventure.bookTitle == bookTitle && adventure.storyTitle == adventureTitle
}
}
}
@Throws(IncompatibleSheetStructure::class, Exception::class) @Throws(IncompatibleSheetStructure::class, Exception::class)
suspend fun fetchBooks() { suspend fun fetchBooks() {
val database = database.adventureDao() val database = database.adventureDao()
@ -177,18 +204,6 @@ class AdventureRepository @Inject constructor(
) )
} }
fun find(bookTitle: String): List<Adventure> {
return adventure.value.filter { adventure ->
adventure.bookTitle == bookTitle
}
}
fun find(bookTitle: String, adventureTitle: String): Adventure? {
return adventure.value.firstOrNull { adventure ->
adventure.bookTitle == bookTitle && adventure.storyTitle == adventureTitle
}
}
@Throws(IncompatibleSheetStructure::class, Exception::class) @Throws(IncompatibleSheetStructure::class, Exception::class)
private suspend fun fetchAdventureBooks(): List<AdventureBook> { private suspend fun fetchAdventureBooks(): List<AdventureBook> {
return googleRepository.fetch { sheet -> return googleRepository.fetch { sheet ->

View file

@ -29,7 +29,7 @@ class AdventureBooksViewModel @Inject constructor(
private val _isLoading = mutableStateOf(false) private val _isLoading = mutableStateOf(false)
val isLoading: State<Boolean> get() = _isLoading val isLoading: State<Boolean> get() = _isLoading
private val _books = adventureRepository.adventure private val _books = adventureRepository.bookFlow()
.map { adventures -> .map { adventures ->
adventures adventures
.map { adventure -> .map { adventure ->

View file

@ -36,7 +36,7 @@ class AdventureStoriesViewModel @Inject constructor(
argument.bookTitle argument.bookTitle
} }
private val _chapters = adventureRepository.adventure private val _chapters = adventureRepository.storyFlow(bookTitle = argument.bookTitle)
.map { adventures -> .map { adventures ->
adventures adventures
.filter { it.bookTitle == argument.bookTitle && it.documentId == argument.documentId } .filter { it.bookTitle == argument.bookTitle && it.documentId == argument.documentId }

View file

@ -1,14 +1,22 @@
package com.pixelized.rplexicon.ui.screens.adventure.detail package com.pixelized.rplexicon.ui.screens.adventure.detail
import android.net.Uri
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember
import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pixelized.rplexicon.data.model.adventure.AdventureLine.Format import com.pixelized.rplexicon.data.model.adventure.AdventureLine.Format
import com.pixelized.rplexicon.data.repository.adventure.AdventureRepository import com.pixelized.rplexicon.data.repository.adventure.AdventureRepository
import com.pixelized.rplexicon.ui.navigation.screens.adventureDetailArgument import com.pixelized.rplexicon.ui.navigation.screens.adventureDetailArgument
import com.pixelized.rplexicon.ui.screens.adventure.detail.AdventureLineUio.Style import com.pixelized.rplexicon.ui.screens.adventure.detail.AdventureLineUio.Style
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
@ -17,44 +25,76 @@ class AdventureDetailViewModel @Inject constructor(
savedStateHandle: SavedStateHandle, savedStateHandle: SavedStateHandle,
) : ViewModel() { ) : ViewModel() {
private val argument = savedStateHandle.adventureDetailArgument private val argument = savedStateHandle.adventureDetailArgument
private val _detail = mutableStateOf(
adventureRepository.find( private val detail = adventureRepository.adventureFlow(
bookTitle = argument.bookTitle, bookTitle = argument.bookTitle,
adventureTitle = argument.adventureTitle, adventureTitle = argument.adventureTitle,
) ).stateIn(
scope = viewModelScope,
started = SharingStarted.Lazily,
initialValue = null,
) )
val background = derivedStateOf { val background: State<Uri?>
_detail.value?.storyBackground @Composable
} get() = remember(detail) {
detail.map { it?.storyBackground }
}.collectAsState(initial = null)
val adventure = derivedStateOf { val adventure: State<List<AdventureLineUio>>
_detail.value?.story?.map { line -> @Composable
AdventureLineUio( get() = remember(detail) {
text = line.text, detail
style = when (line.format) { .map { adventure ->
Format.TITLE -> Style.TITLE adventure?.story?.map { line ->
Format.SUB_TITLE -> Style.SUB_TITLE AdventureLineUio(
Format.CHAPTER -> Style.CHAPTER text = line.text,
Format.PARAGRAPH -> Style.PARAGRAPH style = when (line.format) {
Format.DIALOGUE -> Style.DIALOGUE Format.TITLE -> Style.TITLE
Format.ANNEX -> Style.ANNEX Format.SUB_TITLE -> Style.SUB_TITLE
Format.LEGEND -> Style.LEGEND Format.CHAPTER -> Style.CHAPTER
}, Format.PARAGRAPH -> Style.PARAGRAPH
) Format.DIALOGUE -> Style.DIALOGUE
} ?: emptyList() Format.ANNEX -> Style.ANNEX
} Format.LEGEND -> Style.LEGEND
},
)
} ?: emptyList()
}
}.collectAsState(initial = emptyList())
private val titleCell = derivedStateOf { private val titleCell: State<AdventureLineUio?>
adventure.value.let { adventures -> @Composable
adventures.firstOrNull { it.style == Style.TITLE } get() = adventure.let { state ->
?: adventures.firstOrNull() remember(state) {
derivedStateOf {
state.value.let { adventures ->
adventures.firstOrNull { it.style == Style.TITLE }
?: adventures.firstOrNull()
}
}
}
}
val title: State<String>
@Composable
get() = titleCell.let { state ->
remember(state) {
derivedStateOf {
state.value?.text ?: ""
}
}
}
val titleIndex: State<Int>
@Composable
get() {
val cell = titleCell
val adv = adventure
return remember(cell, adv) {
derivedStateOf {
adv.value.indexOf(cell.value)
}
}
} }
}
val title = derivedStateOf {
titleCell.value?.text ?: ""
}
val titleIndex = derivedStateOf {
adventure.value.indexOf(titleCell.value)
}
} }