1
0
mirror of https://github.com/AllanWang/Frost-for-Facebook.git synced 2024-11-08 20:12:39 +01:00

Enhancement/debug mode (#779)

* Update changelog

* Improve debugger

* Remove need for mapping urls

* Remove excess logs

* Clean up
This commit is contained in:
Allan Wang 2018-03-11 19:24:32 -04:00 committed by GitHub
parent 67988a25d8
commit fe51373f5a
34 changed files with 201 additions and 140 deletions

View File

@ -59,7 +59,7 @@ class AboutActivity : AboutActivityBase(null, {
"subsamplingscaleimageview"
)
val l = libs.prepareLibraries(this, include, null, false, true,true)
val l = libs.prepareLibraries(this, include, null, false, true, true)
// l.forEach { KL.d{"Lib ${it.definedName}"} }
return l
}
@ -88,14 +88,18 @@ class AboutActivity : AboutActivityBase(null, {
if (item is LibraryIItem) {
val now = System.currentTimeMillis()
if (now - lastClick > 500)
clickCount = 0
clickCount = 1
else
clickCount++
lastClick = now
if (clickCount == 7 && !Prefs.debugSettings) {
Prefs.debugSettings = true
L.d { "Debugging section enabled" }
toast(R.string.debug_toast_enabled)
if (clickCount == 8) {
if (!Prefs.debugSettings) {
Prefs.debugSettings = true
L.d { "Debugging section enabled" }
toast(R.string.debug_toast_enabled)
} else {
toast(R.string.debug_toast_already_enabled)
}
}
}
false

View File

@ -15,10 +15,15 @@ import ca.allanwang.kau.utils.visible
import com.mikepenz.google_material_typeface_library.GoogleMaterial
import com.pitchedapps.frost.R
import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.injectors.JsActions
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.createFreshDir
import com.pitchedapps.frost.utils.setFrostColors
import com.pitchedapps.frost.web.DebugWebView
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.io.File
/**
@ -33,6 +38,8 @@ class DebugActivity : KauBaseActivity() {
companion object {
const val RESULT_URL = "extra_result_url"
const val RESULT_SCREENSHOT = "extra_result_screenshot"
const val RESULT_BODY = "extra_result_body"
fun baseDir(context: Context) = File(context.externalCacheDir, "offline_debug")
}
@ -61,13 +68,34 @@ class DebugActivity : KauBaseActivity() {
val parent = baseDir(this)
parent.createFreshDir()
val file = File(parent, "screenshot.png")
web.getScreenshot(file) {
val intent = Intent()
intent.putExtra(RESULT_URL, web.url)
setResult(Activity.RESULT_OK, intent)
finish()
}
val rxScreenshot = Single.fromCallable {
web.getScreenshot(File(parent, "screenshot.png"))
}.subscribeOn(Schedulers.io())
val rxBody = Single.create<String> { emitter ->
web.evaluateJavascript(JsActions.RETURN_BODY.function) {
emitter.onSuccess(it)
}
}.subscribeOn(AndroidSchedulers.mainThread())
Single.zip(listOf(rxScreenshot, rxBody), {
val screenshot = it[0] == true
val body = it[1] as? String
screenshot to body
}).observeOn(AndroidSchedulers.mainThread())
.subscribe { (screenshot, body), err ->
if (err != null) {
L.e { "DebugActivity error ${err.message}" }
setResult(Activity.RESULT_CANCELED)
finish()
return@subscribe
}
val intent = Intent()
intent.putExtra(RESULT_URL, web.url)
intent.putExtra(RESULT_SCREENSHOT, screenshot)
if (body != null)
intent.putExtra(RESULT_BODY, body)
setResult(Activity.RESULT_OK, intent)
finish()
}
}
}

View File

@ -92,7 +92,8 @@ class ImageActivity : KauBaseActivity() {
// a unique image identifier based on the id (if it exists), and its hash
private val IMAGE_HASH: String by lazy {
"${Math.abs(FB_IMAGE_ID_MATCHER.find(IMAGE_URL)[1]?.hashCode() ?: 0)}_${Math.abs(IMAGE_URL.hashCode())}"
"${Math.abs(FB_IMAGE_ID_MATCHER.find(IMAGE_URL)[1]?.hashCode()
?: 0)}_${Math.abs(IMAGE_URL.hashCode())}"
}
override fun onCreate(savedInstanceState: Bundle?) {

View File

@ -83,32 +83,32 @@ class LoginActivity : BaseActivity() {
usernameSubject,
BiFunction(::Pair))
.observeOn(AndroidSchedulers.mainThread()).subscribe { (foundImage, name) ->
refresh = false
if (!foundImage) {
L.e { "Could not get profile photo; Invalid userId?" }
L._i { cookie }
}
textview.text = String.format(getString(R.string.welcome), name)
textview.fadeIn()
frostAnswers {
logLogin(LoginEvent()
.putMethod("frost_browser")
.putSuccess(true))
}
/*
* The user may have logged into an account that is already in the database
* We will let the db handle duplicates and load it now after the new account has been saved
*/
loadFbCookiesAsync {
val cookies = ArrayList(it)
Handler().postDelayed({
if (Showcase.intro)
launchNewTask<IntroActivity>(cookies, true)
else
launchNewTask<MainActivity>(cookies, true)
}, 1000)
}
}
refresh = false
if (!foundImage) {
L.e { "Could not get profile photo; Invalid userId?" }
L._i { cookie }
}
textview.text = String.format(getString(R.string.welcome), name)
textview.fadeIn()
frostAnswers {
logLogin(LoginEvent()
.putMethod("frost_browser")
.putSuccess(true))
}
/*
* The user may have logged into an account that is already in the database
* We will let the db handle duplicates and load it now after the new account has been saved
*/
loadFbCookiesAsync {
val cookies = ArrayList(it)
Handler().postDelayed({
if (Showcase.intro)
launchNewTask<IntroActivity>(cookies, true)
else
launchNewTask<MainActivity>(cookies, true)
}, 1000)
}
}
loadProfile(cookie.id)
loadUsername(cookie)
}
@ -117,17 +117,17 @@ class LoginActivity : BaseActivity() {
private fun loadProfile(id: Long) {
profileLoader.load(PROFILE_PICTURE_URL(id))
.transform(FrostGlide.roundCorner).listener(object : RequestListener<Drawable> {
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
profileSubject.onSuccess(true)
return false
}
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
profileSubject.onSuccess(true)
return false
}
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
e.logFrostAnswers("Profile loading exception")
profileSubject.onSuccess(false)
return false
}
}).into(profile)
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
e.logFrostAnswers("Profile loading exception")
profileSubject.onSuccess(false)
return false
}
}).into(profile)
}
private fun loadUsername(cookie: CookieModel) {

View File

@ -52,7 +52,7 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IabSettings() {
ACTIVITY_REQUEST_DEBUG -> {
val url = data?.extras?.getString(DebugActivity.RESULT_URL)
if (resultCode == Activity.RESULT_OK && url?.isNotBlank() == true)
sendDebug(url)
sendDebug(url, data.extras.getString(DebugActivity.RESULT_BODY))
return
}
}

View File

@ -17,6 +17,7 @@ interface MainActivityContract : ActivityContract, MainFabContract {
* Available on all threads
*/
fun collapseAppBar()
fun reloadFragment(fragment: BaseFragment)
}

View File

@ -15,8 +15,7 @@ interface VideoViewHolder : FrameWrapper, FrostVideoContainerContract {
var videoViewer: FrostVideoViewer?
fun showVideo(url: String)
= showVideo(url, false)
fun showVideo(url: String) = showVideo(url, false)
/**
* Create new viewer and reuse existing one

View File

@ -29,7 +29,8 @@ class NotificationMigration2(modelClass: Class<NotificationModel>) : AlterTableM
@Table(database = NotificationDb::class, allFields = true, primaryKeyConflict = ConflictAction.REPLACE)
data class NotificationModel(@PrimaryKey var id: Long = -1L, var epoch: Long = -1L, var epochIm: Long = -1) : BaseModel()
fun lastNotificationTime(id: Long): NotificationModel = (select from NotificationModel::class where (NotificationModel_Table.id eq id)).querySingle() ?: NotificationModel(id = id)
fun lastNotificationTime(id: Long): NotificationModel = (select from NotificationModel::class where (NotificationModel_Table.id eq id)).querySingle()
?: NotificationModel(id = id)
fun saveNotificationTime(notificationModel: NotificationModel, callback: (() -> Unit)? = null) {
notificationModel.async save {

View File

@ -9,8 +9,11 @@ import com.pitchedapps.frost.facebook.requests.zip
import com.pitchedapps.frost.utils.createFreshDir
import com.pitchedapps.frost.utils.createFreshFile
import com.pitchedapps.frost.utils.frostJsoup
import com.pitchedapps.frost.utils.unescapeHtml
import okhttp3.Request
import okhttp3.ResponseBody
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.nodes.Entities
import java.io.File
@ -29,6 +32,8 @@ import java.util.zip.ZipOutputStream
*/
class OfflineWebsite(private val url: String,
private val cookie: String = "",
baseUrl: String? = null,
private val html: String? = null,
/**
* Directory that holds all the files
*/
@ -38,7 +43,8 @@ class OfflineWebsite(private val url: String,
/**
* Supplied url without the queries
*/
val baseUrl = url.substringBefore("?").trim('/')
private val baseUrl = (baseUrl ?: url.substringBefore("?")
.substringBefore(".com")).trim('/')
private val mainFile = File(baseDir, "index.html")
private val assetDir = File(baseDir, "assets")
@ -50,7 +56,7 @@ class OfflineWebsite(private val url: String,
private val L = KauLoggerExtension("Offline", com.pitchedapps.frost.utils.L)
init {
if (!baseUrl.startsWith("http"))
if (!this.baseUrl.startsWith("http"))
throw IllegalArgumentException("Base Url must start with http")
}
@ -94,7 +100,13 @@ class OfflineWebsite(private val url: String,
if (cancelled) return
val doc = frostJsoup(cookie, url)
val doc: Document
if (html == null || html.length < 100) {
doc = frostJsoup(cookie, url)
} else {
doc = Jsoup.parse("<html>${html.unescapeHtml()}</html>")
L.d { "Building data from supplied content of size ${html.length}" }
}
doc.setBaseUri(baseUrl)
doc.outputSettings().escapeMode(Entities.EscapeMode.extended)
if (doc.childNodeSize() == 0) {
@ -125,8 +137,11 @@ class OfflineWebsite(private val url: String,
progress(50)
downloadCss().subscribe { cssLinks, cssThrowable ->
if (cssThrowable != null) {
L.e { "CSS parsing failed" }
L.e { "CSS parsing failed: ${cssThrowable.message} $cssThrowable" }
callback(false)
return@subscribe
}
progress(70)
@ -291,8 +306,8 @@ class OfflineWebsite(private val url: String,
private fun String.shorten() =
if (length <= 10) this else substring(length - 10)
private fun Set<String>.clean()
= filter(String::isNotBlank).filter { it.startsWith("http") }
private fun Set<String>.clean(): List<String> =
filter(String::isNotBlank).filter { it.startsWith("http") }
private fun reset() {
cancelled = false

View File

@ -130,6 +130,8 @@ fun String.getAuth(): RequestAuth {
inline fun <T, reified R : Any, O> Array<T>.zip(crossinline mapper: (List<R>) -> O,
crossinline caller: (T) -> R): Single<O> {
if (isEmpty())
return Single.just(mapper(emptyList()))
val singles = map { Single.fromCallable { caller(it) }.subscribeOn(Schedulers.io()) }
return Single.zip(singles) {
val results = it.mapNotNull { it as? R }

View File

@ -76,7 +76,8 @@ class HdImageLoading : ModelLoader<HdImageMaybe, InputStream> {
class HdImageFetcher(private val model: HdImageMaybe) : DataFetcher<InputStream> {
@Volatile private var cancelled: Boolean = false
@Volatile
private var cancelled: Boolean = false
private var urlCall: Call? = null
private var inputStream: InputStream? = null
@ -92,7 +93,8 @@ class HdImageFetcher(private val model: HdImageMaybe) : DataFetcher<InputStream>
if (!model.isValid) return callback.fail("Model is invalid")
model.cookie.fbRequest(fail = { callback.fail("Invalid auth") }) {
if (cancelled) return@fbRequest callback.fail("Cancelled")
val url = getFullSizedImage(model.id).invoke() ?: return@fbRequest callback.fail("Null url")
val url = getFullSizedImage(model.id).invoke()
?: return@fbRequest callback.fail("Null url")
if (cancelled) return@fbRequest callback.fail("Cancelled")
if (!url.contains("png") && !url.contains("jpg")) return@fbRequest callback.fail("Invalid format")
urlCall = Request.Builder().url(url).get().call()

View File

@ -1,6 +1,5 @@
package com.pitchedapps.frost.fragments
import android.support.design.widget.FloatingActionButton
import com.pitchedapps.frost.contracts.*
import com.pitchedapps.frost.views.FrostRecyclerView
import io.reactivex.disposables.Disposable

View File

@ -9,7 +9,7 @@ import android.webkit.WebView
*/
enum class CssHider(vararg val items: String) : InjectorContract {
CORE("[data-sigil=m_login_upsell]", "role=progressbar"),
// HEADER("#header", "[data-sigil=MTopBlueBarHeader]",
// HEADER("#header", "[data-sigil=MTopBlueBarHeader]",
// "#header-notices", "[data-sigil*=m-promo-jewel-header]"),
ADS("article[data-xt*=sponsor]",
"article[data-store*=sponsor]"),

View File

@ -16,6 +16,7 @@ enum class JsActions(body: String) : InjectorContract {
LOGIN_CHECK("document.getElementById('signup-button')&&Frost.loadLogin();"),
BASE_HREF("""document.write("<base href='$FB_URL_BASE'/>");"""),
FETCH_BODY("""setTimeout(function(){var e=document.querySelector("main");e||(e=document.querySelector("body")),Frost.handleHtml(e.outerHTML)},1e2);"""),
RETURN_BODY("return(document.getElementsByTagName('html')[0].innerHTML);"),
CREATE_POST(clickBySelector("button[name=view_overview]")),
// CREATE_MSG(clickBySelector("a[rel=dialog]")),
/**
@ -23,7 +24,7 @@ enum class JsActions(body: String) : InjectorContract {
*/
EMPTY("");
val function = "!function(){$body}();"
val function = "(function(){$body})();"
override fun inject(webView: WebView, callback: (() -> Unit)?) =
JsInjector(function).inject(webView, callback)

View File

@ -101,8 +101,7 @@ fun WebView.jsInject(vararg injectors: InjectorContract, callback: ((Int) -> Uni
}
fun FrostWebViewClient.jsInject(vararg injectors: InjectorContract,
callback: ((Int) -> Unit)? = null)
= web.jsInject(*injectors, callback = callback)
callback: ((Int) -> Unit)? = null) = web.jsInject(*injectors, callback = callback)
/**
* Wrapper class to convert a function into an injector

View File

@ -22,8 +22,7 @@ class IntroFragmentTheme : BaseIntroFragment(R.layout.intro_theme) {
val themeList
get() = listOf(light, dark, amoled, glass)
override fun viewArray(): Array<Array<out View>>
= arrayOf(arrayOf(title), arrayOf(light, dark), arrayOf(amoled, glass))
override fun viewArray(): Array<Array<out View>> = arrayOf(arrayOf(title), arrayOf(light, dark), arrayOf(amoled, glass))
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

View File

@ -25,8 +25,7 @@ abstract class BaseImageIntroFragment(
val screen: Drawable by lazyResettableRegistered { imageDrawable.findDrawableByLayerId(R.id.intro_phone_screen) }
val icon: ImageView by bindViewResettable(R.id.intro_button)
override fun viewArray(): Array<Array<out View>>
= arrayOf(arrayOf(title), arrayOf(desc))
override fun viewArray(): Array<Array<out View>> = arrayOf(arrayOf(title), arrayOf(desc))
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
title.setText(titleRes)

View File

@ -1,6 +1,5 @@
package com.pitchedapps.frost.services
import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
@ -93,7 +92,7 @@ fun NotificationCompat.Builder.setFrostAlert(enable: Boolean, ringtone: String):
if (enable) Notification.GROUP_ALERT_CHILDREN
else Notification.GROUP_ALERT_SUMMARY)
} else if (!enable) {
setDefaults(0)
setDefaults(0)
} else {
var defaults = 0
if (Prefs.notificationVibrate) defaults = defaults or Notification.DEFAULT_VIBRATE

View File

@ -10,6 +10,7 @@ import com.pitchedapps.frost.activities.DebugActivity
import com.pitchedapps.frost.activities.SettingsActivity
import com.pitchedapps.frost.activities.SettingsActivity.Companion.ACTIVITY_REQUEST_DEBUG
import com.pitchedapps.frost.debugger.OfflineWebsite
import com.pitchedapps.frost.facebook.FB_URL_BASE
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.parsers.FrostParser
@ -90,18 +91,12 @@ private fun Context.createEmail(parser: FrostParser<*>, content: Any?) =
private const val ZIP_NAME = "debug"
fun SettingsActivity.sendDebug(urlOrig: String) {
val url = when {
urlOrig.endsWith("soft=requests") -> FbItem.FRIENDS.url
urlOrig.endsWith("soft=messages") -> FbItem.MESSAGES.url
urlOrig.endsWith("soft=notifications") -> FbItem.NOTIFICATIONS.url
urlOrig.endsWith("soft=search") -> "${FbItem._SEARCH.url}?q=a"
else -> urlOrig
}
fun SettingsActivity.sendDebug(url: String, html: String?) {
val downloader = OfflineWebsite(url, FbCookie.webCookie ?: "",
DebugActivity.baseDir(this))
baseUrl = FB_URL_BASE,
html = html,
baseDir = DebugActivity.baseDir(this))
val md = materialDialog {
title(R.string.parsing_data)

View File

@ -54,8 +54,10 @@ class AnimatedVectorDelegate(
override fun bind(view: ImageView) {
this.view = view
view.context.drawable(avdStart) as? AnimatedVectorDrawable ?: throw IllegalArgumentException("AnimatedVectorDelegate has a starting drawable that isn't an avd")
view.context.drawable(avdEnd) as? AnimatedVectorDrawable ?: throw IllegalArgumentException("AnimatedVectorDelegate has an ending drawable that isn't an avd")
view.context.drawable(avdStart) as? AnimatedVectorDrawable
?: throw IllegalArgumentException("AnimatedVectorDelegate has a starting drawable that isn't an avd")
view.context.drawable(avdEnd) as? AnimatedVectorDrawable
?: throw IllegalArgumentException("AnimatedVectorDelegate has an ending drawable that isn't an avd")
view.setImageResource(avdStart)
if (emitOnBind) animatedVectorListener?.invoke(avd!!, false)
}

View File

@ -32,6 +32,7 @@ import com.pitchedapps.frost.dbflow.CookieModel
import com.pitchedapps.frost.facebook.*
import com.pitchedapps.frost.facebook.FbUrlFormatter.Companion.VIDEO_REDIRECT
import com.pitchedapps.frost.utils.iab.IS_FROST_PRO
import org.apache.commons.text.StringEscapeUtils
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
import java.io.File
@ -342,4 +343,9 @@ fun File.createFreshDir(): Boolean {
if (exists() && !deleteRecursively())
return false
return mkdirs()
}
}
fun String.unescapeHtml(): String =
StringEscapeUtils.unescapeXml(this)
.replace("\\u003C", "<")
.replace("\\\"", "\"")

View File

@ -94,8 +94,8 @@ abstract class IabBinder : FrostBilling {
error.logFrostAnswers("IAB error $errorCode")
}
override fun onActivityResultBilling(requestCode: Int, resultCode: Int, data: Intent?): Boolean
= bp?.handleActivityResult(requestCode, resultCode, data) ?: false
override fun onActivityResultBilling(requestCode: Int, resultCode: Int, data: Intent?): Boolean = bp?.handleActivityResult(requestCode, resultCode, data)
?: false
override fun purchasePro() {
val bp = this.bp

View File

@ -34,16 +34,16 @@ class AccountItem(val cookie: CookieModel?) : KauIItem<AccountItem, AccountItem.
text.text = cookie.name
GlideApp.with(itemView).load(PROFILE_PICTURE_URL(cookie.id))
.transform(FrostGlide.roundCorner).listener(object : RequestListener<Drawable> {
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
text.fadeIn()
return false
}
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
text.fadeIn()
return false
}
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
text.fadeIn()
return false
}
}).into(image)
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
text.fadeIn()
return false
}
}).into(image)
} else {
text.visible()
image.setImageDrawable(GoogleMaterial.Icon.gmd_add_circle_outline.toDrawable(itemView.context, 100, Prefs.textColor))

View File

@ -16,7 +16,6 @@ import ca.allanwang.kau.utils.*
import com.devbrackets.android.exomedia.listener.VideoControlsVisibilityListener
import com.mikepenz.google_material_typeface_library.GoogleMaterial
import com.pitchedapps.frost.R
import com.pitchedapps.frost.facebook.formattedFbUrl
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.frostDownload

View File

@ -52,8 +52,7 @@ class Keywords @JvmOverloads constructor(
recycler.layoutManager = LinearLayoutManager(context)
recycler.adapter = adapter
adapter.withEventHook(object : ClickEventHook<KeywordItem>() {
override fun onBind(viewHolder: RecyclerView.ViewHolder): View?
= (viewHolder as? KeywordItem.ViewHolder)?.delete
override fun onBind(viewHolder: RecyclerView.ViewHolder): View? = (viewHolder as? KeywordItem.ViewHolder)?.delete
override fun onClick(v: View, position: Int, fastAdapter: FastAdapter<KeywordItem>, item: KeywordItem) {
adapter.remove(position)

View File

@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Color
import android.support.annotation.WorkerThread
import android.util.AttributeSet
import android.view.View
import android.webkit.WebView
@ -16,8 +17,6 @@ import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.createFreshFile
import com.pitchedapps.frost.utils.iab.IS_FROST_PRO
import com.pitchedapps.frost.utils.isFacebookUrl
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.uiThread
import org.jetbrains.anko.withAlpha
import java.io.File
@ -45,27 +44,22 @@ class DebugWebView @JvmOverloads constructor(
isDrawingCacheEnabled = true
}
fun getScreenshot(output: File, callback: (Boolean) -> Unit) {
@WorkerThread
fun getScreenshot(output: File): Boolean {
if (!output.createFreshFile()) {
L.e { "Failed to create ${output.absolutePath} for debug screenshot" }
return callback(false)
return false
}
doAsync {
var valid = true
try {
output.outputStream().use {
drawingCache.compress(Bitmap.CompressFormat.PNG, 100, it)
}
L.d { "Created screenshot at ${output.absolutePath}" }
} catch (e: Exception) {
L.e { "An error occurred ${e.message}" }
valid = false
} finally {
uiThread {
callback(valid)
}
return try {
output.outputStream().use {
drawingCache.compress(Bitmap.CompressFormat.PNG, 100, it)
}
L.d { "Created screenshot at ${output.absolutePath}" }
true
} catch (e: Exception) {
L.e { "An error occurred ${e.message}" }
false
}
}

View File

@ -46,7 +46,8 @@ class FrostChromeClient(web: FrostWebView) : WebChromeClient() {
}
override fun onShowFileChooser(webView: WebView, filePathCallback: ValueCallback<Array<Uri>?>, fileChooserParams: FileChooserParams): Boolean {
activity?.openFileChooser(filePathCallback, fileChooserParams) ?: webView.frostSnackbar(R.string.file_chooser_not_found)
activity?.openFileChooser(filePathCallback, fileChooserParams)
?: webView.frostSnackbar(R.string.file_chooser_not_found)
return activity != null
}

View File

@ -46,15 +46,12 @@ val WebResourceRequest.isMedia: Boolean
* Generic filter passthrough
* If Resource is already nonnull, pass it, otherwise check if filter is met and override the response accordingly
*/
fun WebResourceResponse?.filter(request: WebResourceRequest, filter: (url: String) -> Boolean)
= filter(request.query { filter(it) })
fun WebResourceResponse?.filter(request: WebResourceRequest, filter: (url: String) -> Boolean) = filter(request.query { filter(it) })
fun WebResourceResponse?.filter(filter: Boolean): WebResourceResponse?
= this ?: if (filter) blankResource else null
fun WebResourceResponse?.filter(filter: Boolean): WebResourceResponse? = this
?: if (filter) blankResource else null
fun WebResourceResponse?.filterCss(request: WebResourceRequest): WebResourceResponse?
= filter(request) { it.endsWith(".css") }
fun WebResourceResponse?.filterCss(request: WebResourceRequest): WebResourceResponse? = filter(request) { it.endsWith(".css") }
fun WebResourceResponse?.filterImage(request: WebResourceRequest): WebResourceResponse?
= filter(request.isImage)
fun WebResourceResponse?.filterImage(request: WebResourceRequest): WebResourceResponse? = filter(request.isImage)

View File

@ -99,15 +99,11 @@ open class NestedWebView @JvmOverloads constructor(
final override fun hasNestedScrollingParent() = childHelper.hasNestedScrollingParent()
final override fun dispatchNestedScroll(dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, offsetInWindow: IntArray?)
= childHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow)
final override fun dispatchNestedScroll(dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, offsetInWindow: IntArray?) = childHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow)
final override fun dispatchNestedPreScroll(dx: Int, dy: Int, consumed: IntArray?, offsetInWindow: IntArray?)
= childHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow)
final override fun dispatchNestedPreScroll(dx: Int, dy: Int, consumed: IntArray?, offsetInWindow: IntArray?) = childHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow)
final override fun dispatchNestedFling(velocityX: Float, velocityY: Float, consumed: Boolean)
= childHelper.dispatchNestedFling(velocityX, velocityY, consumed)
final override fun dispatchNestedFling(velocityX: Float, velocityY: Float, consumed: Boolean) = childHelper.dispatchNestedFling(velocityX, velocityY, consumed)
final override fun dispatchNestedPreFling(velocityX: Float, velocityY: Float)
= childHelper.dispatchNestedPreFling(velocityX, velocityY)
final override fun dispatchNestedPreFling(velocityX: Float, velocityY: Float) = childHelper.dispatchNestedPreFling(velocityX, velocityY)
}

View File

@ -2,6 +2,7 @@
<resources>
<string name="debug_toast_enabled">Debugging section is enabled! Go back to settings.</string>
<string name="debug_toast_already_enabled">Debugging section is already enabled. Go back to settings.</string>
<string name="debug_disclaimer_info">Though most private content is automatically removed in the report, some sensitive info may still be visible.
\nPlease have a look at the debug report before sending it.

View File

@ -6,14 +6,16 @@
<item text="" />
-->
<version title="v1.8.3" />
<item text="Add full notification channel support" />
<item text="Fix sound spam for multiple notifications" />
<item text="" />
<item text="" />
<version title="v1.8.2" />
<item text="Fix duplicate notification sounds" />
<item text="Fix map redirecting to blackberry" />
<item text="Fix event reservation" />
<item text="" />
<item text="" />
<item text="" />
<item text="" />
<version title="v1.8.1" />
<item text="Theme new Facebook update" />

View File

@ -15,7 +15,7 @@ class OfflineWebsiteTest {
fun basic() {
val countdown = CountDownLatch(1)
val buildPath = if (File(".").parentFile?.name == "app") "build/offline_test" else "app/build/offline_test"
OfflineWebsite(FB_URL_BASE, COOKIE, File(buildPath))
OfflineWebsite(FB_URL_BASE, COOKIE, baseDir = File(buildPath))
.loadAndZip("test") {
println("Outcome $it")
countdown.countDown()

View File

@ -0,0 +1,16 @@
package com.pitchedapps.frost.utils
import org.junit.Test
import kotlin.test.assertEquals
/**
* Created by Allan Wang on 11/03/18.
*/
class StringEscapeUtilsTest {
@Test
fun utf() {
val escaped = "\\u003Chead&gt; color=\\\"#3b5998\\\""
assertEquals("<head> color=\"#3b5998\"", escaped.unescapeHtml())
}
}

View File

@ -1,5 +1,9 @@
# Changelog
## v1.8.3
* Add full notification channel support
* Fix sound spam for multiple notifications
## v1.8.2
* Fix duplicate notification sounds
* Fix map redirecting to blackberry