diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b9aa1d3f1..2cc8e53e2 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -99,6 +99,7 @@
+
(), View.OnClickList
binding.buttonFavorite.setOnClickListener(this)
binding.buttonRead.setOnClickListener(this)
binding.buttonRead.setOnLongClickListener(this)
+ binding.coverCard.setOnClickListener(this)
viewModel.manga.observe(viewLifecycleOwner, ::onMangaUpdated)
viewModel.isLoading.observe(viewLifecycleOwner, ::onLoadingStateChanged)
viewModel.favouriteCategories.observe(viewLifecycleOwner, ::onFavouriteChanged)
@@ -189,6 +192,17 @@ class DetailsFragment : BaseFragment(), 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()
+ )
+ }
}
}
diff --git a/app/src/main/java/org/koitharu/kotatsu/image/ui/ImageActivity.kt b/app/src/main/java/org/koitharu/kotatsu/image/ui/ImageActivity.kt
new file mode 100644
index 000000000..ca14d2f4d
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/image/ui/ImageActivity.kt
@@ -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() {
+
+ 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 {
+
+ 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))
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoilExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoilExt.kt
index e31e3e20b..53cf3bdb2 100644
--- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoilExt.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoilExt.kt
@@ -7,16 +7,16 @@ import coil.request.ErrorResult
import coil.request.ImageRequest
import coil.request.ImageResult
import coil.request.SuccessResult
+import com.google.android.material.progressindicator.BaseProgressIndicator
import org.koitharu.kotatsu.core.network.CommonHeaders
+import org.koitharu.kotatsu.utils.progress.ImageRequestIndicatorListener
-@Suppress("NOTHING_TO_INLINE")
-inline fun ImageView.newImageRequest(url: String) = ImageRequest.Builder(context)
+fun ImageView.newImageRequest(url: String) = ImageRequest.Builder(context)
.data(url)
.crossfade(true)
.target(this)
-@Suppress("NOTHING_TO_INLINE")
-inline fun ImageRequest.Builder.enqueueWith(loader: ImageLoader) = loader.enqueue(build())
+fun ImageRequest.Builder.enqueueWith(loader: ImageLoader) = loader.enqueue(build())
fun ImageResult.requireBitmap() = when (this) {
is SuccessResult -> drawable.toBitmap()
@@ -32,7 +32,10 @@ fun ImageResult.toBitmapOrNull() = when (this) {
is ErrorResult -> null
}
-@Suppress("NOTHING_TO_INLINE")
-inline fun ImageRequest.Builder.referer(referer: String): ImageRequest.Builder {
+fun ImageRequest.Builder.referer(referer: String): ImageRequest.Builder {
return setHeader(CommonHeaders.REFERER, referer)
+}
+
+fun ImageRequest.Builder.indicator(indicator: BaseProgressIndicator<*>): ImageRequest.Builder {
+ return listener(ImageRequestIndicatorListener(indicator))
}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/progress/ImageRequestIndicatorListener.kt b/app/src/main/java/org/koitharu/kotatsu/utils/progress/ImageRequestIndicatorListener.kt
new file mode 100644
index 000000000..eb38e1d32
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/utils/progress/ImageRequestIndicatorListener.kt
@@ -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()
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_image.xml b/app/src/main/res/layout/activity_image.xml
new file mode 100644
index 000000000..251ff1c27
--- /dev/null
+++ b/app/src/main/res/layout/activity_image.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_details.xml b/app/src/main/res/layout/fragment_details.xml
index 341e70b33..d25e033a2 100644
--- a/app/src/main/res/layout/fragment_details.xml
+++ b/app/src/main/res/layout/fragment_details.xml
@@ -40,6 +40,7 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:scaleType="centerCrop"
+ android:transitionName="cover"
tools:background="@tools:sample/backgrounds/scenic"
tools:ignore="ContentDescription" />