Related manga activity
parent
297029a659
commit
80149b1ce7
@ -0,0 +1,24 @@
|
|||||||
|
package org.koitharu.kotatsu.details.ui.related
|
||||||
|
|
||||||
|
import android.view.Menu
|
||||||
|
import androidx.appcompat.view.ActionMode
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.core.ui.list.ListSelectionController
|
||||||
|
import org.koitharu.kotatsu.list.ui.MangaListFragment
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class RelatedListFragment : MangaListFragment() {
|
||||||
|
|
||||||
|
override val viewModel by viewModels<RelatedListViewModel>()
|
||||||
|
override val isSwipeRefreshEnabled = false
|
||||||
|
|
||||||
|
override fun onScrolledToEnd() = Unit
|
||||||
|
|
||||||
|
override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||||
|
mode.menuInflater.inflate(R.menu.mode_remote, menu)
|
||||||
|
return super.onCreateActionMode(controller, mode, menu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,99 @@
|
|||||||
|
package org.koitharu.kotatsu.details.ui.related
|
||||||
|
|
||||||
|
import androidx.lifecycle.SavedStateHandle
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
import kotlinx.coroutines.plus
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||||
|
import org.koitharu.kotatsu.core.parser.MangaIntent
|
||||||
|
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||||
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.call
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.require
|
||||||
|
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
||||||
|
import org.koitharu.kotatsu.list.domain.ListExtraProvider
|
||||||
|
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.LoadingState
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.toErrorState
|
||||||
|
import org.koitharu.kotatsu.list.ui.model.toUi
|
||||||
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class RelatedListViewModel @Inject constructor(
|
||||||
|
savedStateHandle: SavedStateHandle,
|
||||||
|
mangaRepositoryFactory: MangaRepository.Factory,
|
||||||
|
settings: AppSettings,
|
||||||
|
private val extraProvider: ListExtraProvider,
|
||||||
|
downloadScheduler: DownloadWorker.Scheduler,
|
||||||
|
) : MangaListViewModel(settings, downloadScheduler) {
|
||||||
|
|
||||||
|
private val seed = savedStateHandle.require<ParcelableManga>(MangaIntent.KEY_MANGA).manga
|
||||||
|
private val repository = mangaRepositoryFactory.create(seed.source)
|
||||||
|
private val mangaList = MutableStateFlow<List<Manga>?>(null)
|
||||||
|
private val listError = MutableStateFlow<Throwable?>(null)
|
||||||
|
private var loadingJob: Job? = null
|
||||||
|
|
||||||
|
override val content = combine(
|
||||||
|
mangaList,
|
||||||
|
listMode,
|
||||||
|
listError,
|
||||||
|
) { list, mode, error ->
|
||||||
|
when {
|
||||||
|
list.isNullOrEmpty() && error != null -> listOf(error.toErrorState(canRetry = true))
|
||||||
|
list == null -> listOf(LoadingState)
|
||||||
|
list.isEmpty() -> listOf(createEmptyState())
|
||||||
|
else -> list.toUi(mode, extraProvider)
|
||||||
|
}
|
||||||
|
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState))
|
||||||
|
|
||||||
|
init {
|
||||||
|
loadList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRefresh() {
|
||||||
|
loadList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRetry() {
|
||||||
|
loadList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadList(): Job {
|
||||||
|
loadingJob?.let {
|
||||||
|
if (it.isActive) return it
|
||||||
|
}
|
||||||
|
return launchLoadingJob(Dispatchers.Default) {
|
||||||
|
try {
|
||||||
|
listError.value = null
|
||||||
|
mangaList.value = repository.getRelated(seed)
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
throw e
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
e.printStackTraceDebug()
|
||||||
|
listError.value = e
|
||||||
|
if (!mangaList.value.isNullOrEmpty()) {
|
||||||
|
errorEvent.call(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.also { loadingJob = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createEmptyState() = EmptyState(
|
||||||
|
icon = R.drawable.ic_empty_common,
|
||||||
|
textPrimary = R.string.nothing_found,
|
||||||
|
textSecondary = 0,
|
||||||
|
actionStringRes = 0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
package org.koitharu.kotatsu.details.ui.related
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.core.graphics.Insets
|
||||||
|
import androidx.core.view.updatePadding
|
||||||
|
import androidx.fragment.app.commit
|
||||||
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||||
|
import org.koitharu.kotatsu.core.parser.MangaIntent
|
||||||
|
import org.koitharu.kotatsu.core.ui.BaseActivity
|
||||||
|
import org.koitharu.kotatsu.databinding.ActivityContainerBinding
|
||||||
|
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
|
||||||
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class RelatedMangaActivity : BaseActivity<ActivityContainerBinding>(), AppBarOwner {
|
||||||
|
|
||||||
|
override val appBar: AppBarLayout
|
||||||
|
get() = viewBinding.appbar
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(ActivityContainerBinding.inflate(layoutInflater))
|
||||||
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
val fm = supportFragmentManager
|
||||||
|
if (fm.findFragmentById(R.id.container) == null) {
|
||||||
|
fm.commit {
|
||||||
|
setReorderingAllowed(true)
|
||||||
|
replace(R.id.container, RelatedListFragment::class.java, intent.extras)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onWindowInsetsChanged(insets: Insets) {
|
||||||
|
viewBinding.root.updatePadding(
|
||||||
|
left = insets.left,
|
||||||
|
right = insets.right,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun newIntent(context: Context, seed: Manga) = Intent(context, RelatedMangaActivity::class.java)
|
||||||
|
.putExtra(MangaIntent.KEY_MANGA, ParcelableManga(seed, withChapters = false))
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue