Misc fixes

This commit is contained in:
Koitharu
2020-03-02 19:03:15 +02:00
parent a3948c9046
commit 9c150512c1
16 changed files with 81 additions and 70 deletions

View File

@@ -37,6 +37,7 @@ class ChaptersFragment : BaseFragment(R.layout.fragment_chapters), MangaDetailsV
RecyclerView.VERTICAL RecyclerView.VERTICAL
) )
) )
recyclerView_chapters.setHasFixedSize(true)
recyclerView_chapters.adapter = adapter recyclerView_chapters.adapter = adapter
} }

View File

@@ -54,12 +54,14 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
drawer?.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) drawer?.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
adapter = MangaListAdapter(this) adapter = MangaListAdapter(this)
recyclerView.setHasFixedSize(true)
initListMode(settings.listMode) initListMode(settings.listMode)
recyclerView.adapter = adapter recyclerView.adapter = adapter
recyclerView.addOnScrollListener(PaginationScrollListener(4, this)) recyclerView.addOnScrollListener(PaginationScrollListener(4, this))
swipeRefreshLayout.setOnRefreshListener { swipeRefreshLayout.setOnRefreshListener {
onRequestMoreItems(0) onRequestMoreItems(0)
} }
recyclerView_filter.setHasFixedSize(true)
recyclerView_filter.addItemDecoration(ItemTypeDividerDecoration(view.context)) recyclerView_filter.addItemDecoration(ItemTypeDividerDecoration(view.context))
recyclerView_filter.addItemDecoration(SectionItemDecoration(false, this)) recyclerView_filter.addItemDecoration(SectionItemDecoration(false, this))
settings.subscribe(this) settings.subscribe(this)
@@ -128,10 +130,12 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
} else { } else {
layout_holder.isVisible = false layout_holder.isVisible = false
} }
recyclerView.callOnScrollListeners()
} }
override fun onListAppended(list: List<Manga>) { override fun onListAppended(list: List<Manga>) {
adapter?.appendData(list) adapter?.appendData(list)
recyclerView.callOnScrollListeners()
} }
@CallSuper @CallSuper

View File

@@ -0,0 +1,5 @@
package org.koitharu.kotatsu.ui.reader
enum class ReaderAction {
REPLACE, PREPEND, APPEND
}

View File

@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.ui.reader package org.koitharu.kotatsu.ui.reader
import android.net.Uri import android.net.Uri
import androidx.annotation.CallSuper
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import org.koitharu.kotatsu.core.model.MangaChapter import org.koitharu.kotatsu.core.model.MangaChapter
import org.koitharu.kotatsu.core.model.MangaPage import org.koitharu.kotatsu.core.model.MangaPage
@@ -51,25 +52,15 @@ abstract class BaseReaderFragment(@LayoutRes contentLayoutId: Int) : BaseFragmen
super.onDestroyView() super.onDestroyView()
} }
final override fun onPagesLoaded(chapterId: Long, pages: List<MangaPage>) { @CallSuper
when { override fun onPagesLoaded(chapterId: Long, pages: List<MangaPage>, action: ReaderAction) {
chaptersMap.isEmpty() -> { when (action) {
chaptersMap.push(chapterId to pages.size) ReaderAction.REPLACE -> {
onPagesLoaded(chapterId, pages, Action.REPLACE)
}
shouldAppend(chapterId) -> {
chaptersMap.addLast(chapterId to pages.size)
onPagesLoaded(chapterId, pages, Action.APPEND)
}
shouldPrepend(chapterId) -> {
chaptersMap.addFirst(chapterId to pages.size)
onPagesLoaded(chapterId, pages, Action.PREPEND)
}
else -> {
chaptersMap.clear() chaptersMap.clear()
chaptersMap.push(chapterId to pages.size) chaptersMap.add(chapterId to pages.size)
onPagesLoaded(chapterId, pages, Action.REPLACE)
} }
ReaderAction.PREPEND -> chaptersMap.addFirst(chapterId to pages.size)
ReaderAction.APPEND -> chaptersMap.addLast(chapterId to pages.size)
} }
} }
@@ -100,22 +91,6 @@ abstract class BaseReaderFragment(@LayoutRes contentLayoutId: Int) : BaseFragmen
return null return null
} }
private fun shouldAppend(chapterId: Long): Boolean {
val chapters = lastState?.manga?.chapters ?: return false
val lastChapterId = chaptersMap.peekLast()?.first ?: return false
val indexOfCurrent = chapters.indexOfLast { x -> x.id == lastChapterId }
val indexOfNext = chapters.indexOfLast { x -> x.id == chapterId }
return indexOfCurrent != -1 && indexOfNext != -1 && indexOfCurrent + 1 == indexOfNext
}
private fun shouldPrepend(chapterId: Long): Boolean {
val chapters = lastState?.manga?.chapters ?: return false
val firstChapterId = chaptersMap.peekFirst()?.first ?: return false
val indexOfCurrent = chapters.indexOfFirst { x -> x.id == firstChapterId }
val indexOfPrev = chapters.indexOfFirst { x -> x.id == chapterId }
return indexOfCurrent != -1 && indexOfPrev != -1 && indexOfCurrent + 1 == indexOfPrev
}
protected fun getNextChapterId(): Long { protected fun getNextChapterId(): Long {
val lastChapterId = chaptersMap.peekLast()?.first ?: return 0 val lastChapterId = chaptersMap.peekLast()?.first ?: return 0
val chapters = lastState?.manga?.chapters ?: return 0 val chapters = lastState?.manga?.chapters ?: return 0
@@ -152,10 +127,4 @@ abstract class BaseReaderFragment(@LayoutRes contentLayoutId: Int) : BaseFragmen
total = chapter.second total = chapter.second
) )
} }
protected abstract fun onPagesLoaded(chapterId: Long, pages: List<MangaPage>, action: Action)
protected enum class Action {
REPLACE, PREPEND, APPEND
}
} }

