Convert the AdventureDetailScreen to flow instead of snapshot.
This commit is contained in:
parent
acb76e72cf
commit
e62b558c21
4 changed files with 106 additions and 51 deletions
|
|
@ -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 ->
|
||||||
|
|
|
||||||
|
|
@ -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 ->
|
||||||
|
|
|
||||||
|
|
@ -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 }
|
||||||
|
|
|
||||||
|
|
@ -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,19 +25,28 @@ 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
|
||||||
|
get() = remember(detail) {
|
||||||
|
detail
|
||||||
|
.map { adventure ->
|
||||||
|
adventure?.story?.map { line ->
|
||||||
AdventureLineUio(
|
AdventureLineUio(
|
||||||
text = line.text,
|
text = line.text,
|
||||||
style = when (line.format) {
|
style = when (line.format) {
|
||||||
|
|
@ -44,17 +61,40 @@ class AdventureDetailViewModel @Inject constructor(
|
||||||
)
|
)
|
||||||
} ?: emptyList()
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
|
}.collectAsState(initial = emptyList())
|
||||||
|
|
||||||
private val titleCell = derivedStateOf {
|
private val titleCell: State<AdventureLineUio?>
|
||||||
adventure.value.let { adventures ->
|
@Composable
|
||||||
|
get() = adventure.let { state ->
|
||||||
|
remember(state) {
|
||||||
|
derivedStateOf {
|
||||||
|
state.value.let { adventures ->
|
||||||
adventures.firstOrNull { it.style == Style.TITLE }
|
adventures.firstOrNull { it.style == Style.TITLE }
|
||||||
?: adventures.firstOrNull()
|
?: adventures.firstOrNull()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val title = derivedStateOf {
|
|
||||||
titleCell.value?.text ?: ""
|
|
||||||
}
|
}
|
||||||
val titleIndex = derivedStateOf {
|
}
|
||||||
adventure.value.indexOf(titleCell.value)
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue