Pages thumbnails sheet
This commit is contained in:
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.ui.common.list
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import okhttp3.internal.toImmutableList
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koitharu.kotatsu.utils.ext.replaceWith
|
||||
|
||||
@@ -11,6 +12,8 @@ abstract class BaseRecyclerAdapter<T, E>(private val onItemClickListener: OnRecy
|
||||
|
||||
protected val dataSet = ArrayList<T>()
|
||||
|
||||
val items get() = dataSet.toImmutableList()
|
||||
|
||||
init {
|
||||
@Suppress("LeakingThis")
|
||||
setHasStableIds(true)
|
||||
|
||||
@@ -35,8 +35,8 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
navigationView.setNavigationItemSelectedListener(this)
|
||||
|
||||
if (supportFragmentManager.findFragmentById(R.id.container) == null) {
|
||||
navigationView.setCheckedItem(R.id.nav_local_storage)
|
||||
setPrimaryFragment(LocalListFragment.newInstance())
|
||||
navigationView.setCheckedItem(R.id.nav_history)
|
||||
setPrimaryFragment(HistoryListFragment.newInstance())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,14 @@ import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import org.koitharu.kotatsu.core.model.MangaPage
|
||||
import org.koitharu.kotatsu.ui.common.BaseFullscreenActivity
|
||||
import org.koitharu.kotatsu.ui.reader.thumbnails.OnPageSelectListener
|
||||
import org.koitharu.kotatsu.ui.reader.thumbnails.PagesThumbnailsSheet
|
||||
import org.koitharu.kotatsu.utils.GridTouchHelper
|
||||
import org.koitharu.kotatsu.utils.anim.Motion
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
|
||||
class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnChapterChangeListener,
|
||||
GridTouchHelper.OnGridTouchListener {
|
||||
GridTouchHelper.OnGridTouchListener, OnPageSelectListener {
|
||||
|
||||
private val presenter by moxyPresenter(factory = ::ReaderPresenter)
|
||||
|
||||
@@ -39,6 +41,7 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
touchHelper = GridTouchHelper(this, this)
|
||||
toolbar_bottom.inflateMenu(R.menu.opt_reader_bottom)
|
||||
toolbar_bottom.setOnMenuItemClickListener(::onOptionsItemSelected)
|
||||
|
||||
state = savedInstanceState?.getParcelable(EXTRA_STATE)
|
||||
?: intent.getParcelableExtra<ReaderState>(EXTRA_STATE)
|
||||
@@ -90,6 +93,13 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh
|
||||
)
|
||||
true
|
||||
}
|
||||
R.id.action_pages_thumbs -> {
|
||||
PagesThumbnailsSheet.show(
|
||||
supportFragmentManager, adapter.items,
|
||||
state.chapter?.name ?: title?.toString().orEmpty()
|
||||
)
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
@@ -135,7 +145,11 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh
|
||||
}
|
||||
|
||||
override fun onProcessTouch(rawX: Int, rawY: Int): Boolean {
|
||||
return if (appbar_top.hasGlobalPoint(rawX, rawY) || appbar_bottom.hasGlobalPoint(rawX, rawY)) {
|
||||
return if (appbar_top.hasGlobalPoint(rawX, rawY) || appbar_bottom.hasGlobalPoint(
|
||||
rawX,
|
||||
rawY
|
||||
)
|
||||
) {
|
||||
false
|
||||
} else {
|
||||
val target = rootLayout.hitTest(rawX, rawY)
|
||||
@@ -149,10 +163,19 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh
|
||||
}
|
||||
|
||||
override fun onChapterChanged(chapter: MangaChapter) {
|
||||
presenter.loadChapter(state.copy(
|
||||
chapterId = chapter.id,
|
||||
page = 0
|
||||
))
|
||||
presenter.loadChapter(
|
||||
state.copy(
|
||||
chapterId = chapter.id,
|
||||
page = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onPageSelected(page: MangaPage) {
|
||||
val index = adapter.items.indexOfFirst { x -> x.id == page.id }
|
||||
if (index != -1) {
|
||||
pager.setCurrentItem(index, false)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.koitharu.kotatsu.ui.reader.thumbnails
|
||||
|
||||
import org.koitharu.kotatsu.core.model.MangaPage
|
||||
|
||||
interface OnPageSelectListener {
|
||||
|
||||
fun onPageSelected(page: MangaPage)
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.koitharu.kotatsu.ui.reader.thumbnails
|
||||
|
||||
import android.view.ViewGroup
|
||||
import coil.Coil
|
||||
import coil.api.get
|
||||
import kotlinx.android.synthetic.main.item_page_thumb.*
|
||||
import kotlinx.coroutines.*
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaPage
|
||||
import org.koitharu.kotatsu.domain.MangaProviderFactory
|
||||
import org.koitharu.kotatsu.ui.common.list.BaseViewHolder
|
||||
import org.koitharu.kotatsu.utils.DrawUtils
|
||||
import org.koitharu.kotatsu.utils.ext.resolveDp
|
||||
|
||||
class PageThumbnailHolder(parent: ViewGroup, private val scope: CoroutineScope) :
|
||||
BaseViewHolder<MangaPage, Unit>(parent, R.layout.item_page_thumb) {
|
||||
|
||||
private var job: Job? = null
|
||||
|
||||
init {
|
||||
val color = DrawUtils.invertColor(textView_number.currentTextColor)
|
||||
textView_number.setShadowLayer(parent.resources.resolveDp(26f), 0f, 0f, color)
|
||||
}
|
||||
|
||||
override fun onBind(data: MangaPage, extra: Unit) {
|
||||
imageView_thumb.setImageDrawable(null)
|
||||
textView_number.text = (adapterPosition + 1).toString()
|
||||
job?.cancel()
|
||||
job = scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val url = data.preview ?: data.url.let {
|
||||
MangaProviderFactory.create(data.source).getPageFullUrl(data)
|
||||
}
|
||||
val drawable = Coil.get(url) {
|
||||
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
imageView_thumb.setImageDrawable(drawable)
|
||||
}
|
||||
} catch (e: CancellationException) {
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.koitharu.kotatsu.ui.reader.thumbnails
|
||||
|
||||
import android.view.ViewGroup
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.DisposableHandle
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import org.koitharu.kotatsu.core.model.MangaPage
|
||||
import org.koitharu.kotatsu.ui.common.list.BaseRecyclerAdapter
|
||||
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class PagesThumbnailsAdapter(onItemClickListener: OnRecyclerItemClickListener<MangaPage>?) :
|
||||
BaseRecyclerAdapter<MangaPage, Unit>(onItemClickListener), CoroutineScope, DisposableHandle {
|
||||
|
||||
private val job = SupervisorJob()
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.Main + job
|
||||
|
||||
override fun dispose() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
override fun getExtra(item: MangaPage, position: Int) = Unit
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup) = PageThumbnailHolder(parent, this)
|
||||
|
||||
override fun onGetItemId(item: MangaPage) = item.id
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package org.koitharu.kotatsu.ui.reader.thumbnails
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import kotlinx.android.synthetic.main.sheet_pages.*
|
||||
import kotlinx.coroutines.DisposableHandle
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaPage
|
||||
import org.koitharu.kotatsu.ui.common.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
|
||||
import org.koitharu.kotatsu.ui.common.list.decor.SpacingItemDecoration
|
||||
import org.koitharu.kotatsu.utils.ext.resolveDp
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
|
||||
class PagesThumbnailsSheet : BaseBottomSheet(R.layout.sheet_pages),
|
||||
OnRecyclerItemClickListener<MangaPage> {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
recyclerView.addItemDecoration(SpacingItemDecoration(view.resources.resolveDp(8)))
|
||||
val pages = arguments?.getParcelableArrayList<MangaPage>(ARG_PAGES)
|
||||
if (pages != null) {
|
||||
recyclerView.adapter = PagesThumbnailsAdapter(this).apply {
|
||||
replaceData(pages)
|
||||
}
|
||||
} else {
|
||||
dismissAllowingStateLoss()
|
||||
return
|
||||
}
|
||||
val title = arguments?.getString(ARG_TITLE)
|
||||
toolbar.title = title
|
||||
toolbar.setNavigationOnClickListener { dismiss() }
|
||||
toolbar.subtitle = resources.getQuantityString(R.plurals.pages, pages.size, pages.size)
|
||||
textView_title.text = title
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?) =
|
||||
super.onCreateDialog(savedInstanceState).also {
|
||||
val behavior = (it as BottomSheetDialog).behavior
|
||||
behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
|
||||
private val elevation = resources.getDimension(R.dimen.elevation_large)
|
||||
|
||||
override fun onSlide(bottomSheet: View, slideOffset: Float) = Unit
|
||||
|
||||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
||||
if (newState == BottomSheetBehavior.STATE_EXPANDED) {
|
||||
toolbar.isVisible = true
|
||||
appbar.elevation = elevation
|
||||
} else {
|
||||
toolbar.isVisible = false
|
||||
appbar.elevation = 0f
|
||||
}
|
||||
}
|
||||
})
|
||||
behavior.peekHeight = BottomSheetBehavior.PEEK_HEIGHT_AUTO
|
||||
behavior.isFitToContents = false
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
(recyclerView.adapter as? DisposableHandle)?.dispose()
|
||||
recyclerView.adapter = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onItemClick(item: MangaPage, position: Int, view: View) {
|
||||
((parentFragment as? OnPageSelectListener)
|
||||
?: (activity as? OnPageSelectListener))?.run {
|
||||
onPageSelected(item)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val ARG_PAGES = "pages"
|
||||
private const val ARG_TITLE = "title"
|
||||
|
||||
private const val TAG = "PagesThumbnailsSheet"
|
||||
|
||||
fun show(fm: FragmentManager, pages: List<MangaPage>, title: String) =
|
||||
PagesThumbnailsSheet().withArgs(2) {
|
||||
putParcelableArrayList(ARG_PAGES, ArrayList<MangaPage>(pages))
|
||||
putString(ARG_TITLE, title)
|
||||
}.show(fm, TAG)
|
||||
|
||||
}
|
||||
}
|
||||
17
app/src/main/java/org/koitharu/kotatsu/utils/DrawUtils.kt
Normal file
17
app/src/main/java/org/koitharu/kotatsu/utils/DrawUtils.kt
Normal file
@@ -0,0 +1,17 @@
|
||||
package org.koitharu.kotatsu.utils
|
||||
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.ColorInt
|
||||
|
||||
object DrawUtils {
|
||||
|
||||
@JvmStatic
|
||||
@ColorInt
|
||||
fun invertColor(@ColorInt color: Int): Int {
|
||||
val red = Color.red(color)
|
||||
val green = Color.green(color)
|
||||
val blue = Color.blue(color)
|
||||
val alpha = Color.alpha(color)
|
||||
return Color.argb(alpha, 255 - red, 255 - green, 255 - blue)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user