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,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)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue