Various fixes

This commit is contained in:
Koitharu
2020-02-23 20:48:51 +02:00
parent dce877a139
commit 0e746091b8
30 changed files with 214 additions and 53 deletions

View File

@@ -6,10 +6,15 @@ import android.net.Uri
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.net.toFile
import androidx.lifecycle.lifecycleScope
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.activity_details.*
import kotlinx.coroutines.launch
import moxy.MvpDelegate
import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.core.model.Manga
@@ -18,6 +23,7 @@ import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.ui.common.BaseActivity
import org.koitharu.kotatsu.ui.download.DownloadService
import org.koitharu.kotatsu.utils.ShareHelper
import org.koitharu.kotatsu.utils.ShortcutUtils
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
@@ -33,7 +39,10 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
pager.adapter = MangaDetailsAdapter(resources, supportFragmentManager)
tabs.setupWithViewPager(pager)
intent?.getParcelableExtra<Manga>(EXTRA_MANGA)?.let {
presenter.loadDetails(it)
presenter.loadDetails(
manga = it,
force = savedInstanceState?.containsKey(MvpDelegate.MOXY_DELEGATE_TAGS_KEY) != true
)
} ?: finish()
}
@@ -61,6 +70,8 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
menu.findItem(R.id.action_save).isEnabled =
manga?.source != null && manga?.source != MangaSource.LOCAL
menu.findItem(R.id.action_shortcut).isVisible = BuildConfig.DEBUG ||
ShortcutManagerCompat.isRequestPinShortcutSupported(this)
return super.onPrepareOptionsMenu(menu)
}
@@ -81,6 +92,25 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
}
true
}
R.id.action_shortcut -> {
manga?.let {
lifecycleScope.launch {
if (!ShortcutManagerCompat.requestPinShortcut(
this@MangaDetailsActivity,
ShortcutUtils.createShortcutInfo(this@MangaDetailsActivity, it),
null
)
) {
Snackbar.make(
pager,
R.string.operation_not_supported,
Snackbar.LENGTH_SHORT
).show()
}
}
}
true
}
else -> super.onOptionsItemSelected(item)
}

View File

@@ -1,5 +1,6 @@
package org.koitharu.kotatsu.ui.details
import android.text.Spanned
import androidx.core.text.parseAsHtml
import androidx.core.view.isVisible
import coil.api.load
@@ -25,10 +26,14 @@ class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetai
override fun onMangaUpdated(manga: Manga) {
this.manga = manga
imageView_cover.load(manga.largeCoverUrl ?: manga.coverUrl)
imageView_cover.load(manga.largeCoverUrl ?: manga.coverUrl) {
fallback(R.drawable.ic_placeholder)
crossfade(true)
}
textView_title.text = manga.title
textView_subtitle.text = manga.altTitle
textView_description.text = manga.description?.parseAsHtml()
textView_description.text = manga.description?.parseAsHtml()?.takeUnless(Spanned::isBlank)
?: getString(R.string.no_description)
if (manga.rating == Manga.NO_RATING) {
ratingBar.isVisible = false
} else {

View File

@@ -17,6 +17,9 @@ class MangaGridHolder(parent: ViewGroup) : BaseViewHolder<Manga, MangaHistory?>(
coverRequest?.dispose()
textView_title.text = data.title
coverRequest = imageView_cover.load(data.coverUrl) {
placeholder(R.drawable.ic_placeholder)
fallback(R.drawable.ic_placeholder)
error(R.drawable.ic_placeholder)
crossfade(true)
}
}

View File

@@ -23,6 +23,9 @@ class MangaListDetailsHolder(parent: ViewGroup) : BaseViewHolder<Manga, MangaHis
textView_title.text = data.title
textView_subtitle.textAndVisible = data.altTitle
coverRequest = imageView_cover.load(data.coverUrl) {
placeholder(R.drawable.ic_placeholder)
fallback(R.drawable.ic_placeholder)
error(R.drawable.ic_placeholder)
crossfade(true)
}
if(data.rating == Manga.NO_RATING) {

View File

@@ -14,6 +14,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fragment_list.*
import moxy.MvpDelegate
import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga
@@ -31,6 +32,7 @@ import org.koitharu.kotatsu.ui.common.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.ui.details.MangaDetailsActivity
import org.koitharu.kotatsu.ui.main.list.filter.FilterAdapter
import org.koitharu.kotatsu.ui.main.list.filter.OnFilterChangedListener
import org.koitharu.kotatsu.utils.UiUtils
import org.koitharu.kotatsu.utils.ext.*
abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), MangaListView<E>,
@@ -70,7 +72,7 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (savedInstanceState?.containsKey("MoxyDelegateBundle") != true) {
if (savedInstanceState?.containsKey(MvpDelegate.MOXY_DELEGATE_TAGS_KEY) != true) {
onRequestMoreItems(0)
}
}
@@ -210,7 +212,7 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
recyclerView.clearItemDecorations()
adapter?.listMode = mode
recyclerView.layoutManager = when (mode) {
ListMode.GRID -> GridLayoutManager(ctx, 3)
ListMode.GRID -> GridLayoutManager(ctx, UiUtils.resolveGridSpanCount(ctx))
else -> LinearLayoutManager(ctx)
}
recyclerView.adapter = adapter

View File

@@ -20,6 +20,9 @@ class MangaListHolder(parent: ViewGroup) :
textView_title.text = data.title
textView_subtitle.textAndVisible = data.tags.joinToString(", ") { it.title }
coverRequest = imageView_cover.load(data.coverUrl) {
placeholder(R.drawable.ic_placeholder)
fallback(R.drawable.ic_placeholder)
error(R.drawable.ic_placeholder)
crossfade(true)
}
}

View File

@@ -14,6 +14,7 @@ import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.activity_reader.*
import moxy.MvpDelegate
import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga
@@ -69,7 +70,10 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh
loader = PageLoader()
adapter = PagesAdapter(loader)
pager.adapter = adapter
presenter.loadChapter(state)
pager.offscreenPageLimit = 2
if (savedInstanceState?.containsKey(MvpDelegate.MOXY_DELEGATE_TAGS_KEY) != true) {
presenter.loadChapter(state)
}
}
override fun onDestroy() {

View File

@@ -3,23 +3,30 @@ package org.koitharu.kotatsu.ui.reader.thumbnails
import android.view.ViewGroup
import coil.Coil
import coil.api.get
import coil.size.PixelSize
import coil.size.Size
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
private val thumbSize: Size
init {
val color = DrawUtils.invertColor(textView_number.currentTextColor)
textView_number.setShadowLayer(parent.resources.resolveDp(26f), 0f, 0f, color)
// FIXME
// val color = DrawUtils.invertColor(textView_number.currentTextColor)
// textView_number.setShadowLayer(parent.resources.resolveDp(26f), 0f, 0f, color)
val width = itemView.context.resources.getDimensionPixelSize(R.dimen.preferred_grid_width)
thumbSize = PixelSize(
width = width,
height = (width * 13f / 18f).toInt()
)
}
override fun onBind(data: MangaPage, extra: Unit) {
@@ -32,7 +39,7 @@ class PageThumbnailHolder(parent: ViewGroup, private val scope: CoroutineScope)
MangaProviderFactory.create(data.source).getPageFullUrl(data)
}
val drawable = Coil.get(url) {
size(thumbSize)
}
withContext(Dispatchers.Main) {
imageView_thumb.setImageDrawable(drawable)

View File

@@ -4,6 +4,7 @@ import android.os.Bundle
import android.view.View
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import kotlinx.android.synthetic.main.sheet_pages.*
@@ -13,6 +14,7 @@ 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.UiUtils
import org.koitharu.kotatsu.utils.ext.resolveDp
import org.koitharu.kotatsu.utils.ext.withArgs
@@ -31,6 +33,7 @@ class PagesThumbnailsSheet : BaseBottomSheet(R.layout.sheet_pages),
dismissAllowingStateLoss()
return
}
(recyclerView.layoutManager as? GridLayoutManager)?.spanCount = UiUtils.resolveGridSpanCount(view.context)
val title = arguments?.getString(ARG_TITLE)
toolbar.title = title
toolbar.setNavigationOnClickListener { dismiss() }
@@ -56,8 +59,8 @@ class PagesThumbnailsSheet : BaseBottomSheet(R.layout.sheet_pages),
}
}
})
behavior.peekHeight = BottomSheetBehavior.PEEK_HEIGHT_AUTO
behavior.isFitToContents = false
// behavior.peekHeight = BottomSheetBehavior.PEEK_HEIGHT_AUTO
// behavior.isFitToContents = false
}
override fun onDestroyView() {

View File

@@ -1,17 +0,0 @@
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)
}
}