View File

@@ -75,7 +75,7 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh
} }
if (savedInstanceState?.containsKey(MvpDelegate.MOXY_DELEGATE_TAGS_KEY) != true) { if (savedInstanceState?.containsKey(MvpDelegate.MOXY_DELEGATE_TAGS_KEY) != true) {
presenter.loadChapter(state.manga, state.chapterId) presenter.loadChapter(state.manga, state.chapterId, ReaderAction.REPLACE)
} }
} }
@@ -85,7 +85,7 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh
} }
} }
override fun onPagesLoaded(chapterId: Long, pages: List<MangaPage>) = Unit override fun onPagesLoaded(chapterId: Long, pages: List<MangaPage>, action: ReaderAction) = Unit
override fun onPause() { override fun onPause() {
reader?.let { reader?.let {
@@ -214,7 +214,7 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh
chapterId = chapter.id, chapterId = chapter.id,
page = 0 page = 0
) )
presenter.loadChapter(state.manga, chapter.id) presenter.loadChapter(state.manga, chapter.id, ReaderAction.REPLACE)
} }
override fun onPageSelected(page: MangaPage) { override fun onPageSelected(page: MangaPage) {

View File

@@ -29,7 +29,7 @@ class ReaderPresenter : BasePresenter<ReaderView>() {
private var isInitialized = false private var isInitialized = false
fun loadChapter(manga: Manga, chapterId: Long) { fun loadChapter(manga: Manga, chapterId: Long, action: ReaderAction) {
presenterScope.launch { presenterScope.launch {
viewState.onLoadingStateChanged(isLoading = true) viewState.onLoadingStateChanged(isLoading = true)
try { try {
@@ -60,7 +60,7 @@ class ReaderPresenter : BasePresenter<ReaderView>() {
isInitialized = true isInitialized = true
} }
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
viewState.onPagesLoaded(chapterId, pages) viewState.onPagesLoaded(chapterId, pages, action)
} }
} }
} catch (e: Exception) { } catch (e: Exception) {

View File

@@ -17,7 +17,7 @@ interface ReaderView : MvpView {
fun onChaptersLoader(chapters: List<MangaChapter>) fun onChaptersLoader(chapters: List<MangaChapter>)
@AddToEndSingle @AddToEndSingle
fun onPagesLoaded(chapterId: Long, pages: List<MangaPage>) fun onPagesLoaded(chapterId: Long, pages: List<MangaPage>, action: ReaderAction)
@AddToEndSingle @AddToEndSingle
fun onLoadingStateChanged(isLoading: Boolean) fun onLoadingStateChanged(isLoading: Boolean)

View File

@@ -6,10 +6,8 @@ import kotlinx.android.synthetic.main.fragment_reader_standard.*
import moxy.ktx.moxyPresenter import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.MangaPage import org.koitharu.kotatsu.core.model.MangaPage
import org.koitharu.kotatsu.ui.reader.BaseReaderFragment import org.koitharu.kotatsu.ui.reader.*
import org.koitharu.kotatsu.ui.reader.OnBoundsScrollListener import org.koitharu.kotatsu.utils.ext.callOnPageChaneListeners
import org.koitharu.kotatsu.ui.reader.PageLoader
import org.koitharu.kotatsu.ui.reader.ReaderPresenter
import org.koitharu.kotatsu.utils.ext.doOnPageChanged import org.koitharu.kotatsu.utils.ext.doOnPageChanged
class StandardReaderFragment : BaseReaderFragment(R.layout.fragment_reader_standard), class StandardReaderFragment : BaseReaderFragment(R.layout.fragment_reader_standard),
@@ -39,9 +37,10 @@ class StandardReaderFragment : BaseReaderFragment(R.layout.fragment_reader_stand
super.onDestroyView() super.onDestroyView()
} }
override fun onPagesLoaded(chapterId: Long, pages: List<MangaPage>, action: Action) { override fun onPagesLoaded(chapterId: Long, pages: List<MangaPage>, action: ReaderAction) {
super.onPagesLoaded(chapterId, pages, action)
when (action) { when (action) {
Action.REPLACE -> adapter?.let { ReaderAction.REPLACE -> adapter?.let {
it.replaceData(pages) it.replaceData(pages)
lastState?.let { state -> lastState?.let { state ->
if (chapterId == state.chapterId) { if (chapterId == state.chapterId) {
@@ -49,13 +48,14 @@ class StandardReaderFragment : BaseReaderFragment(R.layout.fragment_reader_stand
} }
} }
} }
Action.PREPEND -> adapter?.run { ReaderAction.PREPEND -> adapter?.run {
val pos = pager.currentItem val pos = pager.currentItem
prependData(pages) prependData(pages)
pager.setCurrentItem(pos + pages.size, false) pager.setCurrentItem(pos + pages.size, false)
} }
Action.APPEND -> adapter?.appendData(pages) ReaderAction.APPEND -> adapter?.appendData(pages)
} }
pager.callOnPageChaneListeners()
} }
override fun onDestroy() { override fun onDestroy() {
@@ -66,14 +66,14 @@ class StandardReaderFragment : BaseReaderFragment(R.layout.fragment_reader_stand
override fun onScrolledToStart() { override fun onScrolledToStart() {
val prevChapterId = getPrevChapterId() val prevChapterId = getPrevChapterId()
if (prevChapterId != 0L) { if (prevChapterId != 0L) {
presenter.loadChapter(lastState?.manga ?: return, prevChapterId) presenter.loadChapter(lastState?.manga ?: return, prevChapterId, ReaderAction.PREPEND)
} }
} }
override fun onScrolledToEnd() { override fun onScrolledToEnd() {
val nextChapterId = getNextChapterId() val nextChapterId = getNextChapterId()
if (nextChapterId != 0L) { if (nextChapterId != 0L) {
presenter.loadChapter(lastState?.manga ?: return, nextChapterId) presenter.loadChapter(lastState?.manga ?: return, nextChapterId, ReaderAction.APPEND)
} }
} }

View File

@@ -6,10 +6,8 @@ import kotlinx.android.synthetic.main.fragment_reader_webtoon.*
import moxy.ktx.moxyPresenter import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.MangaPage import org.koitharu.kotatsu.core.model.MangaPage
import org.koitharu.kotatsu.ui.reader.BaseReaderFragment import org.koitharu.kotatsu.ui.reader.*
import org.koitharu.kotatsu.ui.reader.OnBoundsScrollListener import org.koitharu.kotatsu.utils.ext.callOnScrollListeners
import org.koitharu.kotatsu.ui.reader.PageLoader
import org.koitharu.kotatsu.ui.reader.ReaderPresenter
import org.koitharu.kotatsu.utils.ext.doOnCurrentItemChanged import org.koitharu.kotatsu.utils.ext.doOnCurrentItemChanged
import org.koitharu.kotatsu.utils.ext.firstItem import org.koitharu.kotatsu.utils.ext.firstItem
@@ -29,14 +27,16 @@ class WebtoonReaderFragment : BaseReaderFragment(R.layout.fragment_reader_webtoo
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
adapter = WebtoonAdapter(loader) adapter = WebtoonAdapter(loader)
recyclerView.setHasFixedSize(true)
recyclerView.adapter = adapter recyclerView.adapter = adapter
recyclerView.addOnScrollListener(ListPaginationListener(2, this)) recyclerView.addOnScrollListener(ListPaginationListener(2, this))
recyclerView.doOnCurrentItemChanged(::notifyPageChanged) recyclerView.doOnCurrentItemChanged(::notifyPageChanged)
} }
override fun onPagesLoaded(chapterId: Long, pages: List<MangaPage>, action: Action) { override fun onPagesLoaded(chapterId: Long, pages: List<MangaPage>, action: ReaderAction) {
super.onPagesLoaded(chapterId, pages, action)
when(action) { when(action) {
Action.REPLACE -> { ReaderAction.REPLACE -> {
adapter?.let { adapter?.let {
it.replaceData(pages) it.replaceData(pages)
lastState?.let { state -> lastState?.let { state ->
@@ -46,22 +46,23 @@ class WebtoonReaderFragment : BaseReaderFragment(R.layout.fragment_reader_webtoo
} }
} }
} }
Action.PREPEND -> adapter?.prependData(pages) ReaderAction.PREPEND -> adapter?.prependData(pages)
Action.APPEND -> adapter?.appendData(pages) ReaderAction.APPEND -> adapter?.appendData(pages)
} }
recyclerView.callOnScrollListeners()
} }
override fun onScrolledToStart() { override fun onScrolledToStart() {
val prevChapterId = getPrevChapterId() val prevChapterId = getPrevChapterId()
if (prevChapterId != 0L) { if (prevChapterId != 0L) {
presenter.loadChapter(lastState?.manga ?: return, prevChapterId) presenter.loadChapter(lastState?.manga ?: return, prevChapterId, ReaderAction.PREPEND)
} }
} }
override fun onScrolledToEnd() { override fun onScrolledToEnd() {
val nextChapterId = getNextChapterId() val nextChapterId = getNextChapterId()
if (nextChapterId != 0L) { if (nextChapterId != 0L) {
presenter.loadChapter(lastState?.manga ?: return, nextChapterId) presenter.loadChapter(lastState?.manga ?: return, nextChapterId, ReaderAction.APPEND)
} }
} }

View File

@@ -4,7 +4,6 @@ import android.app.SearchManager
import android.content.Context import android.content.Context
import android.database.Cursor import android.database.Cursor
import android.view.MenuItem import android.view.MenuItem
import android.view.inputmethod.EditorInfo
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
@@ -17,8 +16,6 @@ object SearchHelper {
val view = menuItem.actionView as? SearchView ?: return val view = menuItem.actionView as? SearchView ?: return
val context = view.context val context = view.context
view.queryHint = context.getString(R.string.search_manga) view.queryHint = context.getString(R.string.search_manga)
view.imeOptions = EditorInfo.IME_ACTION_SEARCH
view.inputType = EditorInfo.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE
view.suggestionsAdapter = MangaSuggestionsProvider.getSuggestionAdapter(context) view.suggestionsAdapter = MangaSuggestionsProvider.getSuggestionAdapter(context)
view.setOnQueryTextListener(QueryListener(context, source)) view.setOnQueryTextListener(QueryListener(context, source))
view.setOnSuggestionListener(SuggestionListener(view)) view.setOnSuggestionListener(SuggestionListener(view))

View File

@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.utils.ext
import android.app.Activity import android.app.Activity
import android.graphics.Rect import android.graphics.Rect
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.util.Log
import android.view.* import android.view.*
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.EditText import android.widget.EditText
@@ -188,4 +189,34 @@ fun RecyclerView.doOnCurrentItemChanged(callback: (Int) -> Unit) {
} }
} }
}) })
}
fun RecyclerView.callOnScrollListeners() {
try {
val field = RecyclerView::class.java.getDeclaredField("mScrollListeners")
field.isAccessible = true
val listeners = field.get(this) as List<*>
for (x in listeners) {
(x as RecyclerView.OnScrollListener).onScrolled(this, 0, 0)
}
} catch (e: Throwable) {
Log.e(null, "RecyclerView.callOnScrollListeners() failed", e)
}
}
fun ViewPager2.callOnPageChaneListeners() {
try {
val field = ViewPager2::class.java.getDeclaredField("mExternalPageChangeCallbacks")
field.isAccessible = true
val compositeCallback = field.get(this)
val field2 = compositeCallback.javaClass.getDeclaredField("mCallbacks")
field2.isAccessible = true
val listeners = field2.get(compositeCallback) as List<*>
val position = currentItem
for (x in listeners) {
(x as ViewPager2.OnPageChangeCallback).onPageSelected(position)
}
} catch (e: Throwable) {
Log.e(null, "ViewPager2.callOnPageChaneListeners() failed", e)
}
} }

View File

@@ -42,18 +42,21 @@
<TextView <TextView
android:id="@+id/textView_subtitle" android:id="@+id/textView_subtitle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="wrap_content"
android:layout_marginStart="6dp" android:layout_marginStart="6dp"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:layout_marginEnd="6dp" android:layout_marginEnd="6dp"
android:layout_marginBottom="6dp" android:layout_marginBottom="6dp"
android:layout_weight="1"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2" android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
android:textColor="?android:textColorSecondary" android:textColor="?android:textColorSecondary"
tools:text="@tools:sample/lorem[6]" /> tools:text="@tools:sample/lorem[6]" />
<Space
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1" />
<View <View
android:id="@+id/divider" android:id="@+id/divider"