Add a refresh feature for the adventure detail (was already flow <3)
This commit is contained in:
parent
5a1cedf4ff
commit
03671792d6
10 changed files with 148 additions and 54 deletions
|
|
@ -67,12 +67,12 @@ class AdventureRepository @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun adventureFlow(
|
fun adventureFlow(
|
||||||
bookTitle: String,
|
documentId: String,
|
||||||
adventureTitle: String,
|
adventureTitle: String,
|
||||||
): Flow<Adventure?> {
|
): Flow<Adventure?> {
|
||||||
return adventures.map { adventures ->
|
return adventures.map { adventures ->
|
||||||
adventures.firstOrNull { adventure ->
|
adventures.firstOrNull { adventure ->
|
||||||
adventure.bookTitle == bookTitle && adventure.storyTitle == adventureTitle
|
adventure.documentId == documentId && adventure.storyTitle == adventureTitle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -204,6 +204,35 @@ class AdventureRepository @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||||
|
suspend fun fetchAdventure(
|
||||||
|
documentId: String,
|
||||||
|
storyTitle: String,
|
||||||
|
) {
|
||||||
|
val database = database.adventureDao()
|
||||||
|
|
||||||
|
val lines = fetchAdventureLine(
|
||||||
|
documentId = documentId,
|
||||||
|
storyTitle = storyTitle,
|
||||||
|
).mapIndexed { index, line ->
|
||||||
|
adventureDboFactory.convertToDbo(
|
||||||
|
adventureLine = line,
|
||||||
|
index = index,
|
||||||
|
documentId = documentId,
|
||||||
|
storyTitle = storyTitle,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
database.update(
|
||||||
|
booksToRemove = emptyList(),
|
||||||
|
storiesToRemove = emptyList(),
|
||||||
|
linesToRemove = emptyList(),
|
||||||
|
books = emptyList(),
|
||||||
|
stories = emptyList(),
|
||||||
|
lines = lines,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@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 ->
|
||||||
|
|
|
||||||
|
|
@ -14,22 +14,22 @@ import com.pixelized.rplexicon.ui.screens.adventure.detail.AdventureDetailScreen
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.string.ARG
|
import com.pixelized.rplexicon.utilitary.extentions.string.ARG
|
||||||
|
|
||||||
private const val ROUTE = "adventureDetail"
|
private const val ROUTE = "adventureDetail"
|
||||||
private const val BOOK_TITLE_ARG = "bookTitle"
|
private const val DOCUMENT_ID_ARG = "documentId"
|
||||||
private const val ADVENTURE_TITLE_ARG = "adventureTitle"
|
private const val ADVENTURE_TITLE_ARG = "adventureTitle"
|
||||||
|
|
||||||
val ADVENTURE_DETAIL_ROUTE = "$ROUTE?${BOOK_TITLE_ARG.ARG}&${ADVENTURE_TITLE_ARG.ARG}"
|
val ADVENTURE_DETAIL_ROUTE = "$ROUTE?${DOCUMENT_ID_ARG.ARG}&${ADVENTURE_TITLE_ARG.ARG}"
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
@Immutable
|
@Immutable
|
||||||
class AdventureDetailArgument(
|
class AdventureDetailArgument(
|
||||||
val bookTitle: String,
|
val documentId: String,
|
||||||
val adventureTitle: String,
|
val adventureTitle: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
val SavedStateHandle.adventureDetailArgument: AdventureDetailArgument
|
val SavedStateHandle.adventureDetailArgument: AdventureDetailArgument
|
||||||
get() = AdventureDetailArgument(
|
get() = AdventureDetailArgument(
|
||||||
bookTitle = get(BOOK_TITLE_ARG)
|
documentId = get(DOCUMENT_ID_ARG)
|
||||||
?: error("AdventureDetailArgument missing argument: $BOOK_TITLE_ARG"),
|
?: error("AdventureDetailArgument missing argument: $DOCUMENT_ID_ARG"),
|
||||||
adventureTitle = get(ADVENTURE_TITLE_ARG)
|
adventureTitle = get(ADVENTURE_TITLE_ARG)
|
||||||
?: error("AdventureDetailArgument missing argument: $ADVENTURE_TITLE_ARG"),
|
?: error("AdventureDetailArgument missing argument: $ADVENTURE_TITLE_ARG"),
|
||||||
)
|
)
|
||||||
|
|
@ -39,7 +39,7 @@ fun NavGraphBuilder.composableAdventureDetail() {
|
||||||
route = ADVENTURE_DETAIL_ROUTE,
|
route = ADVENTURE_DETAIL_ROUTE,
|
||||||
animation = NavigationAnimation.Push,
|
animation = NavigationAnimation.Push,
|
||||||
arguments = listOf(
|
arguments = listOf(
|
||||||
navArgument(name = BOOK_TITLE_ARG) {
|
navArgument(name = DOCUMENT_ID_ARG) {
|
||||||
type = NavType.StringType
|
type = NavType.StringType
|
||||||
nullable = false
|
nullable = false
|
||||||
},
|
},
|
||||||
|
|
@ -54,10 +54,10 @@ fun NavGraphBuilder.composableAdventureDetail() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun NavHostController.navigateToAdventureDetail(
|
fun NavHostController.navigateToAdventureDetail(
|
||||||
bookTitle: String,
|
documentId: String,
|
||||||
adventureTitle: String,
|
adventureTitle: String,
|
||||||
option: NavOptionsBuilder.() -> Unit = {},
|
option: NavOptionsBuilder.() -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val route = "$ROUTE?$BOOK_TITLE_ARG=$bookTitle&$ADVENTURE_TITLE_ARG=$adventureTitle"
|
val route = "$ROUTE?$DOCUMENT_ID_ARG=$documentId&$ADVENTURE_TITLE_ARG=$adventureTitle"
|
||||||
navigate(route = route, builder = option)
|
navigate(route = route, builder = option)
|
||||||
}
|
}
|
||||||
|
|
@ -29,7 +29,6 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.shadow
|
import androidx.compose.ui.draw.shadow
|
||||||
|
|
@ -44,7 +43,6 @@ import com.pixelized.rplexicon.ui.composable.rememberAnimatedShadow
|
||||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||||
import com.pixelized.rplexicon.ui.navigation.screens.navigateToAdventureChapters
|
import com.pixelized.rplexicon.ui.navigation.screens.navigateToAdventureChapters
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -52,12 +50,9 @@ fun AdventureBooksScreen(
|
||||||
viewModel: AdventureBooksViewModel = hiltViewModel(),
|
viewModel: AdventureBooksViewModel = hiltViewModel(),
|
||||||
) {
|
) {
|
||||||
val screen = LocalScreenNavHost.current
|
val screen = LocalScreenNavHost.current
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
val refresh = rememberPullRefreshState(
|
val refresh = rememberPullRefreshState(
|
||||||
refreshing = false,
|
refreshing = false,
|
||||||
onRefresh = {
|
onRefresh = { viewModel.update() },
|
||||||
scope.launch { viewModel.update() }
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Surface(
|
Surface(
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,8 @@ class AdventureBooksViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun update() {
|
fun update() {
|
||||||
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
_isLoading.value = true
|
_isLoading.value = true
|
||||||
|
|
@ -73,3 +74,4 @@ class AdventureBooksViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -32,6 +32,7 @@ sealed class AdventureStoriesUio {
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class AdventureItem(
|
data class AdventureItem(
|
||||||
|
val documentId: String,
|
||||||
val bookTitle: String,
|
val bookTitle: String,
|
||||||
val adventureTitle: String,
|
val adventureTitle: String,
|
||||||
) : AdventureStoriesUio()
|
) : AdventureStoriesUio()
|
||||||
|
|
@ -110,6 +111,7 @@ private fun AdventureChapterItemPreview() {
|
||||||
Surface {
|
Surface {
|
||||||
AdventureChapterItem(
|
AdventureChapterItem(
|
||||||
item = AdventureStoriesUio.AdventureItem(
|
item = AdventureStoriesUio.AdventureItem(
|
||||||
|
documentId = "",
|
||||||
bookTitle = "Les chroniques d'une orc",
|
bookTitle = "Les chroniques d'une orc",
|
||||||
adventureTitle = "La traque",
|
adventureTitle = "La traque",
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -50,12 +50,9 @@ fun AdventureStoriesScreen(
|
||||||
viewModel: AdventureStoriesViewModel = hiltViewModel(),
|
viewModel: AdventureStoriesViewModel = hiltViewModel(),
|
||||||
) {
|
) {
|
||||||
val screen = LocalScreenNavHost.current
|
val screen = LocalScreenNavHost.current
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
val refresh = rememberPullRefreshState(
|
val refresh = rememberPullRefreshState(
|
||||||
refreshing = false,
|
refreshing = false,
|
||||||
onRefresh = {
|
onRefresh = { viewModel.update() },
|
||||||
scope.launch { viewModel.update() }
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Surface(
|
Surface(
|
||||||
|
|
@ -71,7 +68,7 @@ fun AdventureStoriesScreen(
|
||||||
chapters = viewModel.chapters,
|
chapters = viewModel.chapters,
|
||||||
onChapter = {
|
onChapter = {
|
||||||
screen.navigateToAdventureDetail(
|
screen.navigateToAdventureDetail(
|
||||||
bookTitle = it.bookTitle,
|
documentId = it.documentId,
|
||||||
adventureTitle = it.adventureTitle
|
adventureTitle = it.adventureTitle
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -118,7 +115,9 @@ private fun AdventureChapterContent(
|
||||||
contentAlignment = Alignment.TopCenter,
|
contentAlignment = Alignment.TopCenter,
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier.pullRefresh(state = refreshState),
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.pullRefresh(state = refreshState),
|
||||||
state = lazyListState,
|
state = lazyListState,
|
||||||
contentPadding = paddingValues,
|
contentPadding = paddingValues,
|
||||||
verticalArrangement = Arrangement.spacedBy(space = 8.dp),
|
verticalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||||
|
|
@ -176,6 +175,7 @@ private fun AdventureChapterPreview() {
|
||||||
mutableStateOf(
|
mutableStateOf(
|
||||||
listOf(
|
listOf(
|
||||||
AdventureStoriesUio.AdventureItem(
|
AdventureStoriesUio.AdventureItem(
|
||||||
|
documentId = "",
|
||||||
bookTitle = "Les chroniques d'une orc",
|
bookTitle = "Les chroniques d'une orc",
|
||||||
adventureTitle = "Biographie",
|
adventureTitle = "Biographie",
|
||||||
),
|
),
|
||||||
|
|
@ -183,30 +183,37 @@ private fun AdventureChapterPreview() {
|
||||||
title = "Mémoire d'une orc",
|
title = "Mémoire d'une orc",
|
||||||
),
|
),
|
||||||
AdventureStoriesUio.AdventureItem(
|
AdventureStoriesUio.AdventureItem(
|
||||||
|
documentId = "",
|
||||||
bookTitle = "Les chroniques d'une orc",
|
bookTitle = "Les chroniques d'une orc",
|
||||||
adventureTitle = "La traque",
|
adventureTitle = "La traque",
|
||||||
),
|
),
|
||||||
AdventureStoriesUio.AdventureItem(
|
AdventureStoriesUio.AdventureItem(
|
||||||
|
documentId = "",
|
||||||
bookTitle = "Les chroniques d'une orc",
|
bookTitle = "Les chroniques d'une orc",
|
||||||
adventureTitle = "Les six mercenaires",
|
adventureTitle = "Les six mercenaires",
|
||||||
),
|
),
|
||||||
AdventureStoriesUio.AdventureItem(
|
AdventureStoriesUio.AdventureItem(
|
||||||
|
documentId = "",
|
||||||
bookTitle = "Les chroniques d'une orc",
|
bookTitle = "Les chroniques d'une orc",
|
||||||
adventureTitle = "La couronne de cuivre",
|
adventureTitle = "La couronne de cuivre",
|
||||||
),
|
),
|
||||||
AdventureStoriesUio.AdventureItem(
|
AdventureStoriesUio.AdventureItem(
|
||||||
|
documentId = "",
|
||||||
bookTitle = "Les chroniques d'une orc",
|
bookTitle = "Les chroniques d'une orc",
|
||||||
adventureTitle = "Le seigneur tout puissant",
|
adventureTitle = "Le seigneur tout puissant",
|
||||||
),
|
),
|
||||||
AdventureStoriesUio.AdventureItem(
|
AdventureStoriesUio.AdventureItem(
|
||||||
|
documentId = "",
|
||||||
bookTitle = "Les chroniques d'une orc",
|
bookTitle = "Les chroniques d'une orc",
|
||||||
adventureTitle = "Vague à l'Amn",
|
adventureTitle = "Vague à l'Amn",
|
||||||
),
|
),
|
||||||
AdventureStoriesUio.AdventureItem(
|
AdventureStoriesUio.AdventureItem(
|
||||||
|
documentId = "",
|
||||||
bookTitle = "Tu parles d'une galère",
|
bookTitle = "Tu parles d'une galère",
|
||||||
adventureTitle = "Tu parles d'une galère",
|
adventureTitle = "Tu parles d'une galère",
|
||||||
),
|
),
|
||||||
AdventureStoriesUio.AdventureItem(
|
AdventureStoriesUio.AdventureItem(
|
||||||
|
documentId = "",
|
||||||
bookTitle = "Les chroniques d'une orc",
|
bookTitle = "Les chroniques d'une orc",
|
||||||
adventureTitle = "Liberté",
|
adventureTitle = "Liberté",
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
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.repository.adventure.AdventureRepository
|
import com.pixelized.rplexicon.data.repository.adventure.AdventureRepository
|
||||||
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
|
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
|
||||||
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio.Structure
|
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio.Structure
|
||||||
|
|
@ -17,6 +18,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
@ -47,6 +49,7 @@ class AdventureStoriesViewModel @Inject constructor(
|
||||||
)
|
)
|
||||||
val stories = entry.value.map {
|
val stories = entry.value.map {
|
||||||
AdventureStoriesUio.AdventureItem(
|
AdventureStoriesUio.AdventureItem(
|
||||||
|
documentId = it.documentId,
|
||||||
bookTitle = it.bookTitle,
|
bookTitle = it.bookTitle,
|
||||||
adventureTitle = it.storyTitle,
|
adventureTitle = it.storyTitle,
|
||||||
)
|
)
|
||||||
|
|
@ -60,7 +63,8 @@ class AdventureStoriesViewModel @Inject constructor(
|
||||||
@Stable
|
@Stable
|
||||||
get() = _chapters.collectAsState(initial = emptyList())
|
get() = _chapters.collectAsState(initial = emptyList())
|
||||||
|
|
||||||
suspend fun update() {
|
fun update() {
|
||||||
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
_isLoading.value = true
|
_isLoading.value = true
|
||||||
|
|
@ -79,3 +83,4 @@ class AdventureStoriesViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package com.pixelized.rplexicon.ui.screens.adventure.detail
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
|
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
|
@ -15,6 +16,8 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Refresh
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
|
|
@ -29,6 +32,7 @@ import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.mutableFloatStateOf
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.produceState
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.Saver
|
import androidx.compose.runtime.saveable.Saver
|
||||||
import androidx.compose.runtime.saveable.mapSaver
|
import androidx.compose.runtime.saveable.mapSaver
|
||||||
|
|
@ -74,11 +78,13 @@ fun AdventureDetailScreen(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.navigationBarsPadding(),
|
.navigationBarsPadding(),
|
||||||
|
isLoading = viewModel.isLoading,
|
||||||
background = viewModel.background,
|
background = viewModel.background,
|
||||||
title = viewModel.title,
|
title = viewModel.title,
|
||||||
titleIndex = viewModel.titleIndex,
|
titleIndex = viewModel.titleIndex,
|
||||||
adventures = viewModel.adventure,
|
adventures = viewModel.adventure,
|
||||||
onBack = { screen.popBackStack() },
|
onBack = { screen.popBackStack() },
|
||||||
|
onRefresh = { viewModel.update() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -100,11 +106,13 @@ private fun AdventureDetailContent(
|
||||||
bottom = 16.dp,
|
bottom = 16.dp,
|
||||||
),
|
),
|
||||||
lazyListState: LazyListState = rememberLazyListState(),
|
lazyListState: LazyListState = rememberLazyListState(),
|
||||||
|
isLoading: State<Boolean>,
|
||||||
title: State<String?>,
|
title: State<String?>,
|
||||||
titleIndex: State<Int>,
|
titleIndex: State<Int>,
|
||||||
background: State<Uri?>,
|
background: State<Uri?>,
|
||||||
adventures: State<List<AdventureLineUio>>,
|
adventures: State<List<AdventureLineUio>>,
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
|
onRefresh: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val nestedScrollOffset = rememberSaveable { mutableFloatStateOf(0f) }
|
val nestedScrollOffset = rememberSaveable { mutableFloatStateOf(0f) }
|
||||||
val titleLayoutInfo = rememberSaveable(stateSaver = TitleLayoutInfoSaver) {
|
val titleLayoutInfo = rememberSaveable(stateSaver = TitleLayoutInfoSaver) {
|
||||||
|
|
@ -183,6 +191,17 @@ private fun AdventureDetailContent(
|
||||||
text = title.value ?: "",
|
text = title.value ?: "",
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
actions = {
|
||||||
|
IconButton(
|
||||||
|
onClick = onRefresh,
|
||||||
|
enabled = isLoading.value.not(),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Refresh,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = lazyListState,
|
state = lazyListState,
|
||||||
|
|
@ -251,6 +270,9 @@ private fun AdventureDetailPreview() {
|
||||||
LexiconTheme {
|
LexiconTheme {
|
||||||
Surface {
|
Surface {
|
||||||
AdventureDetailContent(
|
AdventureDetailContent(
|
||||||
|
isLoading = remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
},
|
||||||
title = remember {
|
title = remember {
|
||||||
mutableStateOf("La traque")
|
mutableStateOf("La traque")
|
||||||
},
|
},
|
||||||
|
|
@ -321,6 +343,7 @@ private fun AdventureDetailPreview() {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onBack = { },
|
onBack = { },
|
||||||
|
onRefresh = { },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.collectAsState
|
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.compose.runtime.remember
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
@ -14,20 +15,23 @@ 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.Dispatchers
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class AdventureDetailViewModel @Inject constructor(
|
class AdventureDetailViewModel @Inject constructor(
|
||||||
adventureRepository: AdventureRepository,
|
private val adventureRepository: AdventureRepository,
|
||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val argument = savedStateHandle.adventureDetailArgument
|
private val argument = savedStateHandle.adventureDetailArgument
|
||||||
|
|
||||||
private val detail = adventureRepository.adventureFlow(
|
private val detail = adventureRepository.adventureFlow(
|
||||||
bookTitle = argument.bookTitle,
|
documentId = argument.documentId,
|
||||||
adventureTitle = argument.adventureTitle,
|
adventureTitle = argument.adventureTitle,
|
||||||
).stateIn(
|
).stateIn(
|
||||||
scope = viewModelScope,
|
scope = viewModelScope,
|
||||||
|
|
@ -35,6 +39,9 @@ class AdventureDetailViewModel @Inject constructor(
|
||||||
initialValue = null,
|
initialValue = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val _isLoading = mutableStateOf(false)
|
||||||
|
val isLoading: State<Boolean> get() = _isLoading
|
||||||
|
|
||||||
val background: State<Uri?>
|
val background: State<Uri?>
|
||||||
@Composable
|
@Composable
|
||||||
get() = remember(detail) {
|
get() = remember(detail) {
|
||||||
|
|
@ -97,4 +104,26 @@ class AdventureDetailViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun update() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
_isLoading.value = true
|
||||||
|
}
|
||||||
|
withContext(Dispatchers.Default) {
|
||||||
|
adventureRepository.fetchAdventure(
|
||||||
|
documentId = argument.documentId,
|
||||||
|
storyTitle = argument.adventureTitle,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (_: Exception) {
|
||||||
|
//_error.emit(value = Structure(ADVENTURE))
|
||||||
|
} finally {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
_isLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -94,13 +94,15 @@ fun rememberPaddingValues(
|
||||||
SUB_TITLE -> 0.dp
|
SUB_TITLE -> 0.dp
|
||||||
|
|
||||||
CHAPTER -> when (previous?.style) {
|
CHAPTER -> when (previous?.style) {
|
||||||
TITLE -> 64.dp
|
TITLE -> 48.dp
|
||||||
|
SUB_TITLE -> 48.dp
|
||||||
else -> 32.dp
|
else -> 32.dp
|
||||||
}
|
}
|
||||||
|
|
||||||
PARAGRAPH -> when (previous?.style) {
|
PARAGRAPH -> when (previous?.style) {
|
||||||
PARAGRAPH -> 8.dp
|
PARAGRAPH -> 8.dp
|
||||||
TITLE -> 64.dp
|
TITLE -> 48.dp
|
||||||
|
SUB_TITLE -> 48.dp
|
||||||
else -> 16.dp
|
else -> 16.dp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue