diff --git a/src/main/kotlin/ca/gosyer/data/server/ServerService.kt b/src/main/kotlin/ca/gosyer/data/server/ServerService.kt index 59e34507..fa2b9731 100644 --- a/src/main/kotlin/ca/gosyer/data/server/ServerService.kt +++ b/src/main/kotlin/ca/gosyer/data/server/ServerService.kt @@ -37,7 +37,7 @@ class ServerService @Inject constructor( } ) private val runtime = Runtime.getRuntime() - var process: Process? = null + private var process: Process? = null fun startAnyway() { initialized.value = ServerResult.UNUSED diff --git a/src/main/kotlin/ca/gosyer/ui/base/components/LoadingScreen.kt b/src/main/kotlin/ca/gosyer/ui/base/components/LoadingScreen.kt index 4a0a9ff3..9d556bdd 100644 --- a/src/main/kotlin/ca/gosyer/ui/base/components/LoadingScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/base/components/LoadingScreen.kt @@ -33,8 +33,10 @@ fun LoadingScreen( val size = remember(maxHeight, maxWidth) { min(maxHeight, maxWidth) / 2 } + // Workaround for random `Cannot round NaN value.` exception + val floatProgress = progress ?: 0F if (progress != null) { - CircularProgressIndicator(progress, Modifier.align(Alignment.Center).size(size)) + CircularProgressIndicator(floatProgress, Modifier.align(Alignment.Center).size(size)) } else { CircularProgressIndicator(Modifier.align(Alignment.Center).size(size)) } diff --git a/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenu.kt b/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenu.kt index 71cd537d..a85f9c53 100644 --- a/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenu.kt +++ b/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenu.kt @@ -95,7 +95,7 @@ fun SourcesMenu(bundle: Bundle, onMangaClick: (Long) -> Unit) { val selectedSource: Source? = selectedSourceTab BundleScope(selectedSource?.id.toString(), autoDispose = false) { if (selectedSource != null) { - SourceScreen(selectedSource, onMangaClick) + SourceScreen(it, selectedSource, onMangaClick) } else { SourceHomeScreen(isLoading, sources, serverUrl, vm::addTab) } diff --git a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreen.kt b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreen.kt index ebfe5663..9b2de4c7 100644 --- a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreen.kt @@ -28,16 +28,16 @@ import ca.gosyer.ui.base.components.MangaGridItem import ca.gosyer.ui.base.vm.viewModel import ca.gosyer.util.compose.persistentLazyListState import com.github.zsoltk.compose.savedinstancestate.Bundle -import com.github.zsoltk.compose.savedinstancestate.LocalSavedInstanceState @Composable fun SourceScreen( + bundle: Bundle, source: Source, onMangaClick: (Long) -> Unit ) { - val bundle = LocalSavedInstanceState.current val vm = viewModel() remember(source.id) { + vm.removeOldSource() vm.init(source, bundle) } val mangas by vm.mangas.collectAsState() @@ -51,6 +51,7 @@ fun SourceScreen( mangas, loading, hasNextPage, + source.supportsLatest, isLatest, serverUrl, onLoadNextPage = vm::loadNextPage, @@ -65,13 +66,14 @@ private fun MangaTable( mangas: List, isLoading: Boolean = false, hasNextPage: Boolean = false, + supportsLatest: Boolean, isLatest: Boolean, serverUrl: String, onLoadNextPage: () -> Unit, onMangaClick: (Long) -> Unit, onClickMode: (Boolean) -> Unit ) { - if (mangas.isEmpty()) { + if (isLoading || mangas.isEmpty()) { LoadingScreen(isLoading) } else { Column { @@ -84,12 +86,14 @@ private fun MangaTable( ) { Text(text = if (isLoading) "Loading..." else "Load next page") } - Button( - onClick = { onClickMode(!isLatest) }, - enabled = !isLoading, - modifier = Modifier.align(Alignment.TopEnd) - ) { - Text(text = if (isLatest) "Latest" else "Browse") + if (supportsLatest) { + Button( + onClick = { onClickMode(!isLatest) }, + enabled = !isLoading, + modifier = Modifier.align(Alignment.TopEnd) + ) { + Text(text = if (isLatest) "To Browse" else "To Latest") + } } } diff --git a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreenViewModel.kt b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreenViewModel.kt index ece80ffb..24cd763d 100644 --- a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreenViewModel.kt +++ b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreenViewModel.kt @@ -10,12 +10,13 @@ import ca.gosyer.data.models.Manga import ca.gosyer.data.models.MangaPage import ca.gosyer.data.models.Source import ca.gosyer.data.server.ServerPreferences -import ca.gosyer.data.server.interactions.MangaInteractionHandler import ca.gosyer.data.server.interactions.SourceInteractionHandler import ca.gosyer.ui.base.vm.ViewModel import ca.gosyer.util.compose.getJsonObjectArray import ca.gosyer.util.compose.putJsonObjectArray +import ca.gosyer.util.lang.seconds import com.github.zsoltk.compose.savedinstancestate.Bundle +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.drop @@ -26,11 +27,10 @@ import javax.inject.Inject class SourceScreenViewModel @Inject constructor( private val sourceHandler: SourceInteractionHandler, - private val mangaHandler: MangaInteractionHandler, serverPreferences: ServerPreferences ) : ViewModel() { private lateinit var source: Source - private lateinit var bundle: Bundle + private var bundle: Bundle? = null val serverUrl = serverPreferences.server().stateIn(scope) @@ -52,36 +52,43 @@ class SourceScreenViewModel @Inject constructor( init { _mangas.drop(1) .onEach { manga -> - bundle.putJsonObjectArray(MANGAS_KEY, manga) + bundle?.putJsonObjectArray(MANGAS_KEY, manga) } .launchIn(scope) _hasNextPage.drop(1) .onEach { - bundle.putBoolean(NEXT_PAGE_KEY, it) + bundle?.putBoolean(NEXT_PAGE_KEY, it) } .launchIn(scope) _pageNum.drop(1) .onEach { - bundle.putInt(PAGE_NUM_KEY, it) + bundle?.putInt(PAGE_NUM_KEY, it) } .launchIn(scope) } - fun init(source: Source, bundle: Bundle) { - this.source = source - this.bundle = bundle + fun removeOldSource() { + bundle = null + _loading.value = true + _isLatest.value = true + _mangas.value = emptyList() + _hasNextPage.value = false + _pageNum.value = 1 + } + + fun init(source: Source, bundle: Bundle, toLatest: Boolean = source.supportsLatest) { scope.launch { - _loading.value = true - _mangas.value = emptyList() - _hasNextPage.value = false + delay(0.5.seconds) + this@SourceScreenViewModel.source = source + this@SourceScreenViewModel.bundle = bundle _pageNum.value = bundle.getInt(PAGE_NUM_KEY, 1) - _isLatest.value = bundle.getBoolean(IS_LATEST_KEY, source.supportsLatest) + _isLatest.value = bundle.getBoolean(IS_LATEST_KEY, toLatest) val page = bundle.getJsonObjectArray(MANGAS_KEY) ?.let { MangaPage(it.filterNotNull(), bundle.getBoolean(NEXT_PAGE_KEY, true)) } ?: getPage() - _mangas.value += page.mangaList + _mangas.value = page.mangaList _hasNextPage.value = page.hasNextPage _loading.value = false } @@ -99,13 +106,13 @@ class SourceScreenViewModel @Inject constructor( } fun setMode(toLatest: Boolean) { + val bundle = bundle ?: return if (isLatest.value != toLatest) { - _isLatest.value = toLatest bundle.remove(MANGAS_KEY) bundle.remove(NEXT_PAGE_KEY) bundle.remove(PAGE_NUM_KEY) bundle.remove(IS_LATEST_KEY) - init(source, bundle) + init(source, bundle, toLatest) } } @@ -117,7 +124,7 @@ class SourceScreenViewModel @Inject constructor( } } - companion object { + private companion object { const val MANGAS_KEY = "mangas" const val NEXT_PAGE_KEY = "next_page" const val PAGE_NUM_KEY = "next_page"