Use Voyager on BrowseSource and SourceSearch screen (#8650)
Some navigation janks will be dealt with when the migration is complete
(cherry picked from commit 94d1b68598)
# Conflicts:
# app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt
# app/src/main/java/eu/kanade/presentation/browse/SourceSearchScreen.kt
# app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceComfortableGrid.kt
# app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceCompactGrid.kt
# app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceList.kt
# app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchController.kt
# app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesTab.kt
# app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt
# app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt
# app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterSheet.kt
This commit is contained in:
@@ -2,24 +2,16 @@ package exh.md.follows
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.core.os.bundleOf
|
||||
import eu.kanade.presentation.browse.BrowseMangadexFollowsScreen
|
||||
import eu.kanade.presentation.browse.components.RemoveMangaDialog
|
||||
import eu.kanade.presentation.components.ChangeCategoryDialog
|
||||
import eu.kanade.presentation.components.DuplicateMangaDialog
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.ui.base.controller.pushController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.BasicFullComposeController
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
||||
import eu.kanade.tachiyomi.ui.category.CategoryController
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
|
||||
/**
|
||||
* Controller that shows the latest manga from the catalogue. Inherit [BrowseSourceController].
|
||||
*/
|
||||
class MangaDexFollowsController(bundle: Bundle) : BrowseSourceController(bundle) {
|
||||
class MangaDexFollowsController(bundle: Bundle) : BasicFullComposeController(bundle) {
|
||||
|
||||
constructor(source: CatalogueSource) : this(
|
||||
bundleOf(
|
||||
@@ -27,71 +19,12 @@ class MangaDexFollowsController(bundle: Bundle) : BrowseSourceController(bundle)
|
||||
),
|
||||
)
|
||||
|
||||
override fun createPresenter(): BrowseSourcePresenter {
|
||||
return MangaDexFollowsPresenter(args.getLong(SOURCE_ID_KEY))
|
||||
}
|
||||
private val sourceId = args.getLong(SOURCE_ID_KEY)
|
||||
|
||||
@Composable
|
||||
override fun ComposeContent() {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
BrowseMangadexFollowsScreen(
|
||||
presenter = presenter,
|
||||
navigateUp = { router.popCurrentController() },
|
||||
onDisplayModeChange = { presenter.displayMode = (it) },
|
||||
onMangaClick = {
|
||||
router.pushController(MangaController(it.id, true))
|
||||
},
|
||||
onMangaLongClick = { manga ->
|
||||
scope.launchIO {
|
||||
val duplicateManga = presenter.getDuplicateLibraryManga(manga)
|
||||
when {
|
||||
manga.favorite -> presenter.dialog = BrowseSourcePresenter.Dialog.RemoveManga(manga)
|
||||
duplicateManga != null -> presenter.dialog = BrowseSourcePresenter.Dialog.AddDuplicateManga(manga, duplicateManga)
|
||||
else -> presenter.addFavorite(manga)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
val onDismissRequest = { presenter.dialog = null }
|
||||
when (val dialog = presenter.dialog) {
|
||||
is BrowseSourcePresenter.Dialog.AddDuplicateManga -> {
|
||||
DuplicateMangaDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
onConfirm = { presenter.addFavorite(dialog.manga) },
|
||||
onOpenManga = { router.pushController(MangaController(dialog.duplicate.id)) },
|
||||
duplicateFrom = presenter.getSourceOrStub(dialog.duplicate),
|
||||
)
|
||||
}
|
||||
is BrowseSourcePresenter.Dialog.RemoveManga -> {
|
||||
RemoveMangaDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
onConfirm = {
|
||||
presenter.changeMangaFavorite(dialog.manga)
|
||||
},
|
||||
mangaToRemove = dialog.manga,
|
||||
)
|
||||
}
|
||||
is BrowseSourcePresenter.Dialog.ChangeMangaCategory -> {
|
||||
ChangeCategoryDialog(
|
||||
initialSelection = dialog.initialSelection,
|
||||
onDismissRequest = onDismissRequest,
|
||||
onEditCategories = {
|
||||
router.pushController(CategoryController())
|
||||
},
|
||||
onConfirm = { include, _ ->
|
||||
presenter.changeMangaFavorite(dialog.manga)
|
||||
presenter.moveMangaToCategories(dialog.manga, include)
|
||||
},
|
||||
)
|
||||
}
|
||||
is BrowseSourcePresenter.Dialog.Migrate -> Unit
|
||||
null -> {}
|
||||
}
|
||||
}
|
||||
|
||||
override fun initFilterSheet() {
|
||||
// No-op: we don't allow filtering in mangadex follows
|
||||
Navigator(screen = MangaDexFollowsScreen(sourceId))
|
||||
}
|
||||
}
|
||||
|
||||
private const val SOURCE_ID_KEY = "source_id"
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package exh.md.follows
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.source.model.SourcePagingSourceType
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.source.getMainSource
|
||||
|
||||
/**
|
||||
* Presenter of [MangaDexFollowsController]. Inherit BrowseCataloguePresenter.
|
||||
*/
|
||||
class MangaDexFollowsPresenter(sourceId: Long) : BrowseSourcePresenter(sourceId) {
|
||||
|
||||
override fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType {
|
||||
return MangaDexFollowsPagingSource(source!!.getMainSource() as MangaDex)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun getRaisedSearchMetadata(manga: Manga, initialMetadata: RaisedSearchMetadata?): State<RaisedSearchMetadata?> {
|
||||
return remember { mutableStateOf(initialMetadata) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package exh.md.follows
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.browse.BrowseSourceContent
|
||||
import eu.kanade.presentation.browse.components.BrowseSourceSimpleToolbar
|
||||
import eu.kanade.presentation.browse.components.RemoveMangaDialog
|
||||
import eu.kanade.presentation.components.ChangeCategoryDialog
|
||||
import eu.kanade.presentation.components.DuplicateMangaDialog
|
||||
import eu.kanade.presentation.components.Scaffold
|
||||
import eu.kanade.presentation.util.LocalRouter
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.pushController
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel
|
||||
import eu.kanade.tachiyomi.ui.category.CategoryController
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
|
||||
class MangaDexFollowsScreen(private val sourceId: Long) : Screen {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val router = LocalRouter.currentOrThrow
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val scope = rememberCoroutineScope()
|
||||
val haptic = LocalHapticFeedback.current
|
||||
val screenModel = rememberScreenModel { MangaDexFollowsScreenModel(sourceId) }
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
val navigateUp: () -> Unit = {
|
||||
when {
|
||||
navigator.canPop -> navigator.pop()
|
||||
router.backstackSize > 1 -> router.popCurrentController()
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = { scrollBehavior ->
|
||||
BrowseSourceSimpleToolbar(
|
||||
title = stringResource(R.string.mangadex_follows),
|
||||
displayMode = screenModel.displayMode,
|
||||
onDisplayModeChange = { screenModel.displayMode = it },
|
||||
navigateUp = navigateUp,
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
},
|
||||
snackbarHost = {
|
||||
SnackbarHost(hostState = snackbarHostState)
|
||||
},
|
||||
) { paddingValues ->
|
||||
val mangaList = remember(state.currentFilter) {
|
||||
screenModel.getMangaListFlow(state.currentFilter)
|
||||
}.collectAsLazyPagingItems()
|
||||
|
||||
BrowseSourceContent(
|
||||
source = screenModel.source,
|
||||
mangaList = mangaList,
|
||||
columns = screenModel.getColumnsPreference(LocalConfiguration.current.orientation),
|
||||
// SY -->
|
||||
ehentaiBrowseDisplayMode = screenModel.ehentaiBrowseDisplayMode,
|
||||
// SY <--
|
||||
displayMode = screenModel.displayMode,
|
||||
snackbarHostState = snackbarHostState,
|
||||
contentPadding = paddingValues,
|
||||
onWebViewClick = null,
|
||||
onHelpClick = null,
|
||||
onLocalSourceHelpClick = null,
|
||||
onMangaClick = { router.pushController(MangaController(it.id, true)) },
|
||||
onMangaLongClick = { manga ->
|
||||
scope.launchIO {
|
||||
val duplicateManga = screenModel.getDuplicateLibraryManga(manga)
|
||||
when {
|
||||
manga.favorite -> screenModel.setDialog(BrowseSourceScreenModel.Dialog.RemoveManga(manga))
|
||||
duplicateManga != null -> screenModel.setDialog(
|
||||
BrowseSourceScreenModel.Dialog.AddDuplicateManga(
|
||||
manga,
|
||||
duplicateManga,
|
||||
),
|
||||
)
|
||||
else -> screenModel.addFavorite(manga)
|
||||
}
|
||||
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
val onDismissRequest = { screenModel.setDialog(null) }
|
||||
when (val dialog = state.dialog) {
|
||||
is BrowseSourceScreenModel.Dialog.Migrate -> {}
|
||||
is BrowseSourceScreenModel.Dialog.AddDuplicateManga -> {
|
||||
DuplicateMangaDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
onConfirm = { screenModel.addFavorite(dialog.manga) },
|
||||
onOpenManga = { router.pushController(MangaController(dialog.duplicate.id)) },
|
||||
duplicateFrom = screenModel.getSourceOrStub(dialog.duplicate),
|
||||
)
|
||||
}
|
||||
is BrowseSourceScreenModel.Dialog.RemoveManga -> {
|
||||
RemoveMangaDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
onConfirm = {
|
||||
screenModel.changeMangaFavorite(dialog.manga)
|
||||
},
|
||||
mangaToRemove = dialog.manga,
|
||||
)
|
||||
}
|
||||
is BrowseSourceScreenModel.Dialog.ChangeMangaCategory -> {
|
||||
ChangeCategoryDialog(
|
||||
initialSelection = dialog.initialSelection,
|
||||
onDismissRequest = onDismissRequest,
|
||||
onEditCategories = {
|
||||
router.pushController(CategoryController())
|
||||
},
|
||||
onConfirm = { include, _ ->
|
||||
screenModel.changeMangaFavorite(dialog.manga)
|
||||
screenModel.moveMangaToCategories(dialog.manga, include)
|
||||
},
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
BackHandler(onBack = navigateUp)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package exh.md.follows
|
||||
|
||||
import android.content.Context
|
||||
import com.bluelinelabs.conductor.Router
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.source.model.SourcePagingSourceType
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.source.getMainSource
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class MangaDexFollowsScreenModel(sourceId: Long) : BrowseSourceScreenModel(sourceId, null) {
|
||||
|
||||
override fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType {
|
||||
return MangaDexFollowsPagingSource(source.getMainSource() as MangaDex)
|
||||
}
|
||||
|
||||
override fun Flow<Manga>.combineMetadata(dbManga: Manga, metadata: RaisedSearchMetadata?): Flow<Pair<Manga, RaisedSearchMetadata?>> {
|
||||
return map { it to metadata }
|
||||
}
|
||||
|
||||
override fun initFilterSheet(context: Context, router: Router) {
|
||||
// No-op: we don't allow filtering in recs
|
||||
}
|
||||
}
|
||||
@@ -2,54 +2,33 @@ package exh.md.similar
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.core.os.bundleOf
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.presentation.browse.BrowseRecommendationsScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.ui.base.controller.pushController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.BasicFullComposeController
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
|
||||
/**
|
||||
* Controller that shows the latest manga from the catalogue. Inherit [BrowseSourceController].
|
||||
*/
|
||||
class MangaDexSimilarController(bundle: Bundle) : BrowseSourceController(bundle) {
|
||||
class MangaDexSimilarController(bundle: Bundle) : BasicFullComposeController(bundle) {
|
||||
|
||||
constructor(manga: Manga, source: CatalogueSource) : this(
|
||||
bundleOf(
|
||||
MANGA_ID to manga.id,
|
||||
MANGA_TITLE to manga.title,
|
||||
SOURCE_ID_KEY to source.id,
|
||||
),
|
||||
)
|
||||
|
||||
private val mangaTitle = args.getString(MANGA_TITLE, "")
|
||||
|
||||
override fun createPresenter(): BrowseSourcePresenter {
|
||||
return MangaDexSimilarPresenter(args.getLong(MANGA_ID), args.getLong(SOURCE_ID_KEY))
|
||||
}
|
||||
val mangaId = args.getLong(MANGA_ID)
|
||||
val sourceId = args.getLong(SOURCE_ID_KEY)
|
||||
|
||||
@Composable
|
||||
override fun ComposeContent() {
|
||||
BrowseRecommendationsScreen(
|
||||
presenter = presenter,
|
||||
navigateUp = { router.popCurrentController() },
|
||||
title = stringResource(R.string.similar, mangaTitle),
|
||||
onMangaClick = {
|
||||
router.pushController(MangaController(it.id, true))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun initFilterSheet() {
|
||||
// No-op: we don't allow filtering in similar
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MANGA_ID = "manga_id"
|
||||
const val MANGA_TITLE = "manga_title"
|
||||
Navigator(screen = MangaDexSimilarScreen(mangaId, sourceId))
|
||||
}
|
||||
}
|
||||
|
||||
private const val MANGA_ID = "manga_id"
|
||||
private const val SOURCE_ID_KEY = "source_id"
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
package exh.md.similar
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.source.model.SourcePagingSourceType
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.source.getMainSource
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
/**
|
||||
* Presenter of [MangaDexSimilarController]. Inherit BrowseCataloguePresenter.
|
||||
*/
|
||||
class MangaDexSimilarPresenter(
|
||||
val mangaId: Long,
|
||||
sourceId: Long,
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
) : BrowseSourcePresenter(sourceId) {
|
||||
|
||||
var manga: Manga? = null
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
this.manga = runBlocking { getManga.await(mangaId) }
|
||||
}
|
||||
|
||||
override fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType {
|
||||
return MangaDexSimilarPagingSource(manga!!, source!!.getMainSource() as MangaDex)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun getRaisedSearchMetadata(manga: Manga, initialMetadata: RaisedSearchMetadata?): State<RaisedSearchMetadata?> {
|
||||
return remember { mutableStateOf(initialMetadata) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package exh.md.similar
|
||||
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.presentation.browse.BrowseSourceContent
|
||||
import eu.kanade.presentation.browse.components.BrowseSourceSimpleToolbar
|
||||
import eu.kanade.presentation.components.Scaffold
|
||||
import eu.kanade.presentation.util.LocalRouter
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.pushController
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
|
||||
class MangaDexSimilarScreen(val mangaId: Long, val sourceId: Long) : Screen {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val screenModel = rememberScreenModel { MangaDexSimilarScreenModel(mangaId, sourceId) }
|
||||
val state by screenModel.state.collectAsState()
|
||||
val router = LocalRouter.currentOrThrow
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
|
||||
val onMangaClick: (Manga) -> Unit = {
|
||||
router.pushController(MangaController(it.id, true))
|
||||
}
|
||||
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
val navigateUp: () -> Unit = {
|
||||
when {
|
||||
navigator.canPop -> navigator.pop()
|
||||
router.backstackSize > 1 -> router.popCurrentController()
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = { scrollBehavior ->
|
||||
BrowseSourceSimpleToolbar(
|
||||
navigateUp = navigateUp,
|
||||
title = stringResource(R.string.similar, screenModel.manga.title),
|
||||
displayMode = screenModel.displayMode,
|
||||
onDisplayModeChange = { screenModel.displayMode = it },
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
},
|
||||
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
||||
) { paddingValues ->
|
||||
val mangaList = remember(state.currentFilter) {
|
||||
screenModel.getMangaListFlow(state.currentFilter)
|
||||
}.collectAsLazyPagingItems()
|
||||
|
||||
BrowseSourceContent(
|
||||
source = screenModel.source,
|
||||
mangaList = mangaList,
|
||||
columns = screenModel.getColumnsPreference(LocalConfiguration.current.orientation),
|
||||
// SY -->
|
||||
ehentaiBrowseDisplayMode = false,
|
||||
// SY <--
|
||||
displayMode = screenModel.displayMode,
|
||||
snackbarHostState = snackbarHostState,
|
||||
contentPadding = paddingValues,
|
||||
onWebViewClick = null,
|
||||
onHelpClick = null,
|
||||
onLocalSourceHelpClick = null,
|
||||
onMangaClick = onMangaClick,
|
||||
onMangaLongClick = onMangaClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package exh.md.similar
|
||||
|
||||
import android.content.Context
|
||||
import com.bluelinelabs.conductor.Router
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.source.model.SourcePagingSourceType
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.source.getMainSource
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
/**
|
||||
* Presenter of [MangaDexSimilarController]. Inherit BrowseCataloguePresenter.
|
||||
*/
|
||||
class MangaDexSimilarScreenModel(
|
||||
val mangaId: Long,
|
||||
sourceId: Long,
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
) : BrowseSourceScreenModel(sourceId, null) {
|
||||
|
||||
val manga: Manga = runBlocking { getManga.await(mangaId) }!!
|
||||
|
||||
override fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType {
|
||||
return MangaDexSimilarPagingSource(manga, source.getMainSource() as MangaDex)
|
||||
}
|
||||
|
||||
override fun Flow<Manga>.combineMetadata(dbManga: Manga, metadata: RaisedSearchMetadata?): Flow<Pair<Manga, RaisedSearchMetadata?>> {
|
||||
return map { it to metadata }
|
||||
}
|
||||
|
||||
override fun initFilterSheet(context: Context, router: Router) {
|
||||
// No-op: we don't allow filtering in recs
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,16 @@ package exh.recs
|
||||
import android.os.Bundle
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.core.os.bundleOf
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.presentation.browse.BrowseRecommendationsScreen
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.ui.base.controller.pushController
|
||||
import eu.kanade.tachiyomi.ui.browse.source.SourcesController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.BasicFullComposeController
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
||||
|
||||
/**
|
||||
* Controller that shows the latest manga from the catalogue. Inherit [BrowseSourceController].
|
||||
*/
|
||||
class RecommendsController(bundle: Bundle) : BrowseSourceController(bundle) {
|
||||
class RecommendsController(bundle: Bundle) : BasicFullComposeController(bundle) {
|
||||
|
||||
constructor(manga: Manga, source: CatalogueSource) : this(
|
||||
bundleOf(
|
||||
@@ -22,38 +21,14 @@ class RecommendsController(bundle: Bundle) : BrowseSourceController(bundle) {
|
||||
),
|
||||
)
|
||||
|
||||
override fun createPresenter(): RecommendsPresenter {
|
||||
return RecommendsPresenter(args.getLong(MANGA_ID), args.getLong(SOURCE_ID_KEY))
|
||||
}
|
||||
val mangaId = args.getLong(MANGA_ID)
|
||||
val sourceId = args.getLong(SOURCE_ID_KEY)
|
||||
|
||||
@Composable
|
||||
override fun ComposeContent() {
|
||||
BrowseRecommendationsScreen(
|
||||
presenter = presenter,
|
||||
navigateUp = { router.popCurrentController() },
|
||||
title = (presenter as RecommendsPresenter).manga!!.title,
|
||||
onMangaClick = { manga ->
|
||||
openSmartSearch(manga.ogTitle)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun initFilterSheet() {
|
||||
// No-op: we don't allow filtering in recs
|
||||
}
|
||||
|
||||
private fun openSmartSearch(title: String) {
|
||||
val smartSearchConfig = SourcesController.SmartSearchConfig(title)
|
||||
router.pushController(
|
||||
SourcesController(
|
||||
bundleOf(
|
||||
SourcesController.SMART_SEARCH_CONFIG to smartSearchConfig,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MANGA_ID = "manga_id"
|
||||
Navigator(screen = RecommendsScreen(mangaId, sourceId))
|
||||
}
|
||||
}
|
||||
|
||||
private const val MANGA_ID = "manga_id"
|
||||
private const val SOURCE_ID_KEY = "source_id"
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package exh.recs
|
||||
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import com.bluelinelabs.conductor.Router
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.presentation.browse.BrowseSourceContent
|
||||
import eu.kanade.presentation.browse.components.BrowseSourceSimpleToolbar
|
||||
import eu.kanade.presentation.components.Scaffold
|
||||
import eu.kanade.presentation.util.LocalRouter
|
||||
import eu.kanade.tachiyomi.ui.base.controller.pushController
|
||||
import eu.kanade.tachiyomi.ui.browse.source.SourcesController
|
||||
|
||||
class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val screenModel = rememberScreenModel { RecommendsScreenModel(mangaId, sourceId) }
|
||||
val state by screenModel.state.collectAsState()
|
||||
val router = LocalRouter.currentOrThrow
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
|
||||
val onMangaClick: (Manga) -> Unit = { manga ->
|
||||
openSmartSearch(router, manga.ogTitle)
|
||||
}
|
||||
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
val navigateUp: () -> Unit = {
|
||||
when {
|
||||
navigator.canPop -> navigator.pop()
|
||||
router.backstackSize > 1 -> router.popCurrentController()
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = { scrollBehavior ->
|
||||
BrowseSourceSimpleToolbar(
|
||||
navigateUp = navigateUp,
|
||||
title = screenModel.manga.title,
|
||||
displayMode = screenModel.displayMode,
|
||||
onDisplayModeChange = { screenModel.displayMode = it },
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
},
|
||||
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
||||
) { paddingValues ->
|
||||
val mangaList = remember(state.currentFilter) {
|
||||
screenModel.getMangaListFlow(state.currentFilter)
|
||||
}.collectAsLazyPagingItems()
|
||||
|
||||
BrowseSourceContent(
|
||||
source = screenModel.source,
|
||||
mangaList = mangaList,
|
||||
columns = screenModel.getColumnsPreference(LocalConfiguration.current.orientation),
|
||||
// SY -->
|
||||
ehentaiBrowseDisplayMode = false,
|
||||
// SY <--
|
||||
displayMode = screenModel.displayMode,
|
||||
snackbarHostState = snackbarHostState,
|
||||
contentPadding = paddingValues,
|
||||
onWebViewClick = null,
|
||||
onHelpClick = null,
|
||||
onLocalSourceHelpClick = null,
|
||||
onMangaClick = onMangaClick,
|
||||
onMangaLongClick = onMangaClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openSmartSearch(router: Router, title: String) {
|
||||
val smartSearchConfig = SourcesController.SmartSearchConfig(title)
|
||||
router.pushController(
|
||||
SourcesController(
|
||||
bundleOf(
|
||||
SourcesController.SMART_SEARCH_CONFIG to smartSearchConfig,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
+5
-12
@@ -1,11 +1,9 @@
|
||||
package exh.recs
|
||||
|
||||
import android.os.Bundle
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.source.model.SourcePagingSourceType
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@@ -13,20 +11,15 @@ import uy.kohesive.injekt.api.get
|
||||
/**
|
||||
* Presenter of [RecommendsController]. Inherit BrowseCataloguePresenter.
|
||||
*/
|
||||
class RecommendsPresenter(
|
||||
class RecommendsScreenModel(
|
||||
val mangaId: Long,
|
||||
sourceId: Long,
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
) : BrowseSourcePresenter(sourceId) {
|
||||
) : BrowseSourceScreenModel(sourceId, null) {
|
||||
|
||||
var manga: Manga? = null
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
this.manga = runBlocking { getManga.await(mangaId) }
|
||||
}
|
||||
val manga = runBlocking { getManga.await(mangaId) }!!
|
||||
|
||||
override fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType {
|
||||
return RecommendsPagingSource(source!!, manga!!)
|
||||
return RecommendsPagingSource(source, manga)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user