aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt10
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivityOrig.kt438
-rw-r--r--app/src/main/res/layout/activity_image.xml2
-rw-r--r--app/src/main/res/layout/activity_image_2.xml72
4 files changed, 6 insertions, 516 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
index c381591e..da991236 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
@@ -50,7 +50,7 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.mikepenz.iconics.typeface.IIcon
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.pitchedapps.frost.R
-import com.pitchedapps.frost.databinding.ActivityImage2Binding
+import com.pitchedapps.frost.databinding.ActivityImageBinding
import com.pitchedapps.frost.facebook.FB_IMAGE_ID_MATCHER
import com.pitchedapps.frost.facebook.get
import com.pitchedapps.frost.facebook.requests.call
@@ -135,7 +135,7 @@ class ImageActivity : KauBaseActivity() {
"${abs(FB_IMAGE_ID_MATCHER.find(imageUrl)[1]?.hashCode() ?: 0)}_${abs(imageUrl.hashCode())}"
}
- lateinit var binding: ActivityImage2Binding
+ lateinit var binding: ActivityImageBinding
private var bottomBehavior: BottomSheetBehavior<View>? = null
private val baseBackgroundColor: Int
@@ -173,7 +173,7 @@ class ImageActivity : KauBaseActivity() {
L.v { "Launching image with url $result" }
result
}
- binding = ActivityImage2Binding.inflate(layoutInflater)
+ binding = ActivityImageBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.init()
launch(CoroutineExceptionHandler { _, throwable -> loadError(throwable) }) {
@@ -183,7 +183,7 @@ class ImageActivity : KauBaseActivity() {
}
}
- private fun ActivityImage2Binding.showImage(url: String) {
+ private fun ActivityImageBinding.showImage(url: String) {
imagePhoto.showImage(Uri.parse(url))
imagePhoto.setImageShownCallback(object : ImageShownCallback {
override fun onThumbnailShown() {}
@@ -195,7 +195,7 @@ class ImageActivity : KauBaseActivity() {
})
}
- private fun ActivityImage2Binding.init() {
+ private fun ActivityImageBinding.init() {
imageContainer.setBackgroundColor(baseBackgroundColor)
toolbar.setBackgroundColor(baseBackgroundColor)
this@ImageActivity.imageText.also { text ->
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivityOrig.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivityOrig.kt
deleted file mode 100644
index 3f6a90fe..00000000
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivityOrig.kt
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Copyright 2018 Allan Wang
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.pitchedapps.frost.activities
-
-import android.content.Context
-import android.content.Intent
-import android.content.res.ColorStateList
-import android.graphics.Color
-import android.os.Bundle
-import android.view.View
-import android.widget.ImageView
-import androidx.customview.widget.ViewDragHelper
-import ca.allanwang.kau.internal.KauBaseActivity
-import ca.allanwang.kau.logging.KauLoggerExtension
-import ca.allanwang.kau.utils.adjustAlpha
-import ca.allanwang.kau.utils.colorToForeground
-import ca.allanwang.kau.utils.copyFromInputStream
-import ca.allanwang.kau.utils.fadeIn
-import ca.allanwang.kau.utils.fadeOut
-import ca.allanwang.kau.utils.gone
-import ca.allanwang.kau.utils.invisible
-import ca.allanwang.kau.utils.isHidden
-import ca.allanwang.kau.utils.isVisible
-import ca.allanwang.kau.utils.materialDialog
-import ca.allanwang.kau.utils.scaleXY
-import ca.allanwang.kau.utils.setIcon
-import ca.allanwang.kau.utils.tint
-import ca.allanwang.kau.utils.toast
-import ca.allanwang.kau.utils.withAlpha
-import ca.allanwang.kau.utils.withMinAlpha
-import com.davemorrissey.labs.subscaleview.ImageSource
-import com.google.android.material.bottomsheet.BottomSheetBehavior
-import com.google.android.material.floatingactionbutton.FloatingActionButton
-import com.mikepenz.iconics.typeface.IIcon
-import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
-import com.pitchedapps.frost.R
-import com.pitchedapps.frost.databinding.ActivityImageBinding
-import com.pitchedapps.frost.facebook.FB_IMAGE_ID_MATCHER
-import com.pitchedapps.frost.facebook.get
-import com.pitchedapps.frost.facebook.requests.call
-import com.pitchedapps.frost.facebook.requests.getFullSizedImageUrl
-import com.pitchedapps.frost.facebook.requests.requestBuilder
-import com.pitchedapps.frost.injectors.ThemeProvider
-import com.pitchedapps.frost.prefs.Prefs
-import com.pitchedapps.frost.services.LocalService
-import com.pitchedapps.frost.utils.ARG_COOKIE
-import com.pitchedapps.frost.utils.ARG_IMAGE_URL
-import com.pitchedapps.frost.utils.ARG_TEXT
-import com.pitchedapps.frost.utils.ActivityThemer
-import com.pitchedapps.frost.utils.frostDownload
-import com.pitchedapps.frost.utils.frostSnackbar
-import com.pitchedapps.frost.utils.frostUriFromFile
-import com.pitchedapps.frost.utils.isIndirectImageUrl
-import com.pitchedapps.frost.utils.logFrostEvent
-import dagger.hilt.android.AndroidEntryPoint
-import kotlinx.coroutines.CoroutineExceptionHandler
-import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.async
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.io.File
-import java.io.FileNotFoundException
-import java.io.IOException
-import javax.inject.Inject
-import kotlin.math.abs
-import kotlin.math.max
-
-/**
- * Created by Allan Wang on 2017-07-15.
- */
-@AndroidEntryPoint
-class ImageActivityOrig : KauBaseActivity() {
-
- @Inject
- lateinit var activityThemer: ActivityThemer
-
- @Inject
- lateinit var prefs: Prefs
-
- @Inject
- lateinit var themeProvider: ThemeProvider
-
- @Volatile
- internal var errorRef: Throwable? = null
-
- /**
- * Reference to the temporary file path
- */
- internal var tempFile: File? = null
-
- private lateinit var dragHelper: ViewDragHelper
-
- companion object {
- /**
- * Cache folder to store images
- * Linked to the uri provider
- */
- private const val IMAGE_FOLDER = "images"
- private const val TIME_FORMAT = "yyyyMMdd_HHmmss"
- private const val IMG_TAG = "Frost"
- const val PURGE_TIME: Long = 10 * 60 * 1000 // 10 min block
- private val L = KauLoggerExtension("Image", com.pitchedapps.frost.utils.L)
-
- fun cacheDir(context: Context): File =
- File(context.cacheDir, IMAGE_FOLDER)
- }
-
- private val cookie: String? by lazy { intent.getStringExtra(ARG_COOKIE) }
-
- val imageUrl: String by lazy { intent.getStringExtra(ARG_IMAGE_URL)?.trim('"') ?: "" }
-
- private lateinit var trueImageUrl: Deferred<String>
-
- private val imageText: String? by lazy { intent.getStringExtra(ARG_TEXT) }
-
- // a unique image identifier based on the id (if it exists), and its hash
- private val imageHash: String by lazy {
- "${abs(FB_IMAGE_ID_MATCHER.find(imageUrl)[1]?.hashCode() ?: 0)}_${abs(imageUrl.hashCode())}"
- }
-
- lateinit var binding: ActivityImageBinding
- private var bottomBehavior: BottomSheetBehavior<View>? = null
-
- private val baseBackgroundColor: Int
- get() = if (prefs.blackMediaBg) Color.BLACK
- else themeProvider.bgColor.withMinAlpha(235)
-
- private fun loadError(e: Throwable) {
- if (e.message?.contains("<!DOCTYPE html>") == true) {
- applicationContext.toast(R.string.image_not_found)
- finish()
- return
- }
- errorRef = e
- e.logFrostEvent("Image load error")
- with(binding) {
- if (imageProgress.isVisible)
- imageProgress.fadeOut()
- }
- tempFile?.delete()
- binding.error.fadeIn()
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- if (imageUrl.isEmpty()) {
- return finish()
- }
- L.i { "Displaying image" }
- trueImageUrl = async(Dispatchers.IO) {
- val result = if (!imageUrl.isIndirectImageUrl) imageUrl
- else cookie?.getFullSizedImageUrl(imageUrl) ?: imageUrl
- if (result != imageUrl)
- L.v { "Launching with true url $result" }
- result
- }
- binding = ActivityImageBinding.inflate(layoutInflater)
- setContentView(binding.root)
- binding.init()
- launch(CoroutineExceptionHandler { _, throwable -> loadError(throwable) }) {
- val tempFile = downloadTempImage()
- this@ImageActivityOrig.tempFile = tempFile
- binding.imageProgress.fadeOut()
-// binding.imagePhoto.setImageURI(frostUriFromFile(tempFile))
- binding.imagePhoto.setImage(ImageSource.uri(frostUriFromFile(tempFile)))
- binding.imagePhoto.animate().alpha(1f).scaleXY(1f).start()
- }
- }
-
- private fun ActivityImageBinding.init() {
- imageContainer.setBackgroundColor(baseBackgroundColor)
- toolbar.setBackgroundColor(baseBackgroundColor)
- this@ImageActivityOrig.imageText.also { text ->
- if (text.isNullOrBlank()) {
- imageText.gone()
- } else {
- imageText.setTextColor(if (prefs.blackMediaBg) Color.WHITE else themeProvider.textColor)
- imageText.setBackgroundColor(
- baseBackgroundColor.colorToForeground(0.2f).withAlpha(255)
- )
- imageText.text = text
- bottomBehavior = BottomSheetBehavior.from<View>(imageText).apply {
- addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
- override fun onSlide(bottomSheet: View, slideOffset: Float) {
- imageText.alpha = slideOffset / 2 + 0.5f
- }
-
- override fun onStateChanged(bottomSheet: View, newState: Int) {
- // No op
- }
- })
- }
- imageText.bringToFront()
- }
- }
- val foregroundTint = if (prefs.blackMediaBg) Color.WHITE else themeProvider.accentColor
-
- fun ImageView.setState(state: FabStatesOrig) {
- setIcon(state.iicon, color = foregroundTint, sizeDp = 24)
- setOnClickListener { state.onClick(this@ImageActivityOrig) }
- }
-
- imageProgress.tint(foregroundTint)
- error.apply {
- invisible()
- setState(FabStatesOrig.ERROR)
- }
- download.apply {
- setState(FabStatesOrig.DOWNLOAD)
- }
- share.apply {
- setState(FabStatesOrig.SHARE)
- }
-// imagePhoto.setOnImageEventListener(object :
-// SubsamplingScaleImageView.DefaultOnImageEventListener() {
-// override fun onImageLoadError(e: Exception) {
-// loadError(e)
-// }
-// })
- activityThemer.setFrostColors {
- themeWindow = false
- }
- dragHelper = ViewDragHelper.create(imageDrag, ViewDragCallback()).apply {
- setEdgeTrackingEnabled(ViewDragHelper.EDGE_TOP or ViewDragHelper.EDGE_BOTTOM)
- }
- imageDrag.dragHelper = dragHelper
- imageDrag.viewToIgnore = imageText
- }
-
- private inner class ViewDragCallback : ViewDragHelper.Callback() {
- private var scrollPercent: Float = 0f
- private var scrollThreshold = 0.5f
- private var scrollToTop = false
-
- override fun tryCaptureView(view: View, i: Int): Boolean {
- L.d { "Try capture ${view.id} $i ${binding.imagePhoto.id} ${binding.imageText.id}" }
- return view === binding.imagePhoto
- }
-
- override fun getViewHorizontalDragRange(child: View): Int = 0
-
- override fun getViewVerticalDragRange(child: View): Int = child.height
-
- override fun onViewPositionChanged(
- changedView: View,
- left: Int,
- top: Int,
- dx: Int,
- dy: Int
- ) {
- super.onViewPositionChanged(changedView, left, top, dx, dy)
- with(binding) {
- // make sure that we are using the proper axis
- scrollPercent = abs(top.toFloat() / imageContainer.height)
- scrollToTop = top < 0
- val multiplier = max(1f - scrollPercent, 0f)
-
- toolbar.alpha = multiplier
- bottomBehavior?.also {
- imageText.alpha =
- multiplier * (if (it.state == BottomSheetBehavior.STATE_COLLAPSED) 0.5f else 1f)
- }
- imageContainer.setBackgroundColor(baseBackgroundColor.adjustAlpha(multiplier))
-
- if (scrollPercent >= 1) {
- if (!isFinishing) {
- finish()
- overridePendingTransition(0, 0)
- }
- }
- }
- }
-
- override fun onViewReleased(releasedChild: View, xvel: Float, yvel: Float) {
- val overScrolled = scrollPercent > scrollThreshold
- val maxOffset = releasedChild.height + 10
- val finalTop = when {
- scrollToTop && (overScrolled || yvel < -dragHelper.minVelocity) -> -maxOffset
- !scrollToTop && (overScrolled || yvel > dragHelper.minVelocity) -> maxOffset
- else -> 0
- }
- dragHelper.settleCapturedViewAt(0, finalTop)
- binding.imageDrag.invalidate()
- }
-
- override fun clampViewPositionHorizontal(child: View, left: Int, dx: Int): Int = 0
-
- override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int = top
- }
-
- private fun getImageExtension(type: String?): String? {
- if (type?.startsWith("image/") != true) {
- return null
- }
- return when (type.substring(6)) {
- "jpeg" -> "jpg"
- "png" -> "png"
- "gif" -> "gif"
- else -> null
- }
- }
-
- @Throws(IOException::class)
- private suspend fun downloadTempImage(): File = withContext(Dispatchers.IO) {
-
- // We assume all images are jpg
- // Activity launcher may be able to provide specifics, but this beats sending a request
- // just to get the content header
- val file = File(cacheDir(this@ImageActivityOrig), "$imageHash.jpg")
-
- if (!file.isFile) {
- file.parentFile?.mkdirs()
- file.createNewFile()
- } else {
- file.setLastModified(System.currentTimeMillis())
- }
-
- // Forbid overwrites
- if (file.isFile && file.length() > 0) {
- L.i { "Forbid image overwrite" }
- return@withContext file
- }
-
- val response = cookie.requestBuilder()
- .url(trueImageUrl.await())
- .get()
- .call()
- .execute()
-
- if (!response.isSuccessful) {
- throw IOException("Unsuccessful response for image: ${response.peekBody(128).string()}")
- }
-
- val body = response.body ?: throw IOException("Failed to retrieve image body")
- file.copyFromInputStream(body.byteStream())
- file
- }
-
- internal suspend fun saveImage() {
- frostDownload(cookie = cookie, url = trueImageUrl.await())
- }
-
- override fun onDestroy() {
- LocalService.schedule(this, LocalService.Flag.PURGE_IMAGE)
- super.onDestroy()
- }
-}
-
-internal enum class FabStatesOrig(
- val iicon: IIcon,
- val iconColorProvider: (ThemeProvider) -> Int = { it.iconColor },
- val backgroundTint: Int = Int.MAX_VALUE
-) {
- ERROR(GoogleMaterial.Icon.gmd_error, { Color.WHITE }, Color.RED) {
- override fun onClick(activity: ImageActivityOrig) {
- val err =
- activity.errorRef?.takeIf { it !is FileNotFoundException && it.message != "Image failed to decode using JPEG decoder" }
- ?: return
- activity.materialDialog {
- title(R.string.kau_error)
- message(text = err.message ?: err.javaClass.name)
- }
- }
- },
- NOTHING(GoogleMaterial.Icon.gmd_adjust) {
- override fun onClick(activity: ImageActivityOrig) {}
- },
- DOWNLOAD(GoogleMaterial.Icon.gmd_file_download) {
- override fun onClick(activity: ImageActivityOrig) {
- activity.launch {
- activity.binding.download.fadeOut()
- activity.saveImage()
- }
- }
- },
- SHARE(GoogleMaterial.Icon.gmd_share) {
- override fun onClick(activity: ImageActivityOrig) {
- val file = activity.tempFile ?: return
- try {
- val photoURI = activity.frostUriFromFile(file)
- val intent = Intent(Intent.ACTION_SEND).apply {
- flags = Intent.FLAG_ACTIVITY_NEW_TASK
- putExtra(Intent.EXTRA_STREAM, photoURI)
- type = "image/png"
- }
- activity.startActivity(intent)
- } catch (e: Exception) {
- activity.errorRef = e
- e.logFrostEvent("Image share failed")
- activity.frostSnackbar(R.string.image_share_failed, activity.themeProvider)
- }
- }
- };
-
- /**
- * Change the fab look
- * If it's in view, give it some animations
- *
- * TODO investigate what is wrong with fadeScaleTransition
- *
- * https://github.com/AllanWang/KAU/issues/184
- *
- */
- fun update(fab: FloatingActionButton, themeProvider: ThemeProvider) {
- val tint =
- if (backgroundTint != Int.MAX_VALUE) backgroundTint else themeProvider.accentColor
- val iconColor = iconColorProvider(themeProvider)
- if (fab.isHidden) {
- fab.setIcon(iicon, color = iconColor)
- fab.backgroundTintList = ColorStateList.valueOf(tint)
- fab.show()
- } else {
- fab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
- override fun onHidden(fab: FloatingActionButton) {
- fab.setIcon(iicon, color = iconColor)
- fab.show()
- }
- })
- }
- }
-
- abstract fun onClick(activity: ImageActivityOrig)
-}
diff --git a/app/src/main/res/layout/activity_image.xml b/app/src/main/res/layout/activity_image.xml
index 7e19dabf..689c4f4d 100644
--- a/app/src/main/res/layout/activity_image.xml
+++ b/app/src/main/res/layout/activity_image.xml
@@ -19,7 +19,7 @@
<!-- Alpha and scaling will be reset on load -->
- <com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
+ <com.github.piasy.biv.view.BigImageView
android:id="@+id/image_photo"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/app/src/main/res/layout/activity_image_2.xml b/app/src/main/res/layout/activity_image_2.xml
deleted file mode 100644
index 689c4f4d..00000000
--- a/app/src/main/res/layout/activity_image_2.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/image_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <ProgressBar
- android:id="@+id/image_progress"
- style="?android:attr/progressBarStyleLarge"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center" />
-
- <com.pitchedapps.frost.views.DragFrame
- android:id="@+id/image_drag"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <!-- Alpha and scaling will be reset on load -->
-
- <com.github.piasy.biv.view.BigImageView
- android:id="@+id/image_photo"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:alpha="0"
- android:scaleX="0.9"
- android:scaleY="0.9" />
-
- </com.pitchedapps.frost.views.DragFrame>
-
- <LinearLayout
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:gravity="end"
- android:orientation="horizontal"
- android:paddingStart="8dp"
- android:paddingTop="10dp"
- android:paddingEnd="8dp"
- android:paddingBottom="10dp">
-
- <ImageView
- android:id="@+id/error"
- style="@style/Image.Icon" />
-
- <Space
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" />
-
- <ImageView
- android:id="@+id/download"
- style="@style/Image.Icon" />
-
- <ImageView
- android:id="@+id/share"
- style="@style/Image.Icon" />
-
- </LinearLayout>
-
- <TextView
- android:id="@+id/image_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:alpha="0.5"
- android:padding="@dimen/kau_padding_normal"
- app:behavior_peekHeight="44dp"
- app:layout_behavior="@string/bottom_sheet_behavior" />
-
-</androidx.coordinatorlayout.widget.CoordinatorLayout>