From 63d8779ad4fab7d2eb762be34eeca04c7debc6f3 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Mon, 13 Nov 2017 05:09:24 -0500 Subject: Enhancement/video (#484) * Fix more parsing issues * Try catch decoder resolves #456 * Fix unit test and add null check for images, resolves #458 * Remove downloadservice, resolves #459 * Clean up progress animator * Check for download manager before download attempt * Update strings --- app/src/main/AndroidManifest.xml | 5 -- app/src/main/assets/js/click_a.js | 2 + app/src/main/assets/js/click_a.min.js | 2 +- .../pitchedapps/frost/activities/ImageActivity.kt | 1 + .../pitchedapps/frost/facebook/FbUrlFormatter.kt | 55 ++++++++++------- .../pitchedapps/frost/services/DownloadService.kt | 4 ++ .../kotlin/com/pitchedapps/frost/utils/Animator.kt | 70 ---------------------- .../com/pitchedapps/frost/utils/Downloader.kt | 19 +++++- .../kotlin/com/pitchedapps/frost/utils/Utils.kt | 2 +- .../com/pitchedapps/frost/views/FrostVideoView.kt | 4 +- .../frost/web/FrostUrlOverlayValidator.kt | 7 ++- app/src/main/res/values/strings_errors.xml | 2 + 12 files changed, 71 insertions(+), 102 deletions(-) delete mode 100644 app/src/main/kotlin/com/pitchedapps/frost/utils/Animator.kt (limited to 'app/src/main') diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5acf19d6..136a467f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -145,11 +145,6 @@ android:enabled="true" android:label="@string/frost_notifications" android:permission="android.permission.BIND_JOB_SERVICE" /> - cleanedUrl = cleanedUrl.replace(k, v, true) } - if (cleanedUrl != url && !cleanedUrl.contains("?")) cleanedUrl = cleanedUrl.replaceFirst("&", "?") + cleaned = clean(url) + } + + fun clean(url: String): String { + if (url.isBlank()) return "" + var cleanedUrl = url + discardable.forEach { cleanedUrl = cleanedUrl.replace(it, "", true) } + val changed = cleanedUrl != url + converter.forEach { (k, v) -> cleanedUrl = cleanedUrl.replace(k, v, true) } + try { cleanedUrl = URLDecoder.decode(cleanedUrl, StandardCharsets.UTF_8.name()) - val qm = cleanedUrl.indexOf("?") - if (qm > -1) { - cleanedUrl.substring(qm + 1).split("&").forEach { - val p = it.split("=") - queries.put(p[0], p.elementAtOrNull(1) ?: "") - } - cleanedUrl = cleanedUrl.substring(0, qm) + } catch (e: Exception) { + L.e(e, "Failed url formatting") + return url + } + if (changed && !cleanedUrl.contains("?")) //ensure we aren't missing '?' + cleanedUrl = cleanedUrl.replaceFirst("&", "?") + val qm = cleanedUrl.indexOf("?") + if (qm > -1) { + cleanedUrl.substring(qm + 1).split("&").forEach { + val p = it.split("=") + queries.put(p[0], p.elementAtOrNull(1) ?: "") } - discardableQueries.forEach { queries.remove(it) } - //final cleanup - misc.forEach { (k, v) -> cleanedUrl = cleanedUrl.replace(k, v, true) } - if (cleanedUrl.startsWith("#!")) cleanedUrl = cleanedUrl.substring(2) - if (cleanedUrl.startsWith("/")) cleanedUrl = FB_URL_BASE + cleanedUrl.substring(1) - cleanedUrl = cleanedUrl.replaceFirst(".facebook.com//", ".facebook.com/") //sometimes we are given a bad url - L.v(null, "Formatted url from $url to $cleanedUrl") - cleaned = cleanedUrl + cleanedUrl = cleanedUrl.substring(0, qm) } + discardableQueries.forEach { queries.remove(it) } + //final cleanup + misc.forEach { (k, v) -> cleanedUrl = cleanedUrl.replace(k, v, true) } + if (cleanedUrl.startsWith("#!")) cleanedUrl = cleanedUrl.substring(2) + if (cleanedUrl.startsWith("/")) cleanedUrl = FB_URL_BASE + cleanedUrl.substring(1) + cleanedUrl = cleanedUrl.replaceFirst(".facebook.com//", ".facebook.com/") //sometimes we are given a bad url + L.v(null, "Formatted url from $url to $cleanedUrl") + return cleanedUrl } override fun toString(): String { @@ -76,6 +85,10 @@ class FbUrlFormatter(url: String) { * Items here are explicitly removed from the url * Taken from FaceSlim * https://github.com/indywidualny/FaceSlim/blob/master/app/src/main/java/org/indywidualni/fblite/util/Miscellany.java + * + * Note: Typically, in this case, the redirect url should have all the necessary queries + * I am unsure how Facebook reacts in all cases, so the ones after the redirect are appended on afterwards + * That shouldn't break anything */ val discardable = arrayOf( "http://lm.facebook.com/l.php?u=", diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/DownloadService.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/DownloadService.kt index fda5ebf5..520d750f 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/services/DownloadService.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/services/DownloadService.kt @@ -1,5 +1,6 @@ package com.pitchedapps.frost.services +import android.annotation.SuppressLint import android.app.IntentService import android.app.Notification import android.app.PendingIntent @@ -26,11 +27,14 @@ import java.io.File /** * Created by Allan Wang on 2017-08-08. * + * Not in use + * * Background file downloader * All we are given is a link and a mime type * * With reference to the OkHttp3 sample */ +@SuppressLint("Registered") class DownloadService : IntentService("FrostVideoDownloader") { companion object { diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Animator.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Animator.kt deleted file mode 100644 index da852e6e..00000000 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Animator.kt +++ /dev/null @@ -1,70 +0,0 @@ -package com.pitchedapps.frost.utils - -import android.animation.Animator -import android.animation.AnimatorListenerAdapter -import android.animation.ValueAnimator -import android.view.animation.Interpolator - -/** - * Created by Allan Wang on 2017-11-10. - */ -class ProgressAnimator private constructor(private vararg val values: Float) { - - companion object { - inline fun ofFloat(crossinline builder: ProgressAnimator.() -> Unit) = ofFloat(0f, 1f) { builder() } - - fun ofFloat(vararg values: Float, builder: ProgressAnimator.() -> Unit) = ProgressAnimator(*values).apply { - builder() - build() - } - } - - private val animators: MutableList<(Float) -> Unit> = mutableListOf() - private val startActions: MutableList<() -> Unit> = mutableListOf() - private val endActions: MutableList<() -> Unit> = mutableListOf() - - var duration: Long = -1L - var interpolator: Interpolator? = null - - /** - * Add more changes to the [ValueAnimator] before running - */ - var extraConfigs: ValueAnimator.() -> Unit = {} - - fun withAnimator(from: Float, to: Float, animator: (Float) -> Unit) = animators.add { - val range = to - from - animator(range * it + from) - } - - fun withAnimator(animator: (Float) -> Unit) = animators.add(animator) - - fun withAnimatorInv(animator: (Float) -> Unit) = animators.add { animator(1f - it) } - - fun withStartAction(action: () -> Unit) = startActions.add(action) - - fun withEndAction(action: () -> Unit) = endActions.add(action) - - fun build() { - ValueAnimator.ofFloat(*values).apply { - if (this@ProgressAnimator.duration > 0L) - duration = this@ProgressAnimator.duration - if (this@ProgressAnimator.interpolator != null) - interpolator = this@ProgressAnimator.interpolator - addUpdateListener { - val progress = it.animatedValue as Float - animators.forEach { it(progress) } - } - addListener(object : AnimatorListenerAdapter() { - override fun onAnimationStart(animation: Animator?) { - startActions.forEach { it() } - } - - override fun onAnimationEnd(animation: Animator?) { - endActions.forEach { it() } - } - }) - extraConfigs() - start() - } - } -} \ No newline at end of file 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 3e1e1dde..e6db8eee 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt @@ -8,10 +8,15 @@ import android.os.Environment import android.webkit.URLUtil import ca.allanwang.kau.permissions.PERMISSION_WRITE_EXTERNAL_STORAGE import ca.allanwang.kau.permissions.kauRequestPermissions +import ca.allanwang.kau.utils.isAppEnabled import ca.allanwang.kau.utils.string import com.pitchedapps.frost.R import com.pitchedapps.frost.dbflow.loadFbCookie import com.pitchedapps.frost.facebook.USER_AGENT_BASIC +import android.support.v4.content.ContextCompat.startActivity +import android.content.Intent +import android.content.ActivityNotFoundException +import ca.allanwang.kau.utils.showAppInfo /** @@ -37,6 +42,16 @@ fun Context.frostDownload(uri: Uri?, L.d("Received download request", "Download $uri") if (uri.scheme != "http" && uri.scheme != "https") return L.e("Invalid download attempt", uri.toString()) + if (!isAppEnabled(DOWNLOAD_MANAGER_PACKAGE)) { + materialDialogThemed { + title(R.string.no_download_manager) + content(R.string.no_download_manager_desc) + positiveText(R.string.kau_yes) + onPositive { _, _ -> showAppInfo(DOWNLOAD_MANAGER_PACKAGE) } + negativeText(R.string.kau_no) + } + return + } kauRequestPermissions(PERMISSION_WRITE_EXTERNAL_STORAGE) { granted, _ -> if (!granted) return@kauRequestPermissions val request = DownloadManager.Request(uri) @@ -53,4 +68,6 @@ fun Context.frostDownload(uri: Uri?, val dm = getSystemService(DOWNLOAD_SERVICE) as DownloadManager dm.enqueue(request) } -} \ No newline at end of file +} + +private const val DOWNLOAD_MANAGER_PACKAGE = "com.android.providers.downloads" \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt index 22c77f5f..c644499e 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt @@ -202,7 +202,7 @@ inline val String?.isFacebookUrl get() = this != null && this.contains(FACEBOOK_COM) inline val String?.isVideoUrl - get() = this != null && this.startsWith(VIDEO_REDIRECT) + get() = this != null && (this.startsWith(VIDEO_REDIRECT) || this.startsWith("https://video-")) fun Context.frostChangelog() = showChangelog(R.xml.frost_changelog, Prefs.textColor) { theme() diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt index 639dc9ba..9d5e199a 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt @@ -8,12 +8,12 @@ import android.util.AttributeSet import android.view.GestureDetector import android.view.MotionEvent import android.view.View +import ca.allanwang.kau.ui.ProgressAnimator import ca.allanwang.kau.utils.AnimHolder import ca.allanwang.kau.utils.dpToPx import ca.allanwang.kau.utils.scaleXY import com.devbrackets.android.exomedia.ui.widget.VideoView import com.pitchedapps.frost.utils.L -import com.pitchedapps.frost.utils.ProgressAnimator /** * Created by Allan Wang on 2017-10-13. @@ -83,7 +83,7 @@ class FrostVideoView @JvmOverloads constructor( ProgressAnimator.ofFloat { duration = ANIMATION_DURATION interpolator = AnimHolder.fastOutSlowInInterpolator(context) - withAnimatorInv { viewerContract.onExpand(it) } + withAnimator { viewerContract.onExpand(1f - it) } withAnimator(origScale, scale) { scaleXY = it } withAnimator(origX, tX) { translationX = it } withAnimator(origY, tY) { translationY = it } 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 ca88a23e..e8f9fee9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt @@ -3,11 +3,13 @@ package com.pitchedapps.frost.web import com.pitchedapps.frost.activities.WebOverlayActivity import com.pitchedapps.frost.activities.WebOverlayActivityBase import com.pitchedapps.frost.activities.WebOverlayBasicActivity + import com.pitchedapps.frost.contracts.VideoViewHolder import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.facebook.USER_AGENT_BASIC import com.pitchedapps.frost.facebook.formattedFbUrl import com.pitchedapps.frost.utils.* +import org.jetbrains.anko.runOnUiThread /** * Created by Allan Wang on 2017-08-15. @@ -18,6 +20,9 @@ import com.pitchedapps.frost.utils.* * This helper method will collect all known cases and launch the overlay accordingly * Returns {@code true} (default) if action is consumed, {@code false} otherwise * + * Note that this is not always called on the main thread! + * UI related methods should always be posted or they may not be properly executed. + * * If the request already comes from an instance of [WebOverlayActivity], we will then judge * whether the user agent string should be changed. All propagated results will return false, * as we have no need of sending a new intent to the same activity @@ -26,7 +31,7 @@ fun FrostWebViewCore.requestWebOverlay(url: String): Boolean { if (url == "#") return false if (url.isVideoUrl && context is VideoViewHolder) { L.i("Found video", url) - (context as VideoViewHolder).showVideo(url) + context.runOnUiThread { (context as VideoViewHolder).showVideo(url) } return true } if (!Prefs.overlayEnabled) return false diff --git a/app/src/main/res/values/strings_errors.xml b/app/src/main/res/values/strings_errors.xml index cf1a48cb..88428652 100644 --- a/app/src/main/res/values/strings_errors.xml +++ b/app/src/main/res/values/strings_errors.xml @@ -4,4 +4,6 @@ The url could not be loaded properly. Would you like to send it for debugging? Invalid Share Url You have shared a block of text that is not a url. The text has been copied to your clipboard, so you may share it manually yourself. + No Download Manager + The download manager is not enabled. Would you like to enable it to allow downloads? \ No newline at end of file -- cgit v1.2.3