From 34e5eebbc2dfdd9e71ba200c044f3637ba89aaa2 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Sat, 29 Feb 2020 23:34:35 -0800 Subject: Prepare for android q image download support --- .../pitchedapps/frost/activities/ImageActivity.kt | 63 +++++++++++++++++----- .../com/pitchedapps/frost/utils/Downloader.kt | 5 +- 2 files changed, 53 insertions(+), 15 deletions(-) (limited to 'app/src/main') 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 6ae7622d..629d5c9b 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt @@ -16,13 +16,18 @@ */ package com.pitchedapps.frost.activities +import android.content.ContentValues import android.content.Context import android.content.Intent import android.content.res.ColorStateList import android.graphics.Color +import android.net.Uri +import android.os.Build import android.os.Bundle import android.os.Environment +import android.provider.MediaStore import android.view.View +import androidx.core.net.toFile import androidx.customview.widget.ViewDragHelper import ca.allanwang.kau.internal.KauBaseActivity import ca.allanwang.kau.logging.KauLoggerExtension @@ -49,6 +54,7 @@ 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.BuildConfig import com.pitchedapps.frost.R import com.pitchedapps.frost.databinding.ActivityImageBinding import com.pitchedapps.frost.facebook.FB_IMAGE_ID_MATCHER @@ -67,6 +73,13 @@ import com.pitchedapps.frost.utils.isIndirectImageUrl import com.pitchedapps.frost.utils.logFrostEvent import com.pitchedapps.frost.utils.sendFrostEmail import com.pitchedapps.frost.utils.setFrostColors +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 org.koin.android.ext.android.inject import java.io.File import java.io.FileNotFoundException import java.io.IOException @@ -75,14 +88,6 @@ import java.util.Date import java.util.Locale import kotlin.math.abs import kotlin.math.max -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 org.koin.android.ext.android.inject -import org.koin.core.inject /** * Created by Allan Wang on 2017-07-15. @@ -103,6 +108,8 @@ class ImageActivity : KauBaseActivity() { * Nonnull once the image is downloaded by the user */ internal var savedFile: File? = null + + internal var savedUri: Uri? = null /** * Indicator for fab's click result */ @@ -159,6 +166,7 @@ class ImageActivity : KauBaseActivity() { } errorRef = e e.logFrostEvent("Image load error") + L.e(e) { "ASDF" } with(binding) { if (imageProgress.isVisible) imageProgress.fadeOut() @@ -305,13 +313,43 @@ class ImageActivity : KauBaseActivity() { return null } return when (type.substring(6)) { - "jpeg" -> ".jpg" - "png" -> ".png" - "gif" -> ".gif" + "jpeg" -> "jpg" + "png" -> "png" + "gif" -> "gif" else -> null } } + private fun newImageUri(mimeType: String): Uri? { + val imageExtension = getImageExtension(mimeType) + val timeStamp = SimpleDateFormat(TIME_FORMAT, Locale.getDefault()).format(Date()) + val imageFileName = "${IMG_TAG}_${timeStamp}" + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + val contentValues = ContentValues().apply { + put(MediaStore.MediaColumns.DISPLAY_NAME, imageFileName) + put(MediaStore.MediaColumns.MIME_TYPE, mimeType) + put(MediaStore.MediaColumns.RELATIVE_PATH, IMG_TAG) + } + return contentResolver.insert( + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + contentValues + ) + } + val storageDir = + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + val frostDir = File(storageDir, IMG_TAG) + if (!frostDir.exists()) frostDir.mkdirs() + val imageFile = File(frostDir, "$imageFileName.$imageExtension") + return try { + frostUriFromFile(imageFile) + } catch (e: IllegalArgumentException) { + if (BuildConfig.DEBUG) { + L.e(e) { "Could not get uri for ${imageFile.absolutePath}" } + } + null + } + } + @Throws(IOException::class) private fun createPublicMediaFile(): File { val timeStamp = SimpleDateFormat(TIME_FORMAT, Locale.getDefault()).format(Date()) @@ -343,7 +381,6 @@ class ImageActivity : KauBaseActivity() { } else { file.setLastModified(System.currentTimeMillis()) } - // Forbid overwrites if (file.isFile && file.length() > 0) { L.i { "Forbid image overwrite" } @@ -370,7 +407,7 @@ class ImageActivity : KauBaseActivity() { throw IOException("Unsuccessful response for image: ${response.peekBody(128).string()}") } - imgExtension = getImageExtension(response.header("Content-Type")) ?: ".jpg" + imgExtension = getImageExtension(response.header("Content-Type")) ?: "jpg" val body = response.body ?: throw IOException("Failed to retrieve image body") diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt index 5e909b03..3c713ec9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt @@ -22,6 +22,7 @@ import android.content.Context.DOWNLOAD_SERVICE import android.net.Uri import android.os.Environment import android.webkit.URLUtil +import androidx.core.content.getSystemService import ca.allanwang.kau.permissions.PERMISSION_WRITE_EXTERNAL_STORAGE import ca.allanwang.kau.permissions.kauRequestPermissions import ca.allanwang.kau.utils.isAppEnabled @@ -64,7 +65,8 @@ fun Context.frostDownload( toast(R.string.error_invalid_download) return L.e { "Invalid download $uri" } } - if (!isAppEnabled(DOWNLOAD_MANAGER_PACKAGE)) { + val dm = getSystemService() + if (dm == null || !isAppEnabled(DOWNLOAD_MANAGER_PACKAGE)) { materialDialog { title(R.string.no_download_manager) message(R.string.no_download_manager_desc) @@ -87,7 +89,6 @@ fun Context.frostDownload( request.allowScanningByMediaScanner() request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "Frost/$title") - val dm = getSystemService(DOWNLOAD_SERVICE) as DownloadManager try { dm.enqueue(request) } catch (e: Exception) { -- cgit v1.2.3 From c1591dffa764eb16e1f825fceab0c04ac4456af4 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Sun, 1 Mar 2020 01:25:06 -0800 Subject: Rearrange image activity to use download manager --- .../pitchedapps/frost/activities/ImageActivity.kt | 218 ++++++--------------- .../com/pitchedapps/frost/utils/Downloader.kt | 8 +- .../pitchedapps/frost/views/FrostVideoViewer.kt | 2 +- .../com/pitchedapps/frost/views/FrostWebView.kt | 2 +- app/src/main/res/layout/activity_image.xml | 39 +++- app/src/main/res/values/styles.xml | 9 + 6 files changed, 105 insertions(+), 173 deletions(-) (limited to 'app/src/main') 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 629d5c9b..4abdd15f 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt @@ -16,29 +16,23 @@ */ package com.pitchedapps.frost.activities -import android.content.ContentValues import android.content.Context import android.content.Intent import android.content.res.ColorStateList import android.graphics.Color -import android.net.Uri -import android.os.Build import android.os.Bundle -import android.os.Environment -import android.provider.MediaStore import android.view.View -import androidx.core.net.toFile +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.mediapicker.scanMedia -import ca.allanwang.kau.permissions.PERMISSION_WRITE_EXTERNAL_STORAGE -import ca.allanwang.kau.permissions.kauRequestPermissions 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 @@ -54,7 +48,6 @@ 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.BuildConfig import com.pitchedapps.frost.R import com.pitchedapps.frost.databinding.ActivityImageBinding import com.pitchedapps.frost.facebook.FB_IMAGE_ID_MATCHER @@ -67,6 +60,7 @@ 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.Prefs +import com.pitchedapps.frost.utils.frostDownload import com.pitchedapps.frost.utils.frostSnackbar import com.pitchedapps.frost.utils.frostUriFromFile import com.pitchedapps.frost.utils.isIndirectImageUrl @@ -83,9 +77,6 @@ import org.koin.android.ext.android.inject import java.io.File import java.io.FileNotFoundException import java.io.IOException -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale import kotlin.math.abs import kotlin.math.max @@ -102,28 +93,10 @@ class ImageActivity : KauBaseActivity() { /** * Reference to the temporary file path */ - internal lateinit var tempFile: File - /** - * Reference to path for downloaded image - * Nonnull once the image is downloaded by the user - */ - internal var savedFile: File? = null - - internal var savedUri: Uri? = null - /** - * Indicator for fab's click result - */ - internal var fabAction: FabStates = FabStates.NOTHING - set(value) { - if (field == value) return - field = value - value.update(binding.imageFab, prefs) - } + internal var tempFile: File? = null private lateinit var dragHelper: ViewDragHelper - private var imgExtension: String = ".jpg" - companion object { /** * Cache folder to store images @@ -152,7 +125,7 @@ class ImageActivity : KauBaseActivity() { "${abs(FB_IMAGE_ID_MATCHER.find(imageUrl)[1]?.hashCode() ?: 0)}_${abs(imageUrl.hashCode())}" } - private lateinit var binding: ActivityImageBinding + lateinit var binding: ActivityImageBinding private var bottomBehavior: BottomSheetBehavior? = null private val baseBackgroundColor = if (prefs.blackMediaBg) Color.BLACK @@ -166,13 +139,12 @@ class ImageActivity : KauBaseActivity() { } errorRef = e e.logFrostEvent("Image load error") - L.e(e) { "ASDF" } with(binding) { if (imageProgress.isVisible) imageProgress.fadeOut() } - tempFile.delete() - fabAction = FabStates.ERROR + tempFile?.delete() + binding.error.fadeIn() } override fun onCreate(savedInstanceState: Bundle?) { @@ -190,34 +162,31 @@ class ImageActivity : KauBaseActivity() { } binding = ActivityImageBinding.inflate(layoutInflater) setContentView(binding.root) - binding.onCreate() - tempFile = File(cacheDir(this), imageHash) + binding.init() launch(CoroutineExceptionHandler { _, throwable -> loadError(throwable) }) { - downloadImageTo(tempFile) + val tempFile = downloadTempImage() + this@ImageActivity.tempFile = tempFile binding.imageProgress.fadeOut() binding.imagePhoto.setImage(ImageSource.uri(frostUriFromFile(tempFile))) - fabAction = FabStates.DOWNLOAD binding.imagePhoto.animate().alpha(1f).scaleXY(1f).start() } } - private fun ActivityImageBinding.onCreate() { + private fun ActivityImageBinding.init() { imageContainer.setBackgroundColor(baseBackgroundColor) + toolbar.setBackgroundColor(baseBackgroundColor) this@ImageActivity.imageText.also { text -> if (text.isNullOrBlank()) { imageText.gone() } else { imageText.setTextColor(if (prefs.blackMediaBg) Color.WHITE else prefs.textColor) imageText.setBackgroundColor( - (if (prefs.blackMediaBg) Color.BLACK else prefs.bgColor) - .colorToForeground(0.2f).withAlpha(255) + baseBackgroundColor.colorToForeground(0.2f).withAlpha(255) ) imageText.text = text bottomBehavior = BottomSheetBehavior.from(imageText).apply { - setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { + addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onSlide(bottomSheet: View, slideOffset: Float) { - if (slideOffset == 0f && !imageFab.isShown) imageFab.show() - else if (slideOffset != 0f && imageFab.isShown) imageFab.hide() imageText.alpha = slideOffset / 2 + 0.5f } @@ -229,8 +198,24 @@ class ImageActivity : KauBaseActivity() { imageText.bringToFront() } } - imageProgress.tint(if (prefs.blackMediaBg) Color.WHITE else prefs.accentColor) - imageFab.setOnClickListener { fabAction.onClick(this@ImageActivity) } + val foregroundTint = if (prefs.blackMediaBg) Color.WHITE else prefs.accentColor + + fun ImageView.setState(state: FabStates) { + setIcon(state.iicon, color = foregroundTint, sizeDp = 24) + setOnClickListener { state.onClick(this@ImageActivity) } + } + + imageProgress.tint(foregroundTint) + error.apply { + invisible() + setState(FabStates.ERROR) + } + download.apply { + setState(FabStates.DOWNLOAD) + } + share.apply { + setState(FabStates.SHARE) + } imagePhoto.setOnImageEventListener(object : SubsamplingScaleImageView.DefaultOnImageEventListener() { override fun onImageLoadError(e: Exception) { @@ -275,7 +260,7 @@ class ImageActivity : KauBaseActivity() { scrollToTop = top < 0 val multiplier = max(1f - scrollPercent, 0f) - imageFab.alpha = multiplier + toolbar.alpha = multiplier bottomBehavior?.also { imageText.alpha = multiplier * (if (it.state == BottomSheetBehavior.STATE_COLLAPSED) 0.5f else 1f) @@ -320,122 +305,29 @@ class ImageActivity : KauBaseActivity() { } } - private fun newImageUri(mimeType: String): Uri? { - val imageExtension = getImageExtension(mimeType) - val timeStamp = SimpleDateFormat(TIME_FORMAT, Locale.getDefault()).format(Date()) - val imageFileName = "${IMG_TAG}_${timeStamp}" - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - val contentValues = ContentValues().apply { - put(MediaStore.MediaColumns.DISPLAY_NAME, imageFileName) - put(MediaStore.MediaColumns.MIME_TYPE, mimeType) - put(MediaStore.MediaColumns.RELATIVE_PATH, IMG_TAG) - } - return contentResolver.insert( - MediaStore.Images.Media.EXTERNAL_CONTENT_URI, - contentValues - ) - } - val storageDir = - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) - val frostDir = File(storageDir, IMG_TAG) - if (!frostDir.exists()) frostDir.mkdirs() - val imageFile = File(frostDir, "$imageFileName.$imageExtension") - return try { - frostUriFromFile(imageFile) - } catch (e: IllegalArgumentException) { - if (BuildConfig.DEBUG) { - L.e(e) { "Could not get uri for ${imageFile.absolutePath}" } - } - null - } - } - @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, imgExtension, frostDir) - } - - /** - * Saves the image to the specified file, creating it if it doesn't exist. - * Returns true if a change is made, false otherwise. - * Throws an error if something goes wrong. - */ - @Throws(IOException::class) - private suspend fun downloadImageTo(file: File): Boolean { - val exceptionHandler = CoroutineExceptionHandler { _, err -> - if (file.isFile && file.length() == 0L) { - file.delete() - } - throw err + private suspend fun downloadTempImage(): File = withContext(Dispatchers.IO) { + val response = cookie.requestBuilder() + .url(trueImageUrl.await()) + .get() + .call() + .execute() + + if (!response.isSuccessful) { + throw IOException("Unsuccessful response for image: ${response.peekBody(128).string()}") } - return withContext(Dispatchers.IO + exceptionHandler) { - 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 false - } - // Fast route, image is already downloaded - if (tempFile.isFile && tempFile.length() > 0) { - if (tempFile == file) { - return@withContext false - } - tempFile.copyTo(file, true) - return@withContext true - } - - // No temp file, download ourselves - val response = cookie.requestBuilder() - .url(trueImageUrl.await()) - .get() - .call() - .execute() - - if (!response.isSuccessful) { - throw IOException("Unsuccessful response for image: ${response.peekBody(128).string()}") - } + val imgExtension = getImageExtension(response.header("Content-Type")) ?: "jpg" - imgExtension = getImageExtension(response.header("Content-Type")) ?: "jpg" + val body = response.body ?: throw IOException("Failed to retrieve image body") - val body = response.body ?: throw IOException("Failed to retrieve image body") - - file.copyFromInputStream(body.byteStream()) - - return@withContext true - } + val tempFile = File(cacheDir(this@ImageActivity), "$imageHash.$imgExtension") + tempFile.copyFromInputStream(body.byteStream()) + tempFile } - internal fun saveImage() { - kauRequestPermissions(PERMISSION_WRITE_EXTERNAL_STORAGE) { granted, _ -> - L.d { "Download image callback granted: $granted" } - if (granted) { - val errorHandler = CoroutineExceptionHandler { _, throwable -> - loadError(throwable) - frostSnackbar(R.string.image_download_fail) - } - launch(errorHandler) { - val destination = createPublicMediaFile() - downloadImageTo(destination) - L.d { "Download image async finished" } - scanMedia(destination) - savedFile = destination - frostSnackbar(R.string.image_download_success) - fabAction = FabStates.SHARE - } - } - } + internal suspend fun saveImage() { + frostDownload(cookie = cookie, url = trueImageUrl.await()) } override fun onDestroy() { @@ -472,12 +364,18 @@ internal enum class FabStates( override fun onClick(activity: ImageActivity) {} }, DOWNLOAD(GoogleMaterial.Icon.gmd_file_download) { - override fun onClick(activity: ImageActivity) = activity.saveImage() + override fun onClick(activity: ImageActivity) { + activity.launch { + activity.saveImage() + activity.binding.download.fadeOut() + } + } }, SHARE(GoogleMaterial.Icon.gmd_share) { override fun onClick(activity: ImageActivity) { + val file = activity.tempFile ?: return try { - val photoURI = activity.frostUriFromFile(activity.savedFile!!) + val photoURI = activity.frostUriFromFile(file) val intent = Intent(Intent.ACTION_SEND).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK putExtra(Intent.EXTRA_STREAM, photoURI) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt index 3c713ec9..60c642f4 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt @@ -40,7 +40,7 @@ import com.pitchedapps.frost.facebook.USER_AGENT * With reference to Stack Overflow */ fun Context.frostDownload( - cookie: CookieEntity, + cookie: String?, url: String?, userAgent: String = USER_AGENT, contentDisposition: String? = null, @@ -52,7 +52,7 @@ fun Context.frostDownload( } fun Context.frostDownload( - cookie: CookieEntity, + cookie: String?, uri: Uri?, userAgent: String = USER_AGENT, contentDisposition: String? = null, @@ -82,7 +82,9 @@ fun Context.frostDownload( val request = DownloadManager.Request(uri) request.setMimeType(mimeType) val title = URLUtil.guessFileName(uri.toString(), contentDisposition, mimeType) - request.addRequestHeader("Cookie", cookie.cookie) + if (cookie != null) { + request.addRequestHeader("Cookie", cookie) + } request.addRequestHeader("User-Agent", userAgent) request.setDescription(string(R.string.downloading)) request.setTitle(title) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt index ec822bfa..20480d10 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt @@ -118,7 +118,7 @@ class FrostVideoViewer @JvmOverloads constructor( R.id.action_pip -> video.isExpanded = false R.id.action_download -> context.ctxCoroutine.launchMain { val cookie = cookieDao.currentCookie(prefs) ?: return@launchMain - context.frostDownload(cookie, video.videoUri) + context.frostDownload(cookie.cookie, video.videoUri) } } true diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt index 9ca622a3..b04b8855 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt @@ -98,7 +98,7 @@ class FrostWebView @JvmOverloads constructor( context.ctxCoroutine.launchMain { val cookie = cookieDao.currentCookie(prefs) ?: return@launchMain context.frostDownload( - cookie, + cookie.cookie, url, userAgent, contentDisposition, diff --git a/app/src/main/res/layout/activity_image.xml b/app/src/main/res/layout/activity_image.xml index 7d79cb74..6530dc4a 100644 --- a/app/src/main/res/layout/activity_image.xml +++ b/app/src/main/res/layout/activity_image.xml @@ -27,6 +27,37 @@ + + + + + + + + + + + + - - diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index b94f754f..fcacacc3 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -182,4 +182,13 @@ @dimen/drawer_nav_horizontal_margins + + -- cgit v1.2.3 From fd7a35809b360c3ca97e11a794e5f21734868d61 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Sun, 1 Mar 2020 01:32:10 -0800 Subject: Avoid downloading temp image if it already exists --- app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'app/src/main') 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 4abdd15f..f12ca7aa 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt @@ -322,7 +322,9 @@ class ImageActivity : KauBaseActivity() { val body = response.body ?: throw IOException("Failed to retrieve image body") val tempFile = File(cacheDir(this@ImageActivity), "$imageHash.$imgExtension") - tempFile.copyFromInputStream(body.byteStream()) + if (!tempFile.exists() || tempFile.length() == 0L) { + tempFile.copyFromInputStream(body.byteStream()) + } tempFile } -- cgit v1.2.3 From 0acf9aae5e25a80954bffba767b238e810166923 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Sun, 1 Mar 2020 01:33:08 -0800 Subject: Fade out download icon before download completes --- app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main') 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 f12ca7aa..f8ba32c4 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt @@ -368,8 +368,8 @@ internal enum class FabStates( DOWNLOAD(GoogleMaterial.Icon.gmd_file_download) { override fun onClick(activity: ImageActivity) { activity.launch { - activity.saveImage() activity.binding.download.fadeOut() + activity.saveImage() } } }, -- cgit v1.2.3 From 23acc1b70887dc7b1a9600a8cdef1e2c9676665d Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Sun, 1 Mar 2020 01:48:40 -0800 Subject: Update changelog --- app/src/main/play/en-US/whatsnew | 3 ++- app/src/main/res/xml/frost_changelog.xml | 2 +- docs/Changelog.md | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/play/en-US/whatsnew b/app/src/main/play/en-US/whatsnew index 4474eebc..cd456c04 100644 --- a/app/src/main/play/en-US/whatsnew +++ b/app/src/main/play/en-US/whatsnew @@ -1,4 +1,5 @@ v2.4.4 * Lots of under the hood fixes -* Fixed sharing \ No newline at end of file +* Fixed sharing +* Fix photo downloads for Android Q+ \ No newline at end of file diff --git a/app/src/main/res/xml/frost_changelog.xml b/app/src/main/res/xml/frost_changelog.xml index 99a48160..28ac4402 100644 --- a/app/src/main/res/xml/frost_changelog.xml +++ b/app/src/main/res/xml/frost_changelog.xml @@ -9,7 +9,7 @@ - + diff --git a/docs/Changelog.md b/docs/Changelog.md index 4280780a..51ef89f8 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -3,6 +3,7 @@ ## v2.4.4 * Lots of under the hood fixes * Fixed sharing +* Fix photo downloads for Android Q+ ## v2.4.3 * Fix Android theme -- cgit v1.2.3