View File

@@ -0,0 +1,33 @@
package org.koitharu.kotatsu.utils
import android.content.Context
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.graphics.drawable.IconCompat
import androidx.core.graphics.drawable.toBitmap
import coil.Coil
import coil.api.get
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.ui.details.MangaDetailsActivity
object ShortcutUtils {
@JvmStatic
suspend fun createShortcutInfo(context: Context, manga: Manga): ShortcutInfoCompat {
// val icon = withContext(Dispatchers.IO) {
// Coil.loader().get(manga.coverUrl) {
// context.getSystemService<ActivityManager>()?.let {
// size(it.launcherLargeIconSize)
// }
// }.toBitmap()
// }
return ShortcutInfoCompat.Builder(context, manga.id.toString())
.setShortLabel(manga.title)
.setLongLabel(manga.title)
.setIcon(IconCompat.createWithResource(context, R.drawable.ic_launcher_foreground))
.setIntent(MangaDetailsActivity.newIntent(context, manga))
.build()
}
}

View File

@@ -0,0 +1,28 @@
package org.koitharu.kotatsu.utils
import android.content.Context
import android.graphics.Color
import androidx.annotation.ColorInt
import org.koitharu.kotatsu.R
import kotlin.math.roundToInt
object UiUtils {
@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)
}
@JvmStatic
fun resolveGridSpanCount(context: Context): Int {
val cellWidth = context.resources.getDimensionPixelSize(R.dimen.preferred_grid_width)
val screenWidth = context.resources.displayMetrics.widthPixels.toDouble()
val estimatedCount = (screenWidth / cellWidth).roundToInt()
return estimatedCount.coerceAtLeast(2)
}
}

View File

@@ -33,6 +33,7 @@ suspend inline fun <T, R> T.retryUntilSuccess(maxAttempts: Int, action: T.() ->
}
fun Throwable.getDisplayMessage(resources: Resources) = when (this) {
is UnsupportedOperationException -> resources.getString(R.string.operation_not_supported)
is UnsupportedFileException -> resources.getString(R.string.text_file_not_supported)
is IOException -> resources.getString(R.string.network_error)
else -> if (BuildConfig.DEBUG) {