mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-14 21:18:56 +01:00
Migrate More screen to Compose (#6990)
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package eu.kanade.tachiyomi.ui.base.presenter
|
||||
|
||||
import android.os.Bundle
|
||||
import com.fredporciuncula.flow.preferences.Preference
|
||||
import eu.kanade.core.prefs.PreferenceMutableState
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.cancel
|
||||
@@ -10,7 +12,7 @@ import rx.Observable
|
||||
|
||||
open class BasePresenter<V> : RxPresenter<V>() {
|
||||
|
||||
lateinit var presenterScope: CoroutineScope
|
||||
var presenterScope: CoroutineScope = MainScope()
|
||||
|
||||
/**
|
||||
* Query from the view where applicable
|
||||
@@ -20,7 +22,6 @@ open class BasePresenter<V> : RxPresenter<V>() {
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
try {
|
||||
super.onCreate(savedState)
|
||||
presenterScope = MainScope()
|
||||
} catch (e: NullPointerException) {
|
||||
// Swallow this error. This should be fixed in the library but since it's not critical
|
||||
// (only used by restartables) it should be enough. It saves me a fork.
|
||||
@@ -38,6 +39,8 @@ open class BasePresenter<V> : RxPresenter<V>() {
|
||||
return super.getView()
|
||||
}
|
||||
|
||||
fun <T> Preference<T>.asState() = PreferenceMutableState(this, presenterScope)
|
||||
|
||||
/**
|
||||
* Subscribes an observable with [deliverFirst] and adds it to the presenter's lifecycle
|
||||
* subscription list.
|
||||
|
||||
@@ -1,187 +1,38 @@
|
||||
package eu.kanade.tachiyomi.ui.more
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import eu.kanade.presentation.more.MoreScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.download.DownloadService
|
||||
import eu.kanade.tachiyomi.ui.base.controller.ComposeController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NoAppBarElevationController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.RootController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.pushController
|
||||
import eu.kanade.tachiyomi.ui.category.CategoryController
|
||||
import eu.kanade.tachiyomi.ui.download.DownloadController
|
||||
import eu.kanade.tachiyomi.ui.setting.SettingsBackupController
|
||||
import eu.kanade.tachiyomi.ui.setting.SettingsController
|
||||
import eu.kanade.tachiyomi.ui.setting.SettingsMainController
|
||||
import eu.kanade.tachiyomi.util.preference.add
|
||||
import eu.kanade.tachiyomi.util.preference.bindTo
|
||||
import eu.kanade.tachiyomi.util.preference.iconRes
|
||||
import eu.kanade.tachiyomi.util.preference.iconTint
|
||||
import eu.kanade.tachiyomi.util.preference.onClick
|
||||
import eu.kanade.tachiyomi.util.preference.preference
|
||||
import eu.kanade.tachiyomi.util.preference.preferenceCategory
|
||||
import eu.kanade.tachiyomi.util.preference.summaryRes
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.subscriptions.CompositeSubscription
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class MoreController :
|
||||
SettingsController(),
|
||||
ComposeController<MorePresenter>(),
|
||||
RootController,
|
||||
NoAppBarElevationController {
|
||||
|
||||
private val downloadManager: DownloadManager by injectLazy()
|
||||
private var isDownloading: Boolean = false
|
||||
private var downloadQueueSize: Int = 0
|
||||
override fun getTitle() = resources?.getString(R.string.label_more)
|
||||
|
||||
private var untilDestroySubscriptions = CompositeSubscription()
|
||||
private set
|
||||
override fun createPresenter() = MorePresenter()
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
|
||||
titleRes = R.string.label_more
|
||||
|
||||
val tintColor = context.getResourceColor(R.attr.colorAccent)
|
||||
|
||||
add(MoreHeaderPreference(context))
|
||||
|
||||
switchPreference {
|
||||
bindTo(preferences.downloadedOnly())
|
||||
titleRes = R.string.label_downloaded_only
|
||||
summaryRes = R.string.downloaded_only_summary
|
||||
iconRes = R.drawable.ic_cloud_off_24dp
|
||||
iconTint = tintColor
|
||||
}
|
||||
|
||||
switchPreference {
|
||||
bindTo(preferences.incognitoMode())
|
||||
summaryRes = R.string.pref_incognito_mode_summary
|
||||
titleRes = R.string.pref_incognito_mode
|
||||
iconRes = R.drawable.ic_glasses_24dp
|
||||
iconTint = tintColor
|
||||
|
||||
preferences.incognitoMode().asFlow()
|
||||
.onEach { isChecked = it }
|
||||
.launchIn(viewScope)
|
||||
}
|
||||
|
||||
preferenceCategory {
|
||||
preference {
|
||||
titleRes = R.string.label_download_queue
|
||||
|
||||
if (downloadManager.queue.isNotEmpty()) {
|
||||
initDownloadQueueSummary(this)
|
||||
}
|
||||
|
||||
iconRes = R.drawable.ic_get_app_24dp
|
||||
iconTint = tintColor
|
||||
onClick {
|
||||
router.pushController(DownloadController())
|
||||
}
|
||||
}
|
||||
preference {
|
||||
titleRes = R.string.categories
|
||||
iconRes = R.drawable.ic_label_24dp
|
||||
iconTint = tintColor
|
||||
onClick {
|
||||
router.pushController(CategoryController())
|
||||
}
|
||||
}
|
||||
preference {
|
||||
titleRes = R.string.label_backup
|
||||
iconRes = R.drawable.ic_settings_backup_restore_24dp
|
||||
iconTint = tintColor
|
||||
onClick {
|
||||
router.pushController(SettingsBackupController())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
preferenceCategory {
|
||||
preference {
|
||||
titleRes = R.string.label_settings
|
||||
iconRes = R.drawable.ic_settings_24dp
|
||||
iconTint = tintColor
|
||||
onClick {
|
||||
router.pushController(SettingsMainController())
|
||||
}
|
||||
}
|
||||
preference {
|
||||
iconRes = R.drawable.ic_info_24dp
|
||||
iconTint = tintColor
|
||||
titleRes = R.string.pref_category_about
|
||||
onClick {
|
||||
router.pushController(AboutController())
|
||||
}
|
||||
}
|
||||
preference {
|
||||
titleRes = R.string.label_help
|
||||
iconRes = R.drawable.ic_help_24dp
|
||||
iconTint = tintColor
|
||||
onClick {
|
||||
activity?.openInBrowser(URL_HELP)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View {
|
||||
if (untilDestroySubscriptions.isUnsubscribed) {
|
||||
untilDestroySubscriptions = CompositeSubscription()
|
||||
}
|
||||
|
||||
return super.onCreateView(inflater, container, savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onDestroyView(view: View) {
|
||||
super.onDestroyView(view)
|
||||
untilDestroySubscriptions.unsubscribe()
|
||||
}
|
||||
|
||||
private fun initDownloadQueueSummary(preference: Preference) {
|
||||
// Handle running/paused status change
|
||||
DownloadService.runningRelay
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeUntilDestroy { isRunning ->
|
||||
isDownloading = isRunning
|
||||
updateDownloadQueueSummary(preference)
|
||||
}
|
||||
|
||||
// Handle queue progress updating
|
||||
downloadManager.queue.getUpdatedObservable()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeUntilDestroy {
|
||||
downloadQueueSize = it.size
|
||||
updateDownloadQueueSummary(preference)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateDownloadQueueSummary(preference: Preference) {
|
||||
var pendingDownloadExists = downloadQueueSize != 0
|
||||
var pauseMessage = resources?.getString(R.string.paused)
|
||||
var numberOfPendingDownloads = resources?.getQuantityString(R.plurals.download_queue_summary, downloadQueueSize, downloadQueueSize)
|
||||
|
||||
preference.summary = when {
|
||||
!pendingDownloadExists -> null
|
||||
!isDownloading && !pendingDownloadExists -> pauseMessage
|
||||
!isDownloading && pendingDownloadExists -> "$pauseMessage • $numberOfPendingDownloads"
|
||||
else -> numberOfPendingDownloads
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> Observable<T>.subscribeUntilDestroy(onNext: (T) -> Unit): Subscription {
|
||||
return subscribe(onNext).also { untilDestroySubscriptions.add(it) }
|
||||
@Composable
|
||||
override fun ComposeContent(nestedScrollInterop: NestedScrollConnection) {
|
||||
MoreScreen(
|
||||
nestedScrollInterop = nestedScrollInterop,
|
||||
presenter = presenter,
|
||||
onClickDownloadQueue = { router.pushController(DownloadController()) },
|
||||
onClickCategories = { router.pushController(CategoryController()) },
|
||||
onClickBackupAndRestore = { router.pushController(SettingsBackupController()) },
|
||||
onClickSettings = { router.pushController(SettingsMainController()) },
|
||||
onClickAbout = { router.pushController(AboutController()) },
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
package eu.kanade.tachiyomi.ui.more
|
||||
|
||||
import android.os.Bundle
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.download.DownloadService
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.subscriptions.CompositeSubscription
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class MorePresenter(
|
||||
private val downloadManager: DownloadManager = Injekt.get(),
|
||||
preferencesHelper: PreferencesHelper = Injekt.get(),
|
||||
) : BasePresenter<MoreController>() {
|
||||
|
||||
val downloadedOnly = preferencesHelper.downloadedOnly().asState()
|
||||
val incognitoMode = preferencesHelper.incognitoMode().asState()
|
||||
|
||||
private var _state: MutableStateFlow<DownloadQueueState> = MutableStateFlow(DownloadQueueState.Stopped)
|
||||
val downloadQueueState: StateFlow<DownloadQueueState> = _state
|
||||
|
||||
private var isDownloading: Boolean = false
|
||||
private var downloadQueueSize: Int = 0
|
||||
private var untilDestroySubscriptions = CompositeSubscription()
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
if (untilDestroySubscriptions.isUnsubscribed) {
|
||||
untilDestroySubscriptions = CompositeSubscription()
|
||||
}
|
||||
|
||||
initDownloadQueueSummary()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
untilDestroySubscriptions.unsubscribe()
|
||||
}
|
||||
|
||||
private fun initDownloadQueueSummary() {
|
||||
// Handle running/paused status change
|
||||
DownloadService.runningRelay
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeUntilDestroy { isRunning ->
|
||||
isDownloading = isRunning
|
||||
updateDownloadQueueState()
|
||||
}
|
||||
|
||||
// Handle queue progress updating
|
||||
downloadManager.queue.getUpdatedObservable()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeUntilDestroy {
|
||||
downloadQueueSize = it.size
|
||||
updateDownloadQueueState()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateDownloadQueueState() {
|
||||
presenterScope.launchIO {
|
||||
val pendingDownloadExists = downloadQueueSize != 0
|
||||
_state.emit(
|
||||
when {
|
||||
!pendingDownloadExists -> DownloadQueueState.Stopped
|
||||
!isDownloading && !pendingDownloadExists -> DownloadQueueState.Paused(0)
|
||||
!isDownloading && pendingDownloadExists -> DownloadQueueState.Paused(downloadQueueSize)
|
||||
else -> DownloadQueueState.Downloading(downloadQueueSize)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> Observable<T>.subscribeUntilDestroy(onNext: (T) -> Unit): Subscription {
|
||||
return subscribe(onNext).also { untilDestroySubscriptions.add(it) }
|
||||
}
|
||||
}
|
||||
|
||||
sealed class DownloadQueueState {
|
||||
object Stopped : DownloadQueueState()
|
||||
data class Paused(val pending: Int) : DownloadQueueState()
|
||||
data class Downloading(val pending: Int) : DownloadQueueState()
|
||||
}
|
||||
Reference in New Issue
Block a user