mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Convert extension details to full Compose
This commit is contained in:
		| @@ -11,6 +11,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource | ||||
| import androidx.compose.foundation.layout.Arrangement | ||||
| import androidx.compose.foundation.layout.Box | ||||
| import androidx.compose.foundation.layout.Column | ||||
| import androidx.compose.foundation.layout.PaddingValues | ||||
| import androidx.compose.foundation.layout.Row | ||||
| import androidx.compose.foundation.layout.Spacer | ||||
| import androidx.compose.foundation.layout.WindowInsets | ||||
| @@ -20,9 +21,12 @@ import androidx.compose.foundation.layout.height | ||||
| import androidx.compose.foundation.layout.navigationBars | ||||
| import androidx.compose.foundation.layout.padding | ||||
| import androidx.compose.foundation.layout.size | ||||
| import androidx.compose.foundation.layout.statusBarsPadding | ||||
| import androidx.compose.foundation.layout.width | ||||
| import androidx.compose.foundation.lazy.items | ||||
| import androidx.compose.material.icons.Icons | ||||
| import androidx.compose.material.icons.outlined.HelpOutline | ||||
| import androidx.compose.material.icons.outlined.History | ||||
| import androidx.compose.material.icons.outlined.Settings | ||||
| import androidx.compose.material3.AlertDialog | ||||
| import androidx.compose.material3.Button | ||||
| @@ -41,22 +45,25 @@ import androidx.compose.runtime.remember | ||||
| import androidx.compose.runtime.setValue | ||||
| import androidx.compose.ui.Alignment | ||||
| import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.input.nestedscroll.NestedScrollConnection | ||||
| import androidx.compose.ui.input.nestedscroll.nestedScroll | ||||
| import androidx.compose.ui.platform.LocalContext | ||||
| import androidx.compose.ui.platform.LocalUriHandler | ||||
| import androidx.compose.ui.res.stringResource | ||||
| import androidx.compose.ui.text.TextStyle | ||||
| import androidx.compose.ui.text.font.FontWeight | ||||
| import androidx.compose.ui.text.style.TextAlign | ||||
| import androidx.compose.ui.unit.dp | ||||
| import eu.kanade.presentation.browse.components.ExtensionIcon | ||||
| import eu.kanade.presentation.components.AppBar | ||||
| import eu.kanade.presentation.components.AppBarActions | ||||
| import eu.kanade.presentation.components.DIVIDER_ALPHA | ||||
| import eu.kanade.presentation.components.Divider | ||||
| import eu.kanade.presentation.components.EmptyScreen | ||||
| import eu.kanade.presentation.components.LoadingScreen | ||||
| import eu.kanade.presentation.components.PreferenceRow | ||||
| import eu.kanade.presentation.components.Scaffold | ||||
| import eu.kanade.presentation.components.ScrollbarLazyColumn | ||||
| import eu.kanade.presentation.util.horizontalPadding | ||||
| import eu.kanade.presentation.util.plus | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.extension.model.Extension | ||||
| import eu.kanade.tachiyomi.source.ConfigurableSource | ||||
| @@ -66,11 +73,68 @@ import eu.kanade.tachiyomi.util.system.LocaleHelper | ||||
|  | ||||
| @Composable | ||||
| fun ExtensionDetailsScreen( | ||||
|     nestedScrollInterop: NestedScrollConnection, | ||||
|     navigateUp: () -> Unit, | ||||
|     presenter: ExtensionDetailsPresenter, | ||||
|     onClickSourcePreferences: (sourceId: Long) -> Unit, | ||||
| ) { | ||||
|     val uriHandler = LocalUriHandler.current | ||||
|  | ||||
|     Scaffold( | ||||
|         modifier = Modifier.statusBarsPadding(), | ||||
|         topBar = { | ||||
|             AppBar( | ||||
|                 title = stringResource(R.string.label_extension_info), | ||||
|                 navigateUp = navigateUp, | ||||
|                 actions = { | ||||
|                     AppBarActions( | ||||
|                         actions = buildList { | ||||
|                             if (presenter.extension?.isUnofficial == false) { | ||||
|                                 add( | ||||
|                                     AppBar.Action( | ||||
|                                         title = stringResource(R.string.whats_new), | ||||
|                                         icon = Icons.Outlined.History, | ||||
|                                         onClick = { uriHandler.openUri(presenter.getChangelogUrl()) }, | ||||
|                                     ), | ||||
|                                 ) | ||||
|                                 add( | ||||
|                                     AppBar.Action( | ||||
|                                         title = stringResource(R.string.action_faq_and_guides), | ||||
|                                         icon = Icons.Outlined.HelpOutline, | ||||
|                                         onClick = { uriHandler.openUri(presenter.getReadmeUrl()) }, | ||||
|                                     ), | ||||
|                                 ) | ||||
|                             } | ||||
|                             addAll( | ||||
|                                 listOf( | ||||
|                                     AppBar.OverflowAction( | ||||
|                                         title = stringResource(R.string.action_enable_all), | ||||
|                                         onClick = { presenter.toggleSources(true) }, | ||||
|                                     ), | ||||
|                                     AppBar.OverflowAction( | ||||
|                                         title = stringResource(R.string.action_disable_all), | ||||
|                                         onClick = { presenter.toggleSources(false) }, | ||||
|                                     ), | ||||
|                                     AppBar.OverflowAction( | ||||
|                                         title = stringResource(R.string.pref_clear_cookies), | ||||
|                                         onClick = { presenter.clearCookies() }, | ||||
|                                     ), | ||||
|                                 ), | ||||
|                             ) | ||||
|                         }, | ||||
|                     ) | ||||
|                 }, | ||||
|             ) | ||||
|         }, | ||||
|     ) { paddingValues -> | ||||
|         ExtensionDetails(paddingValues, presenter, onClickSourcePreferences) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @Composable | ||||
| private fun ExtensionDetails( | ||||
|     paddingValues: PaddingValues, | ||||
|     presenter: ExtensionDetailsPresenter, | ||||
|     onClickUninstall: () -> Unit, | ||||
|     onClickSourcePreferences: (sourceId: Long) -> Unit, | ||||
|     onClickSource: (sourceId: Long) -> Unit, | ||||
| ) { | ||||
|     when { | ||||
|         presenter.isLoading -> LoadingScreen() | ||||
| @@ -81,8 +145,7 @@ fun ExtensionDetailsScreen( | ||||
|             var showNsfwWarning by remember { mutableStateOf(false) } | ||||
|  | ||||
|             ScrollbarLazyColumn( | ||||
|                 modifier = Modifier.nestedScroll(nestedScrollInterop), | ||||
|                 contentPadding = WindowInsets.navigationBars.asPaddingValues(), | ||||
|                 contentPadding = paddingValues + WindowInsets.navigationBars.asPaddingValues(), | ||||
|             ) { | ||||
|                 when { | ||||
|                     extension.isUnofficial -> | ||||
| @@ -98,7 +161,7 @@ fun ExtensionDetailsScreen( | ||||
|                 item { | ||||
|                     DetailsHeader( | ||||
|                         extension = extension, | ||||
|                         onClickUninstall = onClickUninstall, | ||||
|                         onClickUninstall = { presenter.uninstallExtension() }, | ||||
|                         onClickAppInfo = { | ||||
|                             Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { | ||||
|                                 data = Uri.fromParts("package", extension.pkgName, null) | ||||
| @@ -119,7 +182,7 @@ fun ExtensionDetailsScreen( | ||||
|                         modifier = Modifier.animateItemPlacement(), | ||||
|                         source = source, | ||||
|                         onClickSourcePreferences = onClickSourcePreferences, | ||||
|                         onClickSource = onClickSource, | ||||
|                         onClickSource = { presenter.toggleSource(it) }, | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|   | ||||
| @@ -2,135 +2,35 @@ package eu.kanade.tachiyomi.ui.browse.extension.details | ||||
|  | ||||
| import android.annotation.SuppressLint | ||||
| import android.os.Bundle | ||||
| import android.view.Menu | ||||
| import android.view.MenuInflater | ||||
| import android.view.MenuItem | ||||
| import androidx.compose.runtime.Composable | ||||
| import androidx.compose.ui.input.nestedscroll.NestedScrollConnection | ||||
| import androidx.core.os.bundleOf | ||||
| import eu.kanade.presentation.browse.ExtensionDetailsScreen | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.network.NetworkHelper | ||||
| import eu.kanade.tachiyomi.source.online.HttpSource | ||||
| import eu.kanade.tachiyomi.ui.base.controller.ComposeController | ||||
| import eu.kanade.tachiyomi.ui.base.controller.openInBrowser | ||||
| import eu.kanade.tachiyomi.ui.base.controller.FullComposeController | ||||
| import eu.kanade.tachiyomi.ui.base.controller.pushController | ||||
| import eu.kanade.tachiyomi.util.system.logcat | ||||
| import okhttp3.HttpUrl.Companion.toHttpUrl | ||||
| import uy.kohesive.injekt.injectLazy | ||||
|  | ||||
| @SuppressLint("RestrictedApi") | ||||
| class ExtensionDetailsController(bundle: Bundle? = null) : | ||||
|     ComposeController<ExtensionDetailsPresenter>(bundle) { | ||||
|  | ||||
|     private val network: NetworkHelper by injectLazy() | ||||
| class ExtensionDetailsController( | ||||
|     bundle: Bundle? = null, | ||||
| ) : FullComposeController<ExtensionDetailsPresenter>(bundle) { | ||||
|  | ||||
|     constructor(pkgName: String) : this( | ||||
|         bundleOf(PKGNAME_KEY to pkgName), | ||||
|     ) | ||||
|  | ||||
|     init { | ||||
|         setHasOptionsMenu(true) | ||||
|     } | ||||
|  | ||||
|     override fun getTitle() = resources?.getString(R.string.label_extension_info) | ||||
|  | ||||
|     override fun createPresenter() = ExtensionDetailsPresenter(args.getString(PKGNAME_KEY)!!) | ||||
|  | ||||
|     @Composable | ||||
|     override fun ComposeContent(nestedScrollInterop: NestedScrollConnection) { | ||||
|     override fun ComposeContent() { | ||||
|         ExtensionDetailsScreen( | ||||
|             nestedScrollInterop = nestedScrollInterop, | ||||
|             navigateUp = router::popCurrentController, | ||||
|             presenter = presenter, | ||||
|             onClickUninstall = { presenter.uninstallExtension() }, | ||||
|             onClickSourcePreferences = { router.pushController(SourcePreferencesController(it)) }, | ||||
|             onClickSource = { presenter.toggleSource(it) }, | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { | ||||
|         inflater.inflate(R.menu.extension_details, menu) | ||||
|  | ||||
|         presenter.extension?.let { extension -> | ||||
|             menu.findItem(R.id.action_history).isVisible = !extension.isUnofficial | ||||
|             menu.findItem(R.id.action_faq_and_guides).isVisible = !extension.isUnofficial | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onOptionsItemSelected(item: MenuItem): Boolean { | ||||
|         when (item.itemId) { | ||||
|             R.id.action_history -> openChangelog() | ||||
|             R.id.action_faq_and_guides -> openReadme() | ||||
|             R.id.action_enable_all -> toggleAllSources(true) | ||||
|             R.id.action_disable_all -> toggleAllSources(false) | ||||
|             R.id.action_clear_cookies -> clearCookies() | ||||
|         } | ||||
|         return super.onOptionsItemSelected(item) | ||||
|     } | ||||
|  | ||||
|     fun onExtensionUninstalled() { | ||||
|         router.popCurrentController() | ||||
|     } | ||||
|  | ||||
|     private fun toggleAllSources(enable: Boolean) { | ||||
|         presenter.toggleSources(enable) | ||||
|     } | ||||
|  | ||||
|     private fun openChangelog() { | ||||
|         val extension = presenter.extension!! | ||||
|         val pkgName = extension.pkgName.substringAfter("eu.kanade.tachiyomi.extension.") | ||||
|         val pkgFactory = extension.pkgFactory | ||||
|         if (extension.hasChangelog) { | ||||
|             val url = createUrl(URL_EXTENSION_BLOB, pkgName, pkgFactory, "/CHANGELOG.md") | ||||
|             openInBrowser(url) | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         // Falling back on GitHub commit history because there is no explicit changelog in extension | ||||
|         val url = createUrl(URL_EXTENSION_COMMITS, pkgName, pkgFactory) | ||||
|         openInBrowser(url) | ||||
|     } | ||||
|  | ||||
|     private fun openReadme() { | ||||
|         val extension = presenter.extension!! | ||||
|  | ||||
|         if (!extension.hasReadme) { | ||||
|             openInBrowser("https://tachiyomi.org/help/faq/#extensions") | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         val pkgName = extension.pkgName.substringAfter("eu.kanade.tachiyomi.extension.") | ||||
|         val pkgFactory = extension.pkgFactory | ||||
|         val url = createUrl(URL_EXTENSION_BLOB, pkgName, pkgFactory, "/README.md") | ||||
|         openInBrowser(url) | ||||
|         return | ||||
|     } | ||||
|  | ||||
|     private fun createUrl(url: String, pkgName: String, pkgFactory: String?, path: String = ""): String { | ||||
|         return if (!pkgFactory.isNullOrEmpty()) { | ||||
|             when (path.isEmpty()) { | ||||
|                 true -> "$url/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/$pkgFactory" | ||||
|                 else -> "$url/multisrc/overrides/$pkgFactory/" + (pkgName.split(".").lastOrNull() ?: "") + path | ||||
|             } | ||||
|         } else { | ||||
|             url + "/src/" + pkgName.replace(".", "/") + path | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun clearCookies() { | ||||
|         val urls = presenter.extension?.sources | ||||
|             ?.filterIsInstance<HttpSource>() | ||||
|             ?.map { it.baseUrl } | ||||
|             ?.distinct() ?: emptyList() | ||||
|  | ||||
|         val cleared = urls.sumOf { | ||||
|             network.cookieManager.remove(it.toHttpUrl()) | ||||
|         } | ||||
|  | ||||
|         logcat { "Cleared $cleared cookies for: ${urls.joinToString()}" } | ||||
|     } | ||||
| } | ||||
|  | ||||
| private const val PKGNAME_KEY = "pkg_name" | ||||
| private const val URL_EXTENSION_COMMITS = "https://github.com/tachiyomiorg/tachiyomi-extensions/commits/master" | ||||
| private const val URL_EXTENSION_BLOB = "https://github.com/tachiyomiorg/tachiyomi-extensions/blob/master" | ||||
|   | ||||
| @@ -7,14 +7,18 @@ import eu.kanade.domain.source.interactor.ToggleSource | ||||
| import eu.kanade.presentation.browse.ExtensionDetailsState | ||||
| import eu.kanade.presentation.browse.ExtensionDetailsStateImpl | ||||
| import eu.kanade.tachiyomi.extension.ExtensionManager | ||||
| import eu.kanade.tachiyomi.network.NetworkHelper | ||||
| import eu.kanade.tachiyomi.source.Source | ||||
| import eu.kanade.tachiyomi.source.online.HttpSource | ||||
| import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter | ||||
| import eu.kanade.tachiyomi.util.lang.launchIO | ||||
| import eu.kanade.tachiyomi.util.lang.withUIContext | ||||
| import eu.kanade.tachiyomi.util.system.LocaleHelper | ||||
| import eu.kanade.tachiyomi.util.system.logcat | ||||
| import kotlinx.coroutines.CoroutineScope | ||||
| import kotlinx.coroutines.flow.collectLatest | ||||
| import kotlinx.coroutines.flow.map | ||||
| import okhttp3.HttpUrl.Companion.toHttpUrl | ||||
| import uy.kohesive.injekt.Injekt | ||||
| import uy.kohesive.injekt.api.get | ||||
|  | ||||
| @@ -24,6 +28,7 @@ class ExtensionDetailsPresenter( | ||||
|     private val context: Application = Injekt.get(), | ||||
|     private val getExtensionSources: GetExtensionSources = Injekt.get(), | ||||
|     private val toggleSource: ToggleSource = Injekt.get(), | ||||
|     private val network: NetworkHelper = Injekt.get(), | ||||
|     private val extensionManager: ExtensionManager = Injekt.get(), | ||||
| ) : BasePresenter<ExtensionDetailsController>(), ExtensionDetailsState by state { | ||||
|  | ||||
| @@ -32,7 +37,7 @@ class ExtensionDetailsPresenter( | ||||
|  | ||||
|         presenterScope.launchIO { | ||||
|             extensionManager.getInstalledExtensionsFlow() | ||||
|                 .map { it.firstOrNull { it.pkgName == pkgName } } | ||||
|                 .map { it.firstOrNull { pkg-> pkg.pkgName == pkgName } } | ||||
|                 .collectLatest { extension -> | ||||
|                     // If extension is null it's most likely uninstalled | ||||
|                     if (extension == null) { | ||||
| @@ -65,6 +70,44 @@ class ExtensionDetailsPresenter( | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun getChangelogUrl(): String { | ||||
|         extension ?: return "" | ||||
|  | ||||
|         val pkgName = extension.pkgName.substringAfter("eu.kanade.tachiyomi.extension.") | ||||
|         val pkgFactory = extension.pkgFactory | ||||
|         if (extension.hasChangelog) { | ||||
|             return createUrl(URL_EXTENSION_BLOB, pkgName, pkgFactory, "/CHANGELOG.md") | ||||
|         } | ||||
|  | ||||
|         // Falling back on GitHub commit history because there is no explicit changelog in extension | ||||
|         return createUrl(URL_EXTENSION_COMMITS, pkgName, pkgFactory) | ||||
|     } | ||||
|  | ||||
|     fun getReadmeUrl(): String { | ||||
|         extension ?: return "" | ||||
|  | ||||
|         if (!extension.hasReadme) { | ||||
|             return "https://tachiyomi.org/help/faq/#extensions" | ||||
|         } | ||||
|  | ||||
|         val pkgName = extension.pkgName.substringAfter("eu.kanade.tachiyomi.extension.") | ||||
|         val pkgFactory = extension.pkgFactory | ||||
|         return createUrl(URL_EXTENSION_BLOB, pkgName, pkgFactory, "/README.md") | ||||
|     } | ||||
|  | ||||
|     fun clearCookies() { | ||||
|         val urls = extension?.sources | ||||
|             ?.filterIsInstance<HttpSource>() | ||||
|             ?.map { it.baseUrl } | ||||
|             ?.distinct() ?: emptyList() | ||||
|  | ||||
|         val cleared = urls.sumOf { | ||||
|             network.cookieManager.remove(it.toHttpUrl()) | ||||
|         } | ||||
|  | ||||
|         logcat { "Cleared $cleared cookies for: ${urls.joinToString()}" } | ||||
|     } | ||||
|  | ||||
|     fun uninstallExtension() { | ||||
|         val extension = extension ?: return | ||||
|         extensionManager.uninstallExtension(extension.pkgName) | ||||
| @@ -77,6 +120,17 @@ class ExtensionDetailsPresenter( | ||||
|     fun toggleSources(enable: Boolean) { | ||||
|         extension?.sources?.forEach { toggleSource.await(it.id, enable) } | ||||
|     } | ||||
|  | ||||
|     private fun createUrl(url: String, pkgName: String, pkgFactory: String?, path: String = ""): String { | ||||
|         return if (!pkgFactory.isNullOrEmpty()) { | ||||
|             when (path.isEmpty()) { | ||||
|                 true -> "$url/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/$pkgFactory" | ||||
|                 else -> "$url/multisrc/overrides/$pkgFactory/" + (pkgName.split(".").lastOrNull() ?: "") + path | ||||
|             } | ||||
|         } else { | ||||
|             url + "/src/" + pkgName.replace(".", "/") + path | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| data class ExtensionSourceItem( | ||||
| @@ -84,3 +138,6 @@ data class ExtensionSourceItem( | ||||
|     val enabled: Boolean, | ||||
|     val labelAsName: Boolean, | ||||
| ) | ||||
|  | ||||
| private const val URL_EXTENSION_COMMITS = "https://github.com/tachiyomiorg/tachiyomi-extensions/commits/master" | ||||
| private const val URL_EXTENSION_BLOB = "https://github.com/tachiyomiorg/tachiyomi-extensions/blob/master" | ||||
|   | ||||
| @@ -99,25 +99,14 @@ class MangaPresenter( | ||||
| ) : BasePresenter<MangaController>() { | ||||
|  | ||||
|     private val _state: MutableStateFlow<MangaScreenState> = MutableStateFlow(MangaScreenState.Loading) | ||||
|  | ||||
|     val state = _state.asStateFlow() | ||||
|  | ||||
|     private val successState: MangaScreenState.Success? | ||||
|         get() = state.value as? MangaScreenState.Success | ||||
|  | ||||
|     /** | ||||
|      * Subscription to update the manga from the source. | ||||
|      */ | ||||
|     private var fetchMangaJob: Job? = null | ||||
|  | ||||
|     /** | ||||
|      * Subscription to retrieve the new list of chapters from the source. | ||||
|      */ | ||||
|     private var fetchChaptersJob: Job? = null | ||||
|  | ||||
|     /** | ||||
|      * Subscription to observe download status changes. | ||||
|      */ | ||||
|     private var observeDownloadsStatusJob: Job? = null | ||||
|     private var observeDownloadsPageJob: Job? = null | ||||
|  | ||||
| @@ -138,7 +127,7 @@ class MangaPresenter( | ||||
|     val isFavoritedManga: Boolean | ||||
|         get() = manga?.favorite ?: false | ||||
|  | ||||
|     val processedChapters: Sequence<ChapterItem>? | ||||
|     private val processedChapters: Sequence<ChapterItem>? | ||||
|         get() = successState?.processedChapters | ||||
|  | ||||
|     private val selectedPositions: Array<Int> = arrayOf(-1, -1) // first and last selected index in list | ||||
| @@ -164,8 +153,6 @@ class MangaPresenter( | ||||
|     override fun onCreate(savedState: Bundle?) { | ||||
|         super.onCreate(savedState) | ||||
|  | ||||
|         // Manga info - start | ||||
|  | ||||
|         presenterScope.launchIO { | ||||
|             val manga = getMangaAndChapters.awaitManga(mangaId) | ||||
|  | ||||
| @@ -221,15 +208,11 @@ class MangaPresenter( | ||||
|         } | ||||
|  | ||||
|         preferences.incognitoMode() | ||||
|             .asHotFlow { incognito -> | ||||
|                 incognitoMode = incognito | ||||
|             } | ||||
|             .asHotFlow { incognitoMode = it } | ||||
|             .launchIn(presenterScope) | ||||
|  | ||||
|         preferences.downloadedOnly() | ||||
|             .asHotFlow { downloadedOnly -> | ||||
|                 downloadedOnlyMode = downloadedOnly | ||||
|             } | ||||
|             .asHotFlow { downloadedOnlyMode = it } | ||||
|             .launchIn(presenterScope) | ||||
|     } | ||||
|  | ||||
| @@ -239,6 +222,7 @@ class MangaPresenter( | ||||
|     } | ||||
|  | ||||
|     // Manga info - start | ||||
|  | ||||
|     /** | ||||
|      * Fetch manga information from source. | ||||
|      */ | ||||
| @@ -395,7 +379,7 @@ class MangaPresenter( | ||||
|      * @param manga the manga to get categories from. | ||||
|      * @return Array of category ids the manga is in, if none returns default id | ||||
|      */ | ||||
|     suspend fun getMangaCategoryIds(manga: DomainManga): List<Long> { | ||||
|     private suspend fun getMangaCategoryIds(manga: DomainManga): List<Long> { | ||||
|         return getCategories.await(manga.id) | ||||
|             .map { it.id } | ||||
|     } | ||||
| @@ -420,7 +404,7 @@ class MangaPresenter( | ||||
|         moveMangaToCategory(categoryIds) | ||||
|     } | ||||
|  | ||||
|     fun moveMangaToCategory(categoryIds: List<Long>) { | ||||
|     private fun moveMangaToCategory(categoryIds: List<Long>) { | ||||
|         presenterScope.launchIO { | ||||
|             setMangaCategories.await(mangaId, categoryIds) | ||||
|         } | ||||
| @@ -951,7 +935,7 @@ class MangaPresenter( | ||||
|                                 .lastOrNull() | ||||
|                                 ?.chapterNumber?.toDouble() ?: -1.0 | ||||
|  | ||||
|                             if (latestLocalReadChapterNumber >= track.lastChapterRead) { | ||||
|                             if (latestLocalReadChapterNumber > track.lastChapterRead) { | ||||
|                                 val updatedTrack = track.copy( | ||||
|                                     lastChapterRead = latestLocalReadChapterNumber, | ||||
|                                 ) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user