Show not downloaded chapters in local manga
This commit is contained in:
@@ -15,7 +15,6 @@ import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseFragment
|
||||
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.databinding.FragmentChaptersBinding
|
||||
import org.koitharu.kotatsu.details.ui.adapter.BranchesAdapter
|
||||
@@ -27,7 +26,9 @@ import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderState
|
||||
|
||||
class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
||||
OnListItemClickListener<MangaChapter>, ActionMode.Callback, AdapterView.OnItemSelectedListener {
|
||||
OnListItemClickListener<ChapterListItem>,
|
||||
ActionMode.Callback,
|
||||
AdapterView.OnItemSelectedListener {
|
||||
|
||||
private val viewModel by sharedViewModel<DetailsViewModel>()
|
||||
|
||||
@@ -105,9 +106,9 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onItemClick(item: MangaChapter, view: View) {
|
||||
override fun onItemClick(item: ChapterListItem, view: View) {
|
||||
if (selectionDecoration?.checkedItemsCount != 0) {
|
||||
selectionDecoration?.toggleItemChecked(item.id)
|
||||
selectionDecoration?.toggleItemChecked(item.chapter.id)
|
||||
if (selectionDecoration?.checkedItemsCount == 0) {
|
||||
actionMode?.finish()
|
||||
} else {
|
||||
@@ -116,6 +117,10 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
||||
}
|
||||
return
|
||||
}
|
||||
if (item.isMissing) {
|
||||
(activity as? DetailsActivity)?.showChapterMissingDialog(item.chapter.id)
|
||||
return
|
||||
}
|
||||
val options = ActivityOptions.makeScaleUpAnimation(
|
||||
view,
|
||||
0,
|
||||
@@ -127,17 +132,17 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
||||
ReaderActivity.newIntent(
|
||||
view.context,
|
||||
viewModel.manga.value ?: return,
|
||||
ReaderState(item.id, 0, 0)
|
||||
ReaderState(item.chapter.id, 0, 0)
|
||||
), options.toBundle()
|
||||
)
|
||||
}
|
||||
|
||||
override fun onItemLongClick(item: MangaChapter, view: View): Boolean {
|
||||
override fun onItemLongClick(item: ChapterListItem, view: View): Boolean {
|
||||
if (actionMode == null) {
|
||||
actionMode = (activity as? AppCompatActivity)?.startSupportActionMode(this)
|
||||
}
|
||||
return actionMode?.also {
|
||||
selectionDecoration?.setItemIsChecked(item.id, true)
|
||||
selectionDecoration?.setItemIsChecked(item.chapter.id, true)
|
||||
binding.recyclerViewChapters.invalidateItemDecorations()
|
||||
it.invalidate()
|
||||
} != null
|
||||
@@ -148,7 +153,7 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
||||
R.id.action_save -> {
|
||||
DownloadService.start(
|
||||
context ?: return false,
|
||||
viewModel.manga.value ?: return false,
|
||||
viewModel.getRemoteManga() ?: viewModel.manga.value ?: return false,
|
||||
selectionDecoration?.checkedItemsIds
|
||||
)
|
||||
mode.finish()
|
||||
@@ -174,17 +179,20 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
val manga = viewModel.manga.value
|
||||
mode.menuInflater.inflate(R.menu.mode_chapters, menu)
|
||||
menu.findItem(R.id.action_save).isVisible = manga?.source != MangaSource.LOCAL
|
||||
mode.title = manga?.title
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
val count = selectionDecoration?.checkedItemsCount ?: return false
|
||||
val selectedIds = selectionDecoration?.checkedItemsIds ?: return false
|
||||
val items = chaptersAdapter?.items?.filter { x -> x.chapter.id in selectedIds }.orEmpty()
|
||||
menu.findItem(R.id.action_save).isVisible = items.none { x ->
|
||||
x.chapter.source == MangaSource.LOCAL
|
||||
}
|
||||
mode.subtitle = resources.getQuantityString(
|
||||
R.plurals.chapters_from_x,
|
||||
count,
|
||||
count,
|
||||
items.size,
|
||||
items.size,
|
||||
chaptersAdapter?.itemCount ?: 0
|
||||
)
|
||||
return true
|
||||
|
||||
@@ -34,8 +34,11 @@ import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.os.ShortcutsRepository
|
||||
import org.koitharu.kotatsu.databinding.ActivityDetailsBinding
|
||||
import org.koitharu.kotatsu.download.ui.service.DownloadService
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderState
|
||||
import org.koitharu.kotatsu.search.ui.global.GlobalSearchActivity
|
||||
import org.koitharu.kotatsu.utils.ShareHelper
|
||||
import org.koitharu.kotatsu.utils.ext.buildAlertDialog
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
|
||||
class DetailsActivity : BaseActivity<ActivityDetailsBinding>(),
|
||||
@@ -228,6 +231,33 @@ class DetailsActivity : BaseActivity<ActivityDetailsBinding>(),
|
||||
binding.pager.isUserInputEnabled = true
|
||||
}
|
||||
|
||||
fun showChapterMissingDialog(chapterId: Long) {
|
||||
val remoteManga = viewModel.getRemoteManga()
|
||||
if (remoteManga == null) {
|
||||
Snackbar.make(binding.pager, R.string.chapter_is_missing, Snackbar.LENGTH_LONG)
|
||||
.show()
|
||||
return
|
||||
}
|
||||
buildAlertDialog(this) {
|
||||
setMessage(R.string.chapter_is_missing_text)
|
||||
setTitle(R.string.chapter_is_missing)
|
||||
setNegativeButton(android.R.string.cancel, null)
|
||||
setPositiveButton(R.string.read) { _, _ ->
|
||||
startActivity(
|
||||
ReaderActivity.newIntent(
|
||||
this@DetailsActivity,
|
||||
remoteManga,
|
||||
ReaderState(chapterId, 0, 0)
|
||||
)
|
||||
)
|
||||
}
|
||||
setNeutralButton(R.string.download) { _, _ ->
|
||||
DownloadService.start(this@DetailsActivity, remoteManga, setOf(chapterId))
|
||||
}
|
||||
setCancelable(true)
|
||||
}.show()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val ACTION_MANGA_VIEW = "${BuildConfig.APPLICATION_ID}.action.VIEW_MANGA"
|
||||
|
||||
@@ -128,23 +128,32 @@ class DetailsFragment : BaseFragment<FragmentDetailsBinding>(), View.OnClickList
|
||||
}
|
||||
|
||||
private fun onLoadingStateChanged(isLoading: Boolean) {
|
||||
binding.progressBar.isVisible = isLoading
|
||||
if (isLoading) {
|
||||
binding.progressBar.show()
|
||||
} else {
|
||||
binding.progressBar.hide()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
val manga = viewModel.manga.value
|
||||
val manga = viewModel.manga.value ?: return
|
||||
when (v.id) {
|
||||
R.id.button_favorite -> {
|
||||
FavouriteCategoriesDialog.show(childFragmentManager, manga ?: return)
|
||||
FavouriteCategoriesDialog.show(childFragmentManager, manga)
|
||||
}
|
||||
R.id.button_read -> {
|
||||
startActivity(
|
||||
ReaderActivity.newIntent(
|
||||
context ?: return,
|
||||
manga ?: return,
|
||||
null
|
||||
val chapterId = viewModel.readingHistory.value?.chapterId
|
||||
if (chapterId != null && manga.chapters?.none { x -> x.id == chapterId } == true) {
|
||||
(activity as? DetailsActivity)?.showChapterMissingDialog(chapterId)
|
||||
} else {
|
||||
startActivity(
|
||||
ReaderActivity.newIntent(
|
||||
context ?: return,
|
||||
manga,
|
||||
null
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,11 @@ import org.koitharu.kotatsu.base.domain.MangaIntent
|
||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.exceptions.MangaNotFoundException
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
|
||||
import org.koitharu.kotatsu.details.ui.model.toListItem
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.history.domain.ChapterExtra
|
||||
@@ -29,7 +33,7 @@ class DetailsViewModel(
|
||||
private val localMangaRepository: LocalMangaRepository,
|
||||
private val trackingRepository: TrackingRepository,
|
||||
private val mangaDataRepository: MangaDataRepository,
|
||||
private val settings: AppSettings
|
||||
private val settings: AppSettings,
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val mangaData = MutableStateFlow<Manga?>(intent.manga)
|
||||
@@ -53,6 +57,18 @@ class DetailsViewModel(
|
||||
trackingRepository.getNewChaptersCount(mangaId)
|
||||
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, 0)
|
||||
|
||||
private val remoteManga = MutableStateFlow<Manga?>(null)
|
||||
/*private val remoteManga = mangaData.mapLatest {
|
||||
if (it?.source == MangaSource.LOCAL) {
|
||||
runCatching {
|
||||
val m = localMangaRepository.getRemoteManga(it) ?: return@mapLatest null
|
||||
MangaRepository(m.source).getDetails(m)
|
||||
}.getOrNull()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null)*/
|
||||
|
||||
private val chaptersReversed = settings.observe()
|
||||
.filter { it == AppSettings.KEY_REVERSE_CHAPTERS }
|
||||
.map { settings.chaptersReverse }
|
||||
@@ -85,24 +101,19 @@ class DetailsViewModel(
|
||||
|
||||
val chapters = combine(
|
||||
mangaData.map { it?.chapters.orEmpty() },
|
||||
remoteManga,
|
||||
history.map { it?.chapterId },
|
||||
newChapters,
|
||||
chaptersReversed,
|
||||
selectedBranch
|
||||
) { chapters, currentId, newCount, reversed, branch ->
|
||||
val currentIndex = chapters.indexOfFirst { it.id == currentId }
|
||||
val firstNewIndex = chapters.size - newCount
|
||||
val res = chapters.mapIndexed { index, chapter ->
|
||||
chapter.toListItem(
|
||||
when {
|
||||
index >= firstNewIndex -> ChapterExtra.NEW
|
||||
index == currentIndex -> ChapterExtra.CURRENT
|
||||
index < currentIndex -> ChapterExtra.READ
|
||||
else -> ChapterExtra.UNREAD
|
||||
}
|
||||
)
|
||||
}.filter { it.chapter.branch == branch }
|
||||
if (reversed) res.asReversed() else res
|
||||
) { chapters, sourceManga, currentId, newCount, branch ->
|
||||
val sourceChapters = sourceManga?.chapters
|
||||
if (sourceChapters.isNullOrEmpty()) {
|
||||
mapChapters(chapters, currentId, newCount, branch)
|
||||
} else {
|
||||
mapChaptersWithSource(chapters, sourceChapters, currentId, newCount, branch)
|
||||
}
|
||||
}.combine(chaptersReversed) { list, reversed ->
|
||||
if (reversed) list.asReversed() else list
|
||||
}.asLiveData(viewModelScope.coroutineContext + Dispatchers.Default)
|
||||
|
||||
init {
|
||||
@@ -121,6 +132,12 @@ class DetailsViewModel(
|
||||
?.maxByOrNull { it.value.size }?.key
|
||||
}
|
||||
mangaData.value = manga
|
||||
if (manga.source == MangaSource.LOCAL) {
|
||||
remoteManga.value = runCatching {
|
||||
val m = localMangaRepository.getRemoteManga(manga) ?: return@runCatching null
|
||||
MangaRepository(m.source).getDetails(m)
|
||||
}.getOrNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,4 +159,80 @@ class DetailsViewModel(
|
||||
fun setSelectedBranch(branch: String?) {
|
||||
selectedBranch.value = branch
|
||||
}
|
||||
|
||||
fun getRemoteManga(): Manga? {
|
||||
return remoteManga.value
|
||||
}
|
||||
|
||||
private fun mapChapters(
|
||||
chapters: List<MangaChapter>,
|
||||
currentId: Long?,
|
||||
newCount: Int,
|
||||
branch: String?,
|
||||
): List<ChapterListItem> {
|
||||
val result = ArrayList<ChapterListItem>(chapters.size)
|
||||
val currentIndex = chapters.indexOfFirst { it.id == currentId }
|
||||
val firstNewIndex = chapters.size - newCount
|
||||
for (i in chapters.indices) {
|
||||
val chapter = chapters[i]
|
||||
if (chapter.branch != branch) {
|
||||
continue
|
||||
}
|
||||
result += chapter.toListItem(
|
||||
extra = when {
|
||||
i >= firstNewIndex -> ChapterExtra.NEW
|
||||
i == currentIndex -> ChapterExtra.CURRENT
|
||||
i < currentIndex -> ChapterExtra.READ
|
||||
else -> ChapterExtra.UNREAD
|
||||
},
|
||||
isMissing = false
|
||||
)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun mapChaptersWithSource(
|
||||
chapters: List<MangaChapter>,
|
||||
sourceChapters: List<MangaChapter>,
|
||||
currentId: Long?,
|
||||
newCount: Int,
|
||||
branch: String?,
|
||||
): List<ChapterListItem> {
|
||||
val chaptersMap = chapters.associateByTo(HashMap(chapters.size)) { it.id }
|
||||
val result = ArrayList<ChapterListItem>(sourceChapters.size)
|
||||
val currentIndex = sourceChapters.indexOfFirst { it.id == currentId }
|
||||
val firstNewIndex = sourceChapters.size - newCount
|
||||
for (i in sourceChapters.indices) {
|
||||
val chapter = sourceChapters[i]
|
||||
if (chapter.branch != branch) {
|
||||
continue
|
||||
}
|
||||
val localChapter = chaptersMap.remove(chapter.id)
|
||||
result += localChapter?.toListItem(
|
||||
extra = when {
|
||||
i >= firstNewIndex -> ChapterExtra.NEW
|
||||
i == currentIndex -> ChapterExtra.CURRENT
|
||||
i < currentIndex -> ChapterExtra.READ
|
||||
else -> ChapterExtra.UNREAD
|
||||
},
|
||||
isMissing = false
|
||||
) ?: chapter.toListItem(
|
||||
extra = when {
|
||||
i >= firstNewIndex -> ChapterExtra.NEW
|
||||
i == currentIndex -> ChapterExtra.CURRENT
|
||||
i < currentIndex -> ChapterExtra.READ
|
||||
else -> ChapterExtra.UNREAD
|
||||
},
|
||||
isMissing = true
|
||||
)
|
||||
}
|
||||
if (chaptersMap.isNotEmpty()) { // some chapters on device but not online source
|
||||
result.ensureCapacity(result.size + chaptersMap.size)
|
||||
chaptersMap.values.mapTo(result) {
|
||||
it.toListItem(ChapterExtra.UNREAD, false)
|
||||
}
|
||||
result.sortBy { it.chapter.number }
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -3,23 +3,22 @@ package org.koitharu.kotatsu.details.ui.adapter
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.databinding.ItemChapterBinding
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
|
||||
import org.koitharu.kotatsu.history.domain.ChapterExtra
|
||||
import org.koitharu.kotatsu.utils.ext.getThemeColor
|
||||
|
||||
fun chapterListItemAD(
|
||||
clickListener: OnListItemClickListener<MangaChapter>
|
||||
clickListener: OnListItemClickListener<ChapterListItem>,
|
||||
) = adapterDelegateViewBinding<ChapterListItem, ChapterListItem, ItemChapterBinding>(
|
||||
{ inflater, parent -> ItemChapterBinding.inflate(inflater, parent, false) }
|
||||
) {
|
||||
|
||||
itemView.setOnClickListener {
|
||||
clickListener.onItemClick(item.chapter, it)
|
||||
clickListener.onItemClick(item, it)
|
||||
}
|
||||
itemView.setOnLongClickListener {
|
||||
clickListener.onItemLongClick(item.chapter, it)
|
||||
clickListener.onItemLongClick(item, it)
|
||||
}
|
||||
|
||||
bind { payload ->
|
||||
@@ -43,5 +42,7 @@ fun chapterListItemAD(
|
||||
binding.textViewNumber.setTextColor(context.getThemeColor(android.R.attr.textColorPrimaryInverse))
|
||||
}
|
||||
}
|
||||
binding.textViewTitle.alpha = if (item.isMissing) 0.3f else 1f
|
||||
binding.textViewNumber.alpha = if (item.isMissing) 0.3f else 1f
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,11 @@ package org.koitharu.kotatsu.details.ui.adapter
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
|
||||
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
|
||||
import kotlin.jvm.internal.Intrinsics
|
||||
|
||||
class ChaptersAdapter(
|
||||
onItemClickListener: OnListItemClickListener<MangaChapter>
|
||||
onItemClickListener: OnListItemClickListener<ChapterListItem>,
|
||||
) : AsyncListDifferDelegationAdapter<ChapterListItem>(DiffCallback()) {
|
||||
|
||||
init {
|
||||
@@ -38,7 +37,7 @@ class ChaptersAdapter(
|
||||
}
|
||||
|
||||
override fun getChangePayload(oldItem: ChapterListItem, newItem: ChapterListItem): Any? {
|
||||
if (oldItem.extra != newItem.extra) {
|
||||
if (oldItem.extra != newItem.extra && oldItem.chapter == newItem.chapter) {
|
||||
return newItem.extra
|
||||
}
|
||||
return null
|
||||
|
||||
@@ -5,5 +5,6 @@ import org.koitharu.kotatsu.history.domain.ChapterExtra
|
||||
|
||||
data class ChapterListItem(
|
||||
val chapter: MangaChapter,
|
||||
val extra: ChapterExtra
|
||||
val extra: ChapterExtra,
|
||||
val isMissing: Boolean,
|
||||
)
|
||||
|
||||
@@ -3,7 +3,11 @@ package org.koitharu.kotatsu.details.ui.model
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.history.domain.ChapterExtra
|
||||
|
||||
fun MangaChapter.toListItem(extra: ChapterExtra) = ChapterListItem(
|
||||
fun MangaChapter.toListItem(
|
||||
extra: ChapterExtra,
|
||||
isMissing: Boolean,
|
||||
) = ChapterListItem(
|
||||
chapter = this,
|
||||
extra = extra
|
||||
extra = extra,
|
||||
isMissing = isMissing,
|
||||
)
|
||||
@@ -47,6 +47,7 @@ class DownloadService : BaseService() {
|
||||
private val jobCount = MutableStateFlow(0)
|
||||
private val mutex = Mutex()
|
||||
private val controlReceiver = ControlReceiver()
|
||||
private var binder: DownloadBinder? = null
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
@@ -75,11 +76,12 @@ class DownloadService : BaseService() {
|
||||
|
||||
override fun onBind(intent: Intent): IBinder {
|
||||
super.onBind(intent)
|
||||
return DownloadBinder()
|
||||
return binder ?: DownloadBinder(this).also { binder = it }
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
unregisterReceiver(controlReceiver)
|
||||
binder = null
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
@@ -141,10 +143,10 @@ class DownloadService : BaseService() {
|
||||
}
|
||||
}
|
||||
|
||||
inner class DownloadBinder : Binder() {
|
||||
class DownloadBinder(private val service: DownloadService) : Binder() {
|
||||
|
||||
val downloads: Flow<Collection<JobStateFlow<DownloadManager.State>>>
|
||||
get() = jobCount.mapLatest { jobs.values }
|
||||
get() = service.jobCount.mapLatest { service.jobs.values }
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -160,6 +162,9 @@ class DownloadService : BaseService() {
|
||||
private const val EXTRA_CANCEL_ID = "cancel_id"
|
||||
|
||||
fun start(context: Context, manga: Manga, chaptersIds: Collection<Long>? = null) {
|
||||
if (chaptersIds?.isEmpty() == true) {
|
||||
return
|
||||
}
|
||||
confirmDataTransfer(context) {
|
||||
val intent = Intent(context, DownloadService::class.java)
|
||||
intent.putExtra(EXTRA_MANGA, manga)
|
||||
|
||||
@@ -98,7 +98,10 @@ class LocalMangaRepository(private val context: Context) : MangaRepository {
|
||||
entryName = index.getCoverEntry()
|
||||
?: findFirstEntry(zip.entries(), isImage = true)?.name.orEmpty()
|
||||
),
|
||||
chapters = info.chapters?.map { c -> c.copy(url = fileUri) }
|
||||
chapters = info.chapters?.map { c ->
|
||||
c.copy(url = fileUri,
|
||||
source = MangaSource.LOCAL)
|
||||
}
|
||||
)
|
||||
}
|
||||
// fallback
|
||||
|
||||
@@ -15,16 +15,17 @@ import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.databinding.DialogChaptersBinding
|
||||
import org.koitharu.kotatsu.details.ui.adapter.ChaptersAdapter
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
|
||||
import org.koitharu.kotatsu.details.ui.model.toListItem
|
||||
import org.koitharu.kotatsu.history.domain.ChapterExtra
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
|
||||
class ChaptersDialog : AlertDialogFragment<DialogChaptersBinding>(),
|
||||
OnListItemClickListener<MangaChapter> {
|
||||
OnListItemClickListener<ChapterListItem> {
|
||||
|
||||
override fun onInflateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?
|
||||
container: ViewGroup?,
|
||||
) = DialogChaptersBinding.inflate(inflater, container, false)
|
||||
|
||||
override fun onBuildDialog(builder: AlertDialog.Builder) {
|
||||
@@ -51,7 +52,8 @@ class ChaptersDialog : AlertDialogFragment<DialogChaptersBinding>(),
|
||||
index < currentPosition -> ChapterExtra.READ
|
||||
index == currentPosition -> ChapterExtra.CURRENT
|
||||
else -> ChapterExtra.UNREAD
|
||||
}
|
||||
},
|
||||
isMissing = false
|
||||
)
|
||||
}) {
|
||||
if (currentPosition >= 0) {
|
||||
@@ -66,11 +68,11 @@ class ChaptersDialog : AlertDialogFragment<DialogChaptersBinding>(),
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemClick(item: MangaChapter, view: View) {
|
||||
override fun onItemClick(item: ChapterListItem, view: View) {
|
||||
((parentFragment as? OnChapterChangeListener)
|
||||
?: (activity as? OnChapterChangeListener))?.let {
|
||||
dismiss()
|
||||
it.onChapterChanged(item)
|
||||
it.onChapterChanged(item.chapter)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package org.koitharu.kotatsu.utils.ext
|
||||
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkRequest
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
@@ -19,4 +21,8 @@ suspend fun ConnectivityManager.waitForNetwork(): Network {
|
||||
unregisterNetworkCallback(callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun buildAlertDialog(context: Context, block: AlertDialog.Builder.() -> Unit): AlertDialog {
|
||||
return AlertDialog.Builder(context).apply(block).create()
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.utils.ext
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.transform
|
||||
|
||||
fun <T> Flow<T>.onFirst(action: suspend (T) -> Unit): Flow<T> {
|
||||
var isFirstCall = true
|
||||
@@ -16,4 +17,10 @@ fun <T> Flow<T>.onFirst(action: suspend (T) -> Unit): Flow<T> {
|
||||
|
||||
inline fun <T, R> Flow<List<T>>.mapItems(crossinline transform: (T) -> R): Flow<List<R>> {
|
||||
return map { list -> list.map(transform) }
|
||||
}
|
||||
|
||||
inline fun <T> Flow<T?>.filterNotNull(
|
||||
crossinline predicate: suspend (T) -> Boolean,
|
||||
): Flow<T> = transform { value ->
|
||||
if (value != null && predicate(value)) return@transform emit(value)
|
||||
}
|
||||
@@ -263,13 +263,15 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ProgressBar
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:id="@+id/progressBar"
|
||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"
|
||||
app:showAnimationBehavior="inward"
|
||||
app:hideAnimationBehavior="outward"
|
||||
app:layout_constraintBottom_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
||||
@@ -270,13 +270,15 @@
|
||||
tools:ignore="UnusedAttribute"
|
||||
tools:text="@tools:sample/lorem/random[25]" />
|
||||
|
||||
<ProgressBar
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:id="@+id/progressBar"
|
||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"
|
||||
app:showAnimationBehavior="inward"
|
||||
app:hideAnimationBehavior="outward"
|
||||
app:layout_constraintBottom_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
||||
@@ -277,6 +277,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"
|
||||
app:showAnimationBehavior="inward"
|
||||
app:hideAnimationBehavior="outward"
|
||||
app:layout_constraintBottom_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
||||
@@ -222,4 +222,6 @@
|
||||
<string name="read_more">Read more</string>
|
||||
<string name="queued">Queued</string>
|
||||
<string name="text_downloads_holder">There are currently no active downloads</string>
|
||||
<string name="chapter_is_missing_text">This chapter is missing on your device. Download it or read online</string>
|
||||
<string name="chapter_is_missing">Chapter is missing</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user