aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin/com/pitchedapps/frost/web
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2017-08-14 20:48:39 -0700
committerGitHub <noreply@github.com>2017-08-14 20:48:39 -0700
commit5d9a3fd7fb8f2f9d0f592c89446824980c9841c6 (patch)
treea770b2564b67280fcc9fcc65144bd0b8bd8e2881 /app/src/main/kotlin/com/pitchedapps/frost/web
parentab7ec131b62ac1567e983c846c921bd3ada11dd4 (diff)
downloadfrost-5d9a3fd7fb8f2f9d0f592c89446824980c9841c6.tar.gz
frost-5d9a3fd7fb8f2f9d0f592c89446824980c9841c6.tar.bz2
frost-5d9a3fd7fb8f2f9d0f592c89446824980c9841c6.zip
v1.4.5 (#174)v1.4.5
* Update/kau (#125) * Update logger * Clean imports and bring back reactive libs * Update dependencies and make billing async * Misc (#128) * Update null * Attempt to improve transparent theme backgrounds * Update menu * Move injections to visible method and reduce offset * Update searchview and logging * Clean temp strings and add network states * Move console blacklist to web state * Change some logs to info * Move glide loader to onCreate (#135) * Remove commit number increments (#139) * Fix/misc (#140) * Add canadian locale to toLowerCase * Add try catch to JsAssets * Disable error throwing for bad search subject * Log more throwables quietly * Check internet connection before fetching username * Remove name check in frost notifications * Add activity lifecycle logger * Add rxjava to lib showcase * Move network checker to io thread (#150) * Update dependency * Blank * Feature/jsoup debugger (#152) * Create debugger * Update debugger content * Create debugging logic * Finalize and test debugger * Add reload listener * Fix/pro crash without play store (#155) * Update changelog * Check if iab service exists * Add checker before launching play store request * Separate strings * Enhancement/message notifications (#157) * Map message notifs to the headless html extractor * Update strings * Bring im notifs out of alpha * Update changelog * Remove confirmation dialog (#159) * Separate message notifications and add click intents (#171) * Separate message notifications and add click intent for group notifications * Add comments and finalize * Feature/scroll down on message thread (#172) * Add hook for scroll * Update changelog * Add custom navdrawer layout (#173) * Add faq for auto play * Update changelog * Fix page banner bg (#163)
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/web')
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt12
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt6
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt29
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt6
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt82
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt6
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/HeadlessHtmlExtractor.kt88
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/MessageWebView.kt67
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/SearchWebView.kt33
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/WebStates.kt11
11 files changed, 201 insertions, 141 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt
index 6bc27256..61711092 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt
@@ -34,15 +34,9 @@ class FrostChromeClient(webCore: FrostWebViewCore) : WebChromeClient() {
val activityContract = (webCore.context as? ActivityWebContract)
val context = webCore.context!!
- companion object {
- val consoleBlacklist = setOf(
- "edge-chat"
- )
- }
-
override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean {
if (consoleBlacklist.any { consoleMessage.message().contains(it) }) return true
- L.i("Chrome Console ${consoleMessage.lineNumber()}: ${consoleMessage.message()}")
+ L.d("Chrome Console ${consoleMessage.lineNumber()}: ${consoleMessage.message()}")
return true
}
@@ -63,10 +57,10 @@ class FrostChromeClient(webCore: FrostWebViewCore) : WebChromeClient() {
}
override fun onGeolocationPermissionsShowPrompt(origin: String, callback: GeolocationPermissions.Callback) {
- L.d("Requesting geolocation")
+ L.i("Requesting geolocation")
context.kauRequestPermissions(PERMISSION_ACCESS_FINE_LOCATION) {
granted, _ ->
- L.d("Geolocation response received; ${if (granted) "granted" else "denied"}")
+ L.i("Geolocation response received; ${if (granted) "granted" else "denied"}")
callback(origin, granted, true)
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
index 018ad737..f24a7a51 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
@@ -81,12 +81,14 @@ class FrostJSI(val webView: FrostWebViewCore) {
}
@JavascriptInterface
- fun handleHtml(html: String) {
+ fun handleHtml(html: String?) {
+ html ?: return
webView.post { webView.frostWebClient.handleHtml(html) }
}
@JavascriptInterface
- fun handleHeader(html: String) {
+ fun handleHeader(html: String?) {
+ html ?: return
headerObservable?.onNext(html)
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt
index 3f2891d0..1a907f7f 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt
@@ -5,6 +5,7 @@ import android.webkit.WebResourceResponse
import android.webkit.WebView
import ca.allanwang.kau.utils.use
import com.pitchedapps.frost.utils.L
+import com.pitchedapps.frost.utils.Prefs
import okhttp3.HttpUrl
import java.io.ByteArrayInputStream
@@ -15,17 +16,17 @@ import java.io.ByteArrayInputStream
* Handler to decide when a request should be done by us
* This is the crux of Frost's optimizations for the web browser
*/
-val blankResource: WebResourceResponse by lazy { WebResourceResponse("text/plain", "utf-8", ByteArrayInputStream("".toByteArray())) }
+private val blankResource: WebResourceResponse by lazy { WebResourceResponse("text/plain", "utf-8", ByteArrayInputStream("".toByteArray())) }
//these hosts will redirect to a blank resource
-val blacklistHost: Set<String> by lazy {
+private val blacklistHost: Set<String> by lazy {
setOf(
"edge-chat.facebook.com"
)
}
//these hosts will return null and skip logging
-val whitelistHost: Set<String> by lazy {
+private val whitelistHost: Set<String> by lazy {
setOf(
"static.xx.fbcdn.net",
"m.facebook.com",
@@ -35,13 +36,13 @@ val whitelistHost: Set<String> by lazy {
//these hosts will skip ad inspection
//this list does not have to include anything from the two above
-val adWhitelistHost: Set<String> by lazy {
+private val adWhitelistHost: Set<String> by lazy {
setOf(
"scontent-sea1-1.xx.fbcdn.net"
)
}
-var adblock: Set<String>? = null
+private var adblock: Set<String>? = null
fun shouldFrostInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
val httpUrl = HttpUrl.parse(request.url?.toString() ?: return null) ?: return null
@@ -53,7 +54,8 @@ fun shouldFrostInterceptRequest(view: WebView, request: WebResourceRequest): Web
if (adblock == null) adblock = view.context.assets.open("adblock.txt").bufferedReader().use { it.readLines().toSet() }
if (adblock?.any { url.contains(it) } ?: false) return blankResource
}
- L.v("Intercept Request ${host} ${url}")
+ if (!shouldLoadImages && !Prefs.loadMediaOnMeteredNetwork && request.isMedia) return blankResource
+ L.v("Intercept Request", "$host $url")
return null
}
@@ -64,16 +66,25 @@ fun WebResourceRequest.query(action: (url: String) -> Boolean): Boolean {
return action(url?.path ?: return false)
}
+val WebResourceRequest.isImage: Boolean
+ get() = query { it.contains(".jpg") || it.contains(".png") }
+
+val WebResourceRequest.isMedia: Boolean
+ get() = query { it.contains(".jpg") || it.contains(".png") || it.contains("video") }
+
/**
* 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): WebResourceResponse?
- = this ?: if (request.query { filter(it) }) blankResource else null
+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?.filterCss(request: WebResourceRequest): WebResourceResponse?
= filter(request) { it.endsWith(".css") }
fun WebResourceResponse?.filterImage(request: WebResourceRequest): WebResourceResponse?
- = filter(request) { it.contains(".jpg") || it.contains(".png") }
+ = filter(request.isImage)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt
index 79ca1fdf..89ad766d 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt
@@ -11,7 +11,7 @@ import android.widget.FrameLayout
import android.widget.ProgressBar
import ca.allanwang.kau.utils.*
import com.pitchedapps.frost.R
-import com.pitchedapps.frost.facebook.FbTab
+import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.facebook.USER_AGENT_BASIC
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.frostDownload
@@ -53,7 +53,7 @@ class FrostWebView @JvmOverloads constructor(
}
@SuppressLint("SetJavaScriptEnabled")
- fun setupWebview(url: String, enum: FbTab? = null) {
+ fun setupWebview(url: String, enum: FbItem? = null) {
with(web) {
baseUrl = url
baseEnum = enum
@@ -77,7 +77,7 @@ class FrostWebView @JvmOverloads constructor(
//Some urls have postJavascript injections so make sure we load the base url
override fun onRefresh() {
when (web.baseUrl) {
- FbTab.MENU.url -> web.loadBaseUrl(true)
+ FbItem.MENU.url -> web.loadBaseUrl(true)
else -> web.reload(true)
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
index 94bff3c3..5f679c65 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
@@ -1,8 +1,8 @@
package com.pitchedapps.frost.web
import android.content.Context
-import android.content.Intent
import android.graphics.Bitmap
+import android.graphics.Color
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
@@ -14,10 +14,12 @@ import com.pitchedapps.frost.activities.WebOverlayActivity
import com.pitchedapps.frost.facebook.FACEBOOK_COM
import com.pitchedapps.frost.facebook.FB_URL_BASE
import com.pitchedapps.frost.facebook.FbCookie
+import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.injectors.*
import com.pitchedapps.frost.utils.*
import com.pitchedapps.frost.utils.iab.IS_FROST_PRO
import io.reactivex.subjects.Subject
+import org.jetbrains.anko.withAlpha
/**
* Created by Allan Wang on 2017-05-31.
@@ -42,18 +44,19 @@ open class BaseWebViewClient : WebViewClient() {
open class FrostWebViewClient(val webCore: FrostWebViewCore) : BaseWebViewClient() {
val refreshObservable: Subject<Boolean> = webCore.refreshObservable
+ val isMain = webCore.baseEnum != null
override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
if (url == null) return
- L.i("FWV Loading $url")
-// L.v("Cookies ${CookieManager.getInstance().getCookie(url)}")
+ L.i("FWV Loading", url)
refreshObservable.onNext(true)
if (!url.contains(FACEBOOK_COM)) return
if (url.contains("logout.php")) FbCookie.logout(Prefs.userId, { launchLogin(view.context) })
else if (url.contains("login.php")) FbCookie.reset({ launchLogin(view.context) })
}
+
fun launchLogin(c: Context) {
if (c is MainActivity && c.cookies().isNotEmpty())
c.launchNewTask(SelectorActivity::class.java, c.cookies())
@@ -61,44 +64,52 @@ open class FrostWebViewClient(val webCore: FrostWebViewCore) : BaseWebViewClient
c.launchNewTask(LoginActivity::class.java)
}
+ fun injectBackgroundColor()
+ = webCore.setBackgroundColor(if (isMain) Color.TRANSPARENT else Prefs.bgColor.withAlpha(255))
+
+
+ override fun onPageCommitVisible(view: WebView, url: String?) {
+ super.onPageCommitVisible(view, url)
+ injectBackgroundColor()
+ view.jsInject(
+ CssAssets.ROUND_ICONS.maybe(Prefs.showRoundedIcons),
+ CssHider.HEADER,
+ CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!Prefs.showSuggestedFriends && IS_FROST_PRO),
+ Prefs.themeInjector,
+ CssHider.NON_RECENT.maybe(webCore.url?.contains("?sk=h_chr") ?: false))
+ }
+
override fun onPageFinished(view: WebView, url: String?) {
- super.onPageFinished(view, url)
- if (url == null) return
- L.i("Page finished $url")
+ url ?: return
+ L.i("Page finished", url)
if (!url.contains(FACEBOOK_COM)) {
refreshObservable.onNext(false)
return
}
- view.jsInject(
- CssAssets.ROUND_ICONS.maybe(Prefs.showRoundedIcons),
- CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!Prefs.showSuggestedFriends && IS_FROST_PRO),
- CssHider.ADS.maybe(!Prefs.showFacebookAds && IS_FROST_PRO)
- )
onPageFinishedActions(url)
}
open internal fun onPageFinishedActions(url: String) {
+ if (url.startsWith("${FbItem.MESSAGES.url}/read/") && Prefs.messageScrollToBottom)
+ webCore.pageDown(true)
injectAndFinish()
}
internal fun injectAndFinish() {
L.d("Page finished reveal")
- webCore.jsInject(CssHider.HEADER,
- CssHider.NON_RECENT.maybe(webCore.url.contains("?sk=h_chr")),
- Prefs.themeInjector,
- callback = {
- refreshObservable.onNext(false)
- webCore.jsInject(
- JsActions.LOGIN_CHECK,
- JsAssets.CLICK_A.maybe(webCore.baseEnum != null && Prefs.overlayEnabled),
- JsAssets.TEXTAREA_LISTENER,
- JsAssets.CONTEXT_A,
- JsAssets.HEADER_BADGES.maybe(webCore.baseEnum != null)
- )
- })
- }
-
- open fun handleHtml(html: String) {
+ refreshObservable.onNext(false)
+ injectBackgroundColor()
+ webCore.jsInject(
+ JsActions.LOGIN_CHECK,
+ JsAssets.CLICK_A.maybe(webCore.baseEnum != null && Prefs.overlayEnabled),
+ JsAssets.TEXTAREA_LISTENER,
+ CssHider.ADS.maybe(!Prefs.showFacebookAds && IS_FROST_PRO),
+ JsAssets.CONTEXT_A,
+ JsAssets.HEADER_BADGES.maybe(webCore.baseEnum != null)
+ )
+ }
+
+ open fun handleHtml(html: String?) {
L.d("Handle Html")
}
@@ -112,26 +123,26 @@ open class FrostWebViewClient(val webCore: FrostWebViewCore) : BaseWebViewClient
* returns false if we are already in an overlaying activity
*/
private fun launchRequest(request: WebResourceRequest): Boolean {
- L.d("Launching Url", request.url.toString())
+ L.d("Launching Url", request.url?.toString() ?: "null")
if (webCore.context is WebOverlayActivity) return false
webCore.context.launchWebOverlay(request.url.toString())
return true
}
- private fun launchImage(request: WebResourceRequest, text: String? = null): Boolean {
- L.d("Launching Image", request.url.toString())
- webCore.context.launchImageActivity(request.url.toString(), text)
+ private fun launchImage(url: String, text: String? = null): Boolean {
+ L.d("Launching Image", url)
+ webCore.context.launchImageActivity(url, text)
if (webCore.canGoBack()) webCore.goBack()
return true
}
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
- L.i("Url Loading ${request.url}")
- val path = request.url.path ?: return super.shouldOverrideUrlLoading(view, request)
- L.v("Url Loading Path $path")
+ L.i("Url Loading", request.url?.toString())
+ val path = request.url?.path ?: return super.shouldOverrideUrlLoading(view, request)
+ L.v("Url Loading Path", path)
if (path.startsWith("/composer/")) return launchRequest(request)
if (request.url.toString().contains("scontent-sea1-1.xx.fbcdn.net") && (path.endsWith(".jpg") || path.endsWith(".png")))
- return launchImage(request)
+ return launchImage(request.url.toString())
if (view.context.resolveActivityForUri(request.url)) return true
return super.shouldOverrideUrlLoading(view, request)
}
@@ -163,6 +174,7 @@ class FrostWebViewClientMenu(webCore: FrostWebViewCore) : FrostWebViewClient(web
}
override fun onPageFinishedActions(url: String) {
+ L.d("Should inject ${url.shouldInjectMenu}")
if (!url.shouldInjectMenu) injectAndFinish()
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt
index d8edc15c..6dbc7c8d 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt
@@ -14,7 +14,7 @@ import ca.allanwang.kau.utils.circularReveal
import ca.allanwang.kau.utils.fadeIn
import ca.allanwang.kau.utils.fadeOut
import ca.allanwang.kau.utils.isVisible
-import com.pitchedapps.frost.facebook.FbTab
+import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.utils.Prefs
import io.reactivex.Scheduler
import io.reactivex.android.schedulers.AndroidSchedulers
@@ -41,7 +41,7 @@ class FrostWebViewCore @JvmOverloads constructor(
var baseUrl: String? = null
- var baseEnum: FbTab? = null //only viewpager items should pass the base enum
+ var baseEnum: FbItem? = null //only viewpager items should pass the base enum
internal lateinit var frostWebClient: FrostWebViewClient
init {
@@ -76,7 +76,7 @@ class FrostWebViewCore @JvmOverloads constructor(
if (isVisible) fadeOut(duration = 200L)
} else if (loading) {
dispose?.dispose()
- if (animate && Prefs.animate) circularReveal(offset = 150L)
+ if (animate && Prefs.animate) circularReveal(offset = WEB_LOAD_DELAY)
else fadeIn(duration = 100L)
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/HeadlessHtmlExtractor.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/HeadlessHtmlExtractor.kt
new file mode 100644
index 00000000..50f2f6bc
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/HeadlessHtmlExtractor.kt
@@ -0,0 +1,88 @@
+package com.pitchedapps.frost.web
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.webkit.JavascriptInterface
+import android.webkit.WebView
+import ca.allanwang.kau.utils.gone
+import com.pitchedapps.frost.R
+import com.pitchedapps.frost.facebook.USER_AGENT_BASIC
+import com.pitchedapps.frost.injectors.InjectorContract
+import com.pitchedapps.frost.utils.L
+import io.reactivex.Single
+import io.reactivex.SingleEmitter
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import org.jetbrains.anko.runOnUiThread
+import java.util.concurrent.TimeUnit
+
+/**
+ * Created by Allan Wang on 2017-08-12.
+ *
+ * Launches a headless html request and returns a result pair
+ * When successful, the pair will contain the html content and -1
+ * When unsuccessful, the pair will contain an empty string and a StringRes for the given error
+ *
+ * All errors are rerouted to success calls, so no exceptions should occur.
+ * The headless extractor will also destroy itself on cancellation or when the request is finished
+ */
+fun Context.launchHeadlessHtmlExtractor(url: String, injector: InjectorContract, action: (Single<Pair<String, Int>>) -> Unit) {
+ val single = Single.create<Pair<String, Int>> { e: SingleEmitter<Pair<String, Int>> ->
+ val extractor = HeadlessHtmlExtractor(this, url, injector, e)
+ e.setCancellable {
+ runOnUiThread { extractor.destroy() }
+ e.onSuccess("" to R.string.html_extraction_cancelled)
+ }
+ }.subscribeOn(AndroidSchedulers.mainThread())
+ .timeout(20, TimeUnit.SECONDS, Schedulers.io(), { it.onSuccess("" to R.string.html_extraction_timeout) })
+ .onErrorReturn { "" to R.string.html_extraction_error }
+ action(single)
+}
+
+/**
+ * Given a link and some javascript, will load the link and load the JS on completion
+ * The JS is expected to call [HeadlessHtmlExtractor.HtmlJSI.handleHtml], which will be sent
+ * to the [emitter]
+ */
+@SuppressLint("ViewConstructor")
+private class HeadlessHtmlExtractor(
+ context: Context, url: String, val injector: InjectorContract, val emitter: SingleEmitter<Pair<String, Int>>
+) : WebView(context) {
+
+ val startTime = System.currentTimeMillis()
+
+ init {
+ L.v("Created HeadlessHtmlExtractor for $url")
+ gone()
+ setupWebview(url)
+ }
+
+ @SuppressLint("SetJavaScriptEnabled")
+ private fun setupWebview(url: String) {
+ settings.javaScriptEnabled = true
+ settings.userAgentString = USER_AGENT_BASIC
+ webViewClient = HeadlessWebViewClient(url, injector) // basic client that loads our JS once the page has loaded
+ webChromeClient = QuietChromeClient() // basic client that disables logging
+ addJavascriptInterface(HtmlJSI(), "Frost")
+ loadUrl(url)
+ }
+
+ inner class HtmlJSI {
+ @JavascriptInterface
+ fun handleHtml(html: String?) {
+ val time = System.currentTimeMillis() - startTime
+ emitter.onSuccess((html ?: "") to -1)
+ post {
+ L.d("HeadlessHtmlExtractor fetched $url in $time ms")
+ settings.javaScriptEnabled = false
+ settings.blockNetworkLoads = true
+ destroy()
+ }
+ }
+ }
+
+ override fun destroy() {
+ super.destroy()
+ L.d("HeadlessHtmlExtractor destroyed")
+ }
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt
index 31be4450..aea25337 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt
@@ -60,7 +60,7 @@ class LoginWebView @JvmOverloads constructor(
view.jsInject(CssHider.HEADER.maybe(containsFacebook),
CssHider.CORE.maybe(containsFacebook),
Prefs.themeInjector.maybe(containsFacebook),
- callback = { if (!view.isVisible) view.fadeIn(offset = 150L) })
+ callback = { if (!view.isVisible) view.fadeIn(offset = WEB_LOAD_DELAY) })
}
fun checkForLogin(url: String?, onFound: (id: Long, cookie: String) -> Unit) {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/MessageWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/MessageWebView.kt
deleted file mode 100644
index 53fa0657..00000000
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/MessageWebView.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.pitchedapps.frost.web
-
-import android.annotation.SuppressLint
-import android.app.job.JobParameters
-import android.webkit.JavascriptInterface
-import android.webkit.WebView
-import ca.allanwang.kau.utils.gone
-import com.pitchedapps.frost.dbflow.CookieModel
-import com.pitchedapps.frost.facebook.FbTab
-import com.pitchedapps.frost.facebook.USER_AGENT_BASIC
-import com.pitchedapps.frost.injectors.JsAssets
-import com.pitchedapps.frost.services.NotificationService
-import com.pitchedapps.frost.utils.L
-import com.pitchedapps.frost.utils.frostAnswersCustom
-import org.jetbrains.anko.doAsync
-
-/**
- * Created by Allan Wang on 2017-07-17.
- *
- * Bare boned headless view made solely to extract conversation info
- */
-@SuppressLint("ViewConstructor")
-class MessageWebView(val service: NotificationService, val params: JobParameters?, val cookie: CookieModel) : WebView(service) {
-
- private val startTime = System.currentTimeMillis()
- private var isCancelled = false
-
- init {
- gone()
- setupWebview()
- }
-
- @SuppressLint("SetJavaScriptEnabled")
- private fun setupWebview() {
- settings.javaScriptEnabled = true
- settings.userAgentString = USER_AGENT_BASIC
- webViewClient = HeadlessWebViewClient("MessageNotifs", JsAssets.NOTIF_MSG)
- webChromeClient = QuietChromeClient()
- addJavascriptInterface(MessageJSI(), "Frost")
- loadUrl(FbTab.MESSAGES.url)
- }
-
- fun finish() {
- if (isCancelled) return
- isCancelled = true
- post { destroy() }
- service.finish(params)
- }
-
- override fun destroy() {
- L.d("MessageWebView destroyed")
- super.destroy()
- }
-
- inner class MessageJSI {
- @JavascriptInterface
- fun handleHtml(html: String) {
- if (isCancelled) return
- if (html.length < 10) return finish()
- val time = System.currentTimeMillis() - startTime
- L.d("Notif messages fetched in $time ms")
- frostAnswersCustom("NotificationTime", "Type" to "IM Headless", "Duration" to time)
- doAsync { service.fetchMessageNotifications(cookie, html); finish() }
- }
- }
-
-} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/SearchWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/SearchWebView.kt
index 05d56f92..da6d8ad3 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/SearchWebView.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/SearchWebView.kt
@@ -6,7 +6,7 @@ import android.webkit.JavascriptInterface
import android.webkit.WebView
import ca.allanwang.kau.searchview.SearchItem
import ca.allanwang.kau.utils.gone
-import com.pitchedapps.frost.facebook.FbTab
+import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.facebook.USER_AGENT_BASIC
import com.pitchedapps.frost.injectors.JsAssets
import com.pitchedapps.frost.injectors.JsBuilder
@@ -27,7 +27,7 @@ import java.util.concurrent.TimeUnit
*/
class SearchWebView(context: Context, val contract: SearchContract) : WebView(context) {
- val searchSubject = PublishSubject.create<String>()
+ val searchSubject = PublishSubject.create<String>()!!
init {
gone()
@@ -39,11 +39,11 @@ class SearchWebView(context: Context, val contract: SearchContract) : WebView(co
* Contains the last item's href (search more) as well as the number of items found
* This holder is synchronized
*/
- var previousResult: Pair<String?, Int> = Pair(null, 0)
+ var previousResult: Pair<String, Int> = Pair("", 0)
fun saveResultFrame(result: List<Pair<List<String>, String>>) {
synchronized(previousResult) {
- previousResult = Pair(result.lastOrNull()?.second, result.size)
+ previousResult = Pair(result.last().second, result.size)
}
}
@@ -56,17 +56,22 @@ class SearchWebView(context: Context, val contract: SearchContract) : WebView(co
addJavascriptInterface(SearchJSI(), "Frost")
searchSubject.debounce(300, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.newThread())
.map {
- Jsoup.parse(it).select("a:not([rel*='keywords(']):not([href=#])[rel]").map {
+ val doc = Jsoup.parse(it)
+ L.d(doc.getElementById("main-search_input")?.html())
+ val searchQuery = doc.getElementById("main-search-input")?.text() ?: "Null input"
+ L.d("Search query", searchQuery)
+ doc.select("a:not([rel*='keywords(']):not([href=#])[rel]").map {
element ->
//split text into separate items
- L.v("Search element ${element.attr("href")}")
- val texts = element.select("div").map { (it.text()) }.filter { it.isNotBlank() }
+ L.v("Search element", element.attr("href"))
+ val texts = element.select("div").map { it.text() }.filter { !it.isNullOrBlank() }
val pair = Pair(texts, element.attr("href"))
- L.v("Search element potential $pair")
+ L.v("Search element potential", pair.toString())
pair
}.filter { it.first.isNotEmpty() }
}
- .filter { content -> Pair(content.lastOrNull()?.second, content.size) != previousResult }
+ .filter { it.isNotEmpty() }
+ .filter { Pair(it.last().second, it.size) != previousResult }
.subscribe {
content: List<Pair<List<String>, String>> ->
saveResultFrame(content)
@@ -90,7 +95,7 @@ class SearchWebView(context: Context, val contract: SearchContract) : WebView(co
}
override fun reload() {
- super.loadUrl(FbTab.SEARCH.url)
+ super.loadUrl(FbItem.SEARCH.url)
}
/**
@@ -104,7 +109,8 @@ class SearchWebView(context: Context, val contract: SearchContract) : WebView(co
inner class SearchJSI {
@JavascriptInterface
- fun handleHtml(html: String) {
+ fun handleHtml(html: String?) {
+ html ?: return
L.d("Search received response ${contract.isSearchOpened}")
if (!contract.isSearchOpened) pauseLoad = true
searchSubject.onNext(html)
@@ -117,11 +123,14 @@ class SearchWebView(context: Context, val contract: SearchContract) : WebView(co
L.d("Search loaded successfully")
}
1 -> { //something is not found in the search view; this is effectively useless
- L.eThrow("Search subject error; reverting to full overlay")
+ L.e("Search subject error; reverting to full overlay")
Prefs.searchBar = false
searchSubject.onComplete()
contract.searchOverlayDispose()
}
+ 2 -> {
+ L.v("Search emission received")
+ }
}
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/WebStates.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/WebStates.kt
new file mode 100644
index 00000000..ad1fe467
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/WebStates.kt
@@ -0,0 +1,11 @@
+package com.pitchedapps.frost.web
+
+/**
+ * Created by Allan Wang on 2017-08-08.
+ *
+ * Global variables that are define states or constants for web contents
+ */
+const val WEB_LOAD_DELAY = 50L
+var shouldLoadImages = false
+
+val consoleBlacklist = setOf("edge-chat") \ No newline at end of file