mirror of
https://github.com/AllanWang/Frost-for-Facebook.git
synced 2024-11-08 12:02:33 +01:00
Test image activity
This commit is contained in:
parent
888af190ed
commit
8c343fd09c
@ -31,5 +31,10 @@
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://oss.sonatype.org/content/repositories/snapshots/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
@ -1,5 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DesignSurface">
|
||||
<option name="filePathToZoomLevelMap">
|
||||
<map>
|
||||
<entry key="../../../../layout/custom_preview.xml" value="0.209375" />
|
||||
<entry key="app/src/main/res/layout/activity_image.xml" value="0.1585144927536232" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="NullableNotNullManager">
|
||||
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
|
||||
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
||||
|
@ -274,6 +274,10 @@ dependencies {
|
||||
|
||||
implementation "androidx.biometric:biometric:${Versions.andxBiometric}"
|
||||
|
||||
implementation 'com.github.piasy:BigImageViewer:1.8.1'
|
||||
implementation 'com.github.piasy:GlideImageLoader:1.8.1'
|
||||
implementation 'com.github.piasy:GlideImageViewFactory:1.8.1'
|
||||
|
||||
implementation kau.Dependencies.hilt
|
||||
kapt kau.Dependencies.hiltCompiler
|
||||
testImplementation kau.Dependencies.hiltTest
|
||||
@ -314,7 +318,7 @@ dependencies {
|
||||
testImplementation "com.squareup.okhttp3:mockwebserver:${Versions.okhttp}"
|
||||
androidTestImplementation "com.squareup.okhttp3:mockwebserver:${Versions.okhttp}"
|
||||
|
||||
implementation "com.davemorrissey.labs:subsampling-scale-image-view:${Versions.scaleImageView}"
|
||||
// implementation "com.davemorrissey.labs:subsampling-scale-image-view:${Versions.scaleImageView}"
|
||||
|
||||
implementation "androidx.room:room-ktx:${Versions.room}"
|
||||
implementation "androidx.room:room-runtime:${Versions.room}"
|
||||
|
@ -22,8 +22,11 @@ import android.os.Bundle
|
||||
import android.util.Log
|
||||
import ca.allanwang.kau.logging.KL
|
||||
import ca.allanwang.kau.utils.buildIsLollipopAndUp
|
||||
import com.github.piasy.biv.BigImageViewer
|
||||
import com.github.piasy.biv.loader.glide.GlideImageLoader
|
||||
import com.pitchedapps.frost.db.CookieDao
|
||||
import com.pitchedapps.frost.db.NotificationDao
|
||||
import com.pitchedapps.frost.facebook.requests.httpClient
|
||||
import com.pitchedapps.frost.injectors.ThemeProvider
|
||||
import com.pitchedapps.frost.prefs.Prefs
|
||||
import com.pitchedapps.frost.services.scheduleNotificationsFromPrefs
|
||||
@ -66,6 +69,8 @@ class FrostApp : Application() {
|
||||
|
||||
scheduleNotificationsFromPrefs(prefs)
|
||||
|
||||
BigImageViewer.initialize(GlideImageLoader.with(this, httpClient))
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
|
||||
override fun onActivityPaused(activity: Activity) {}
|
||||
|
@ -20,6 +20,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
@ -42,14 +43,12 @@ 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.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||
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.databinding.ActivityImage2Binding
|
||||
import com.pitchedapps.frost.facebook.FB_IMAGE_ID_MATCHER
|
||||
import com.pitchedapps.frost.facebook.get
|
||||
import com.pitchedapps.frost.facebook.requests.call
|
||||
@ -134,7 +133,7 @@ class ImageActivity : KauBaseActivity() {
|
||||
"${abs(FB_IMAGE_ID_MATCHER.find(imageUrl)[1]?.hashCode() ?: 0)}_${abs(imageUrl.hashCode())}"
|
||||
}
|
||||
|
||||
lateinit var binding: ActivityImageBinding
|
||||
lateinit var binding: ActivityImage2Binding
|
||||
private var bottomBehavior: BottomSheetBehavior<View>? = null
|
||||
|
||||
private val baseBackgroundColor: Int
|
||||
@ -170,19 +169,22 @@ class ImageActivity : KauBaseActivity() {
|
||||
L.v { "Launching with true url $result" }
|
||||
result
|
||||
}
|
||||
binding = ActivityImageBinding.inflate(layoutInflater)
|
||||
binding = ActivityImage2Binding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
binding.init()
|
||||
launch(CoroutineExceptionHandler { _, throwable -> loadError(throwable) }) {
|
||||
val tempFile = downloadTempImage()
|
||||
this@ImageActivity.tempFile = tempFile
|
||||
binding.imageProgress.fadeOut()
|
||||
binding.imagePhoto.setImage(ImageSource.uri(frostUriFromFile(tempFile)))
|
||||
// binding.imagePhoto.setImageURI(frostUriFromFile(tempFile))
|
||||
// Glide.with(binding.imagePhoto).asFile().load(trueImageUrl)
|
||||
binding.imagePhoto.showImage(Uri.parse(trueImageUrl.await()))
|
||||
// binding.imagePhoto.setImage(ImageSource.uri(frostUriFromFile(tempFile)))
|
||||
binding.imagePhoto.animate().alpha(1f).scaleXY(1f).start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun ActivityImageBinding.init() {
|
||||
private fun ActivityImage2Binding.init() {
|
||||
imageContainer.setBackgroundColor(baseBackgroundColor)
|
||||
toolbar.setBackgroundColor(baseBackgroundColor)
|
||||
this@ImageActivity.imageText.also { text ->
|
||||
@ -226,12 +228,12 @@ class ImageActivity : KauBaseActivity() {
|
||||
share.apply {
|
||||
setState(FabStates.SHARE)
|
||||
}
|
||||
imagePhoto.setOnImageEventListener(object :
|
||||
SubsamplingScaleImageView.DefaultOnImageEventListener() {
|
||||
override fun onImageLoadError(e: Exception) {
|
||||
loadError(e)
|
||||
}
|
||||
})
|
||||
// imagePhoto.setOnImageEventListener(object :
|
||||
// SubsamplingScaleImageView.DefaultOnImageEventListener() {
|
||||
// override fun onImageLoadError(e: Exception) {
|
||||
// loadError(e)
|
||||
// }
|
||||
// })
|
||||
activityThemer.setFrostColors {
|
||||
themeWindow = false
|
||||
}
|
||||
|
@ -0,0 +1,438 @@
|
||||
/*
|
||||
* 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)
|
||||
}
|
@ -17,6 +17,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- Alpha and scaling will be reset on load -->
|
||||
|
||||
<com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||
android:id="@+id/image_photo"
|
||||
android:layout_width="match_parent"
|
||||
|
72
app/src/main/res/layout/activity_image_2.xml
Normal file
72
app/src/main/res/layout/activity_image_2.xml
Normal file
@ -0,0 +1,72 @@
|
||||
<?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>
|
@ -9,11 +9,12 @@ buildscript {
|
||||
|
||||
dependencies {
|
||||
classpath kau.Plugins.android
|
||||
classpath kau.Plugins.kotlin
|
||||
// classpath kau.Plugins.kotlin
|
||||
classpath kau.Plugins.spotless
|
||||
classpath kau.Plugins.dexCount
|
||||
classpath kau.Plugins.hilt
|
||||
classpath kau.Plugins.gitVersion
|
||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31'
|
||||
}
|
||||
|
||||
wrapper.setDistributionType(Wrapper.DistributionType.ALL)
|
||||
|
@ -1,3 +0,0 @@
|
||||
include(":app", ":gradle-plugin")
|
||||
|
||||
project(":gradle-plugin").projectDir = file("buildSrc")
|
Loading…
Reference in New Issue
Block a user