diff options
-rw-r--r-- | .idea/compiler.xml | 4 | ||||
-rw-r--r-- | .idea/jarRepositories.xml | 5 | ||||
-rw-r--r-- | .idea/misc.xml | 8 | ||||
-rw-r--r-- | app/build.gradle | 6 | ||||
-rw-r--r-- | app/src/main/AndroidManifest.xml | 5 | ||||
-rw-r--r-- | app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt | 5 | ||||
-rw-r--r-- | app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt | 136 | ||||
-rw-r--r-- | app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt | 2 | ||||
-rw-r--r-- | app/src/main/kotlin/com/pitchedapps/frost/services/LocalService.kt | 90 | ||||
-rw-r--r-- | app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt | 10 | ||||
-rw-r--r-- | app/src/main/play/en-US/whatsnew | 5 | ||||
-rw-r--r-- | app/src/main/res/layout/activity_image.xml | 4 | ||||
-rw-r--r-- | app/src/main/res/xml/frost_changelog.xml | 6 | ||||
-rw-r--r-- | buildSrc/src/main/kotlin/Versions.kt | 4 | ||||
-rw-r--r-- | docs/Changelog.md | 3 |
15 files changed, 88 insertions, 205 deletions
diff --git a/.idea/compiler.xml b/.idea/compiler.xml index fb7f4a8a..fcfdfd20 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="CompilerConfiguration"> - <bytecodeTargetLevel target="11" /> + <bytecodeTargetLevel target="11"> + <module name="Frost-for-Facebook.buildSrc" target="11" /> + </bytecodeTargetLevel> </component> </project>
\ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml index 1e2d92c1..7c680430 100644 --- a/.idea/jarRepositories.xml +++ b/.idea/jarRepositories.xml @@ -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>
\ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index c17036ff..dac62c47 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -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" /> diff --git a/app/build.gradle b/app/build.gradle index 8779069a..2655f695 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -274,6 +274,10 @@ dependencies { implementation "androidx.biometric:biometric:${Versions.andxBiometric}" + implementation "com.github.piasy:BigImageViewer:${Versions.bigImageViewer}" + implementation "com.github.piasy:GlideImageLoader:${Versions.bigImageViewer}" + implementation "com.github.piasy:GlideImageViewFactory:${Versions.bigImageViewer}" + implementation kau.Dependencies.hilt kapt kau.Dependencies.hiltCompiler testImplementation kau.Dependencies.hiltTest @@ -314,8 +318,6 @@ 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 "androidx.room:room-ktx:${Versions.room}" implementation "androidx.room:room-runtime:${Versions.room}" kapt "androidx.room:room-compiler:${Versions.room}" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5485ac15..eeab750f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -173,11 +173,6 @@ android:enabled="true" android:label="@string/frost_notifications" android:permission="android.permission.BIND_JOB_SERVICE" /> - <service - android:name=".services.LocalService" - android:enabled="true" - android:label="@string/local_service_name" - android:permission="android.permission.BIND_JOB_SERVICE" /> <receiver android:name=".services.UpdateReceiver" diff --git a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt index f5ef0b74..d444d225 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt @@ -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) {} 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 b8a71fa1..2700f1b4 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt @@ -16,10 +16,10 @@ */ package com.pitchedapps.frost.activities -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 @@ -28,7 +28,6 @@ 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 @@ -42,22 +41,17 @@ 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.github.piasy.biv.loader.ImageLoader +import com.github.piasy.biv.view.ImageShownCallback 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 @@ -73,10 +67,8 @@ 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 @@ -102,25 +94,10 @@ class ImageActivity : KauBaseActivity() { /** * Reference to the temporary file path */ - internal var tempFile: File? = null + internal val tempFile: File? get() = binding.imagePhoto.currentImageFile 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('"') ?: "" } @@ -129,11 +106,6 @@ class ImageActivity : KauBaseActivity() { 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 @@ -167,21 +139,31 @@ class ImageActivity : KauBaseActivity() { val result = if (!imageUrl.isIndirectImageUrl) imageUrl else cookie?.getFullSizedImageUrl(imageUrl) ?: imageUrl if (result != imageUrl) - L.v { "Launching with true url $result" } + L.v { "Launching image with true url $result" } + else + L.v { "Launching image with url $result" } result } binding = ActivityImageBinding.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.animate().alpha(1f).scaleXY(1f).start() + binding.showImage(trueImageUrl.await()) } } + private fun ActivityImageBinding.showImage(url: String) { + imagePhoto.showImage(Uri.parse(url)) + imagePhoto.setImageShownCallback(object : ImageShownCallback { + override fun onThumbnailShown() {} + + override fun onMainImageShown() { + imageProgress.fadeOut() + imagePhoto.animate().alpha(1f).scaleXY(1f).start() + } + }) + } + private fun ActivityImageBinding.init() { imageContainer.setBackgroundColor(baseBackgroundColor) toolbar.setBackgroundColor(baseBackgroundColor) @@ -226,12 +208,25 @@ class ImageActivity : KauBaseActivity() { share.apply { setState(FabStates.SHARE) } - imagePhoto.setOnImageEventListener(object : - SubsamplingScaleImageView.DefaultOnImageEventListener() { - override fun onImageLoadError(e: Exception) { - loadError(e) - } - }) + + imagePhoto.setImageLoaderCallback(object : ImageLoader.Callback { + override fun onCacheHit(imageType: Int, image: File?) {} + + override fun onCacheMiss(imageType: Int, image: File?) {} + + override fun onStart() {} + + override fun onProgress(progress: Int) {} + + override fun onFinish() {} + + override fun onSuccess(image: File) {} + + override fun onFail(error: Exception) { + loadError(error) + } + }) + activityThemer.setFrostColors { themeWindow = false } @@ -303,61 +298,12 @@ class ImageActivity : KauBaseActivity() { 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@ImageActivity), "$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() + companion object { + private val L = KauLoggerExtension("Image", com.pitchedapps.frost.utils.L) } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt index 1a714374..ab041adc 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt @@ -60,7 +60,7 @@ class FbCookie @Inject internal constructor( * Note that this is a synchronized call */ val webCookie: String? - get() = CookieManager.getInstance().getCookie(FB_COOKIE_DOMAIN) + get() = CookieManager.getInstance().getCookie(HTTPS_FACEBOOK_COM) val messengerCookie: String? get() = CookieManager.getInstance().getCookie(HTTPS_MESSENGER_COM) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/LocalService.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/LocalService.kt deleted file mode 100644 index 3d66f1ee..00000000 --- a/app/src/main/kotlin/com/pitchedapps/frost/services/LocalService.kt +++ /dev/null @@ -1,90 +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.services - -import android.app.job.JobInfo -import android.app.job.JobParameters -import android.app.job.JobScheduler -import android.content.ComponentName -import android.content.Context -import android.os.PersistableBundle -import com.pitchedapps.frost.activities.ImageActivity -import com.pitchedapps.frost.utils.L -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.io.FileFilter - -class LocalService : BaseJobService() { - - enum class Flag { - PURGE_IMAGE - } - - companion object { - private const val FLAG = "extra_local_flag" - - /** - * Launches a local service with the provided flag - */ - fun schedule(context: Context, flag: Flag): Boolean { - val scheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler - val serviceComponent = ComponentName(context, LocalService::class.java) - val bundle = PersistableBundle() - bundle.putString(FLAG, flag.name) - - val builder = JobInfo.Builder(LOCAL_SERVICE_BASE + flag.ordinal, serviceComponent) - .setMinimumLatency(0L) - .setExtras(bundle) - .setOverrideDeadline(2000L) - - val result = scheduler.schedule(builder.build()) - if (result <= 0) { - L.eThrow("FrostRequestService scheduler failed for ${flag.name}") - return false - } - L.d { "Scheduled ${flag.name}" } - return true - } - } - - override fun onStartJob(params: JobParameters?): Boolean { - super.onStartJob(params) - val flagString = params?.extras?.getString(FLAG) - val flag: Flag = try { - Flag.valueOf(flagString!!) - } catch (e: Exception) { - L.e { "Local service with invalid flag $flagString" } - return true - } - launch { - when (flag) { - Flag.PURGE_IMAGE -> purgeImages() - } - } - return false - } - - private suspend fun purgeImages() { - withContext(Dispatchers.IO) { - val purge = System.currentTimeMillis() - ImageActivity.PURGE_TIME - ImageActivity.cacheDir(this@LocalService) - .listFiles(FileFilter { it.isFile && it.lastModified() < purge }) - ?.forEach { it.delete() } - } - } -} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt index 94300348..a0842267 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt @@ -61,16 +61,16 @@ fun FrostWebView.requestWebOverlay(url: String): Boolean { context.runOnUiThread { context.showVideo(url) } return true } - if (url.isImageUrl) { - L.d { "Found fb image" } - context.launchImageActivity(url) - return true - } if (url.isIndirectImageUrl) { L.d { "Found indirect fb image" } context.launchImageActivity(url, cookie = fbCookie.webCookie) return true } + if (url.isImageUrl) { + L.d { "Found fb image" } + context.launchImageActivity(url) + return true + } if (!url.isIndependent) { L.d { "Forbid overlay switch" } return false diff --git a/app/src/main/play/en-US/whatsnew b/app/src/main/play/en-US/whatsnew index 06b44904..2e50ba70 100644 --- a/app/src/main/play/en-US/whatsnew +++ b/app/src/main/play/en-US/whatsnew @@ -1,4 +1,3 @@ -v3.1.1 +v3.1.2 -* Many internal fixes to address 3.1.0 issues -* Theme updates
\ No newline at end of file +* Fix loading full size images
\ 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 index 6530dc4a..689c4f4d 100644 --- a/app/src/main/res/layout/activity_image.xml +++ b/app/src/main/res/layout/activity_image.xml @@ -17,7 +17,9 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - <com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView + <!-- 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" diff --git a/app/src/main/res/xml/frost_changelog.xml b/app/src/main/res/xml/frost_changelog.xml index e5f0ade6..9bc126fb 100644 --- a/app/src/main/res/xml/frost_changelog.xml +++ b/app/src/main/res/xml/frost_changelog.xml @@ -5,6 +5,12 @@ <version title="v" /> <item text="" /> --> + + <version title="v3.1.2" /> + <item text="Fix loading full size images" /> + <item text="" /> + <item text="" /> + <version title="v3.1.1" /> <item text="Many internal fixes to address 3.1.0 issues" /> <item text="Theme updates" /> diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 5c68a01d..a8069507 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -19,8 +19,8 @@ object Versions { const val room = "2.3.0" // http://robolectric.org/getting-started/ const val roboelectric = "4.6" - // https://github.com/davemorrissey/subsampling-scale-image-view#quick-start - const val scaleImageView = "3.10.0" + // https://github.com/Piasy/BigImageViewer#add-the-dependencies + const val bigImageViewer = "1.8.1" // https://github.com/node-gradle/gradle-node-plugin/releases const val nodeGradle = "3.1.1" }
\ No newline at end of file diff --git a/docs/Changelog.md b/docs/Changelog.md index d763f8da..87a48b87 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -1,5 +1,8 @@ # Changelog +## v3.1.2 +* Fix loading full size images + ## v3.1.1 * Many internal fixes to address 3.1.0 issues * Theme updates |