Fullscreen cover view activity

pull/81/head
Koitharu 4 years ago
parent 8e9b89f6f0
commit eea427216d
No known key found for this signature in database
GPG Key ID: 8E861F8CE6E7CE27

@ -99,6 +99,7 @@
<activity <activity
android:name="org.koitharu.kotatsu.download.ui.DownloadsActivity" android:name="org.koitharu.kotatsu.download.ui.DownloadsActivity"
android:label="@string/downloads" /> android:label="@string/downloads" />
<activity android:name=".image.ui.ImageActivity"/>
<service <service
android:name="org.koitharu.kotatsu.download.ui.service.DownloadService" android:name="org.koitharu.kotatsu.download.ui.service.DownloadService"

@ -1,5 +1,6 @@
package org.koitharu.kotatsu.details.ui package org.koitharu.kotatsu.details.ui
import android.app.ActivityOptions
import android.os.Bundle import android.os.Bundle
import android.text.Spanned import android.text.Spanned
import android.view.LayoutInflater import android.view.LayoutInflater
@ -27,6 +28,7 @@ import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.model.MangaState import org.koitharu.kotatsu.core.model.MangaState
import org.koitharu.kotatsu.databinding.FragmentDetailsBinding import org.koitharu.kotatsu.databinding.FragmentDetailsBinding
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesDialog import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesDialog
import org.koitharu.kotatsu.image.ui.ImageActivity
import org.koitharu.kotatsu.reader.ui.ReaderActivity import org.koitharu.kotatsu.reader.ui.ReaderActivity
import org.koitharu.kotatsu.reader.ui.ReaderState import org.koitharu.kotatsu.reader.ui.ReaderState
import org.koitharu.kotatsu.search.ui.SearchActivity import org.koitharu.kotatsu.search.ui.SearchActivity
@ -50,6 +52,7 @@ class DetailsFragment : BaseFragment<FragmentDetailsBinding>(), View.OnClickList
binding.buttonFavorite.setOnClickListener(this) binding.buttonFavorite.setOnClickListener(this)
binding.buttonRead.setOnClickListener(this) binding.buttonRead.setOnClickListener(this)
binding.buttonRead.setOnLongClickListener(this) binding.buttonRead.setOnLongClickListener(this)
binding.coverCard.setOnClickListener(this)
viewModel.manga.observe(viewLifecycleOwner, ::onMangaUpdated) viewModel.manga.observe(viewLifecycleOwner, ::onMangaUpdated)
viewModel.isLoading.observe(viewLifecycleOwner, ::onLoadingStateChanged) viewModel.isLoading.observe(viewLifecycleOwner, ::onLoadingStateChanged)
viewModel.favouriteCategories.observe(viewLifecycleOwner, ::onFavouriteChanged) viewModel.favouriteCategories.observe(viewLifecycleOwner, ::onFavouriteChanged)
@ -189,6 +192,17 @@ class DetailsFragment : BaseFragment<FragmentDetailsBinding>(), View.OnClickList
) )
) )
} }
R.id.cover_card -> {
val options = ActivityOptions.makeSceneTransitionAnimation(
requireActivity(),
binding.imageViewCover,
binding.imageViewCover.transitionName,
)
startActivity(
ImageActivity.newIntent(v.context, manga.largeCoverUrl ?: manga.coverUrl),
options.toBundle()
)
}
} }
} }

