aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt')
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt136
1 files changed, 102 insertions, 34 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 d63fa25e..99fa6eee 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
@@ -1,5 +1,6 @@
package com.pitchedapps.frost.activities
+import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Bitmap
@@ -7,18 +8,20 @@ import android.graphics.Color
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
+import android.os.Environment
import android.support.design.widget.FloatingActionButton
-import android.support.v4.content.FileProvider
import android.view.View
import android.view.ViewGroup
import android.widget.ProgressBar
import android.widget.TextView
import ca.allanwang.kau.internal.KauBaseActivity
+import ca.allanwang.kau.logging.KauLoggerExtension
import ca.allanwang.kau.mediapicker.scanMedia
import ca.allanwang.kau.permissions.PERMISSION_WRITE_EXTERNAL_STORAGE
import ca.allanwang.kau.permissions.kauRequestPermissions
import ca.allanwang.kau.utils.*
import com.bumptech.glide.Glide
+import com.bumptech.glide.RequestManager
import com.bumptech.glide.request.target.BaseTarget
import com.bumptech.glide.request.target.SizeReadyCallback
import com.bumptech.glide.request.target.Target
@@ -27,14 +30,17 @@ import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.mikepenz.google_material_typeface_library.GoogleMaterial
import com.mikepenz.iconics.typeface.IIcon
-import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.R
+import com.pitchedapps.frost.facebook.requests.call
import com.pitchedapps.frost.utils.*
import com.sothree.slidinguppanel.SlidingUpPanelLayout
+import okhttp3.Request
import org.jetbrains.anko.activityUiThreadWithContext
import org.jetbrains.anko.doAsync
import java.io.File
import java.io.IOException
+import java.text.SimpleDateFormat
+import java.util.*
/**
* Created by Allan Wang on 2017-07-15.
@@ -49,17 +55,19 @@ class ImageActivity : KauBaseActivity() {
val fab: FloatingActionButton by bindView(R.id.image_fab)
var errorRef: Throwable? = null
+ private val tempDir: File by lazy { File(cacheDir, IMAGE_FOLDER) }
+
/**
* Reference to the temporary file path
* Should be nonnull if the image is successfully loaded
* As this is temporary, the image is deleted upon exit
*/
- private var tempFilePath: String? = null
+ internal var tempFile: File? = null
/**
* Reference to path for downloaded image
* Nonnull once the image is downloaded by the user
*/
- internal var downloadPath: String? = null
+ internal var savedFile: File? = null
/**
* Indicator for fab's click result
*/
@@ -70,15 +78,28 @@ class ImageActivity : KauBaseActivity() {
value.update(fab)
}
+ 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"
+ private const val IMG_EXTENSION = ".png"
+ private val L = KauLoggerExtension("Image", com.pitchedapps.frost.utils.L)
+ }
+
val imageUrl: String by lazy { intent.getStringExtra(ARG_IMAGE_URL).trim('"') }
val text: String? by lazy { intent.getStringExtra(ARG_TEXT) }
+ private val glide: RequestManager by lazy { Glide.with(this) }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
intent?.extras ?: return finish()
L.i { "Displaying image" }
- L._i { imageUrl }
val layout = if (!text.isNullOrBlank()) R.layout.activity_image else R.layout.activity_image_textless
setContentView(layout)
container.setBackgroundColor(Prefs.bgColor.withMinAlpha(222))
@@ -101,8 +122,10 @@ class ImageActivity : KauBaseActivity() {
imageCallback(null, false)
}
})
- Glide.with(this).asBitmap().load(imageUrl).into(PhotoTarget(this::imageCallback))
- setFrostColors(themeWindow = false)
+ glide.asBitmap().load(imageUrl).into(PhotoTarget(this::imageCallback))
+ setFrostColors {
+ themeWindow = false
+ }
}
/**
@@ -119,7 +142,7 @@ class ImageActivity : KauBaseActivity() {
} else {
photo.setImage(ImageSource.uri(it))
fabAction = FabStates.DOWNLOAD
- photo.animate().alpha(1f).scaleXY(1f).withEndAction { fab.show() }.start()
+ photo.animate().alpha(1f).scaleXY(1f).withEndAction(fab::show).start()
}
})
} else {
@@ -135,52 +158,105 @@ class ImageActivity : KauBaseActivity() {
override fun removeCallback(cb: SizeReadyCallback?) {}
- override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) = callback(resource, true)
+ override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) =
+ callback(resource, true)
- override fun onLoadFailed(errorDrawable: Drawable?) = callback(null, false)
+ override fun onLoadFailed(errorDrawable: Drawable?) =
+ callback(null, false)
- override fun getSize(cb: SizeReadyCallback) = cb.onSizeReady(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
+ override fun getSize(cb: SizeReadyCallback) =
+ cb.onSizeReady(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
}
private fun saveTempImage(resource: Bitmap, callback: (uri: Uri?) -> Unit) {
var photoFile: File? = null
try {
- photoFile = createPrivateMediaFile(".png")
+ photoFile = createPrivateMediaFile()
} catch (e: IOException) {
errorRef = e
+ logImage(e)
} finally {
if (photoFile == null) {
callback(null)
} else {
- tempFilePath = photoFile.absolutePath
- L.d { "Temp image path $tempFilePath" }
+ tempFile = photoFile
+ L.d { "Temp image path ${tempFile?.absolutePath}" }
// File created; proceed with request
- val photoURI = FileProvider.getUriForFile(this,
- BuildConfig.APPLICATION_ID + ".provider",
- photoFile)
+ val photoURI = frostUriFromFile(photoFile)
photoFile.outputStream().use { resource.compress(Bitmap.CompressFormat.PNG, 100, it) }
callback(photoURI)
}
}
}
- internal fun downloadImage() {
+ private fun logImage(e: Exception?) {
+ if (!Prefs.analytics) return
+ val error = e ?: IOException("$imageUrl failed to load")
+ L.e(error) { "$imageUrl failed to load" }
+ }
+
+ @Throws(IOException::class)
+ private fun createPrivateMediaFile(): File {
+ val timeStamp = SimpleDateFormat(TIME_FORMAT, Locale.getDefault()).format(Date())
+ val imageFileName = "${IMG_TAG}_${timeStamp}_"
+ if (!tempDir.exists())
+ tempDir.mkdirs()
+ return File.createTempFile(imageFileName, IMG_EXTENSION, tempDir)
+ }
+
+ @Throws(IOException::class)
+ private fun createPublicMediaFile(): File {
+ val timeStamp = SimpleDateFormat(TIME_FORMAT, Locale.getDefault()).format(Date())
+ val imageFileName = "${IMG_TAG}_${timeStamp}_"
+ val storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
+ val frostDir = File(storageDir, IMG_TAG)
+ if (!frostDir.exists()) frostDir.mkdirs()
+ return File.createTempFile(imageFileName, IMG_EXTENSION, frostDir)
+ }
+
+ @Throws(IOException::class)
+ private fun downloadImageTo(file: File) {
+ val body = Request.Builder()
+ .url(imageUrl)
+ .get()
+ .call()
+ .execute()
+ .body() ?: throw IOException("Failed to retrieve image body")
+ body.byteStream().use { input ->
+ file.outputStream().use { output ->
+ input.copyTo(output)
+ }
+ }
+ }
+
+ internal fun saveImage() {
kauRequestPermissions(PERMISSION_WRITE_EXTERNAL_STORAGE) { granted, _ ->
L.d { "Download image callback granted: $granted" }
if (granted) {
doAsync {
- val destination = createMediaFile(".png")
- downloadPath = destination.absolutePath
+ val destination = createPublicMediaFile()
var success = true
try {
- File(tempFilePath).copyTo(destination, true)
- scanMedia(destination)
+ val temp = tempFile
+ if (temp != null)
+ temp.copyTo(destination, true)
+ else
+ downloadImageTo(destination)
} catch (e: Exception) {
errorRef = e
success = false
} finally {
L.d { "Download image async finished: $success" }
+ if (success) {
+ scanMedia(destination)
+ savedFile = destination
+ } else {
+ try {
+ destination.delete()
+ } catch (ignore: Exception) {
+ }
+ }
activityUiThreadWithContext {
val text = if (success) R.string.image_download_success else R.string.image_download_fail
frostSnackbar(text)
@@ -192,15 +268,9 @@ class ImageActivity : KauBaseActivity() {
}
}
- internal fun deleteTempFile() {
- if (tempFilePath != null) {
- File(tempFilePath!!).delete()
- tempFilePath = null
- }
- }
-
override fun onDestroy() {
- deleteTempFile()
+ tempFile = null
+ tempDir.deleteRecursively()
L.d { "Closing $localClassName" }
super.onDestroy()
}
@@ -229,14 +299,12 @@ internal enum class FabStates(val iicon: IIcon, val iconColor: Int = Prefs.iconC
override fun onClick(activity: ImageActivity) {}
},
DOWNLOAD(GoogleMaterial.Icon.gmd_file_download) {
- override fun onClick(activity: ImageActivity) = activity.downloadImage()
+ override fun onClick(activity: ImageActivity) = activity.saveImage()
},
SHARE(GoogleMaterial.Icon.gmd_share) {
override fun onClick(activity: ImageActivity) {
try {
- val photoURI = FileProvider.getUriForFile(activity,
- BuildConfig.APPLICATION_ID + ".provider",
- File(activity.downloadPath))
+ val photoURI = activity.frostUriFromFile(activity.savedFile!!)
val intent = Intent(Intent.ACTION_SEND).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
putExtra(Intent.EXTRA_STREAM, photoURI)