@ -0,0 +1,92 @@
package org.koitharu.kotatsu.image.ui
import android.content.Context
import android.content.Intent
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.graphics.Insets
import androidx.core.graphics.drawable.toBitmap
import androidx.core.view.updatePadding
import coil.ImageLoader
import coil.request.CachePolicy
import coil.request.ImageRequest
import coil.target.PoolableViewTarget
import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.base.ui.BaseActivity
import org.koitharu.kotatsu.databinding.ActivityImageBinding
import org.koitharu.kotatsu.utils.ext.enqueueWith
import org.koitharu.kotatsu.utils.ext.indicator
class ImageActivity : BaseActivity<ActivityImageBinding>() {
private val coil: ImageLoader by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityImageBinding.inflate(layoutInflater))
supportActionBar?.run {
setDisplayHomeAsUpEnabled(true)
setDisplayShowTitleEnabled(false)
}
loadImage(intent.data)
}
override fun onWindowInsetsChanged(insets: Insets) {
binding.toolbar.updatePadding(
left = insets.left,
right = insets.right,
top = insets.top,
)
}
private fun loadImage(url: Uri?) {
ImageRequest.Builder(this)
.data(url)
.memoryCachePolicy(CachePolicy.DISABLED)
.lifecycle(this)
.target(SsivTarget(binding.ssiv))
.indicator(binding.progressBar)
.enqueueWith(coil)
}
private class SsivTarget(
override val view: SubsamplingScaleImageView,
) : PoolableViewTarget<SubsamplingScaleImageView> {
override fun onStart(placeholder: Drawable?) = setDrawable(placeholder)
override fun onError(error: Drawable?) = setDrawable(error)
override fun onSuccess(result: Drawable) = setDrawable(result)
override fun onClear() = setDrawable(null)
override fun equals(other: Any?): Boolean {
return (this === other) || (other is SsivTarget && view == other.view)
}
override fun hashCode() = view.hashCode()
override fun toString() = "SsivTarget(view=$view)"
private fun setDrawable(drawable: Drawable?) {
if (drawable != null) {
view.setImage(ImageSource.bitmap(drawable.toBitmap()))
} else {
view.recycle()
}
}
}
companion object {
fun newIntent(context: Context, url: String): Intent {
return Intent(context, ImageActivity::class.java)
.setData(Uri.parse(url))
}
}
}

@ -7,16 +7,16 @@ import coil.request.ErrorResult
import coil.request.ImageRequest import coil.request.ImageRequest
import coil.request.ImageResult import coil.request.ImageResult
import coil.request.SuccessResult import coil.request.SuccessResult
import com.google.android.material.progressindicator.BaseProgressIndicator
import org.koitharu.kotatsu.core.network.CommonHeaders import org.koitharu.kotatsu.core.network.CommonHeaders
import org.koitharu.kotatsu.utils.progress.ImageRequestIndicatorListener
@Suppress("NOTHING_TO_INLINE") fun ImageView.newImageRequest(url: String) = ImageRequest.Builder(context)
inline fun ImageView.newImageRequest(url: String) = ImageRequest.Builder(context)
.data(url) .data(url)
.crossfade(true) .crossfade(true)
.target(this) .target(this)
@Suppress("NOTHING_TO_INLINE") fun ImageRequest.Builder.enqueueWith(loader: ImageLoader) = loader.enqueue(build())
inline fun ImageRequest.Builder.enqueueWith(loader: ImageLoader) = loader.enqueue(build())
fun ImageResult.requireBitmap() = when (this) { fun ImageResult.requireBitmap() = when (this) {
is SuccessResult -> drawable.toBitmap() is SuccessResult -> drawable.toBitmap()
@ -32,7 +32,10 @@ fun ImageResult.toBitmapOrNull() = when (this) {
is ErrorResult -> null is ErrorResult -> null
} }
@Suppress("NOTHING_TO_INLINE") fun ImageRequest.Builder.referer(referer: String): ImageRequest.Builder {
inline fun ImageRequest.Builder.referer(referer: String): ImageRequest.Builder {
return setHeader(CommonHeaders.REFERER, referer) return setHeader(CommonHeaders.REFERER, referer)
}
fun ImageRequest.Builder.indicator(indicator: BaseProgressIndicator<*>): ImageRequest.Builder {
return listener(ImageRequestIndicatorListener(indicator))
} }

@ -0,0 +1,18 @@
package org.koitharu.kotatsu.utils.progress
import coil.request.ImageRequest
import coil.request.ImageResult
import com.google.android.material.progressindicator.BaseProgressIndicator
class ImageRequestIndicatorListener(
private val indicator: BaseProgressIndicator<*>,
) : ImageRequest.Listener {
override fun onCancel(request: ImageRequest) = indicator.hide()
override fun onError(request: ImageRequest, throwable: Throwable) = indicator.hide()
override fun onStart(request: ImageRequest) = indicator.show()
override fun onSuccess(request: ImageRequest, metadata: ImageResult.Metadata) = indicator.hide()
}

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
android:id="@+id/ssiv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:transitionName="cover" />
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/Widget.Kotatsu.Toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true" />
</FrameLayout>

@ -40,6 +40,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
android:scaleType="centerCrop" android:scaleType="centerCrop"
android:transitionName="cover"
tools:background="@tools:sample/backgrounds/scenic" tools:background="@tools:sample/backgrounds/scenic"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />

Loading…
Cancel
Save