aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin/com/pitchedapps/frost/web
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/web')
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt16
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt13
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWeb.kt87
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt14
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients2.kt196
5 files changed, 305 insertions, 21 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 61a76e70..90345aa2 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt
@@ -34,7 +34,6 @@ import com.pitchedapps.frost.contracts.WebFileChooser
import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.views.FrostWebView
-import kotlinx.coroutines.channels.SendChannel
/**
* Created by Allan Wang on 2017-05-31.
@@ -51,9 +50,10 @@ class FrostChromeClient(
private val webFileChooser: WebFileChooser,
) : WebChromeClient() {
- private val refresh: SendChannel<Boolean> = web.parent.refreshChannel
- private val progress: SendChannel<Int> = web.parent.progressChannel
- private val title: SendChannel<String> = web.parent.titleChannel
+// private val refresh: SendChannel<Boolean> = web.parent.refreshChannel
+ private val refreshEmit = web.parent.refreshEmit
+ private val progressEmit = web.parent.progressEmit
+ private val titleEmit = web.parent.titleEmit
private val context = web.context!!
override fun getDefaultVideoPoster(): Bitmap? =
@@ -68,12 +68,12 @@ class FrostChromeClient(
override fun onReceivedTitle(view: WebView, title: String) {
super.onReceivedTitle(view, title)
if (title.startsWith("http")) return
- this.title.offer(title)
+ titleEmit(title)
}
override fun onProgressChanged(view: WebView, newProgress: Int) {
super.onProgressChanged(view, newProgress)
- progress.offer(newProgress)
+ progressEmit(newProgress)
}
override fun onShowFileChooser(
@@ -87,8 +87,8 @@ class FrostChromeClient(
private fun JsResult.frostCancel() {
cancel()
- refresh.offer(false)
- progress.offer(100)
+ refreshEmit(false)
+ progressEmit(100)
}
override fun onJsAlert(
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 3ead78f4..4d92e8c2 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
@@ -32,24 +32,24 @@ import com.pitchedapps.frost.utils.isIndependent
import com.pitchedapps.frost.utils.launchImageActivity
import com.pitchedapps.frost.utils.showWebContextMenu
import com.pitchedapps.frost.views.FrostWebView
-import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.launch
import javax.inject.Inject
/**
* Created by Allan Wang on 2017-06-01.
*/
+@FrostWebScoped
class FrostJSI @Inject internal constructor(
val web: FrostWebView,
private val activity: Activity,
private val fbCookie: FbCookie,
- private val prefs: Prefs
+ private val prefs: Prefs,
+ @FrostRefresh private val refreshEmit: FrostEmitter<Boolean>
) {
private val mainActivity: MainActivity? = activity as? MainActivity
private val webActivity: WebOverlayActivityBase? = activity as? WebOverlayActivityBase
- private val header: SendChannel<String>? = mainActivity?.headerBadgeChannel
- private val refresh: SendChannel<Boolean> = web.parent.refreshChannel
+ private val headerEmit: FrostEmitter<String>? = mainActivity?.headerEmit
private val cookies: List<CookieEntity> = activity.cookies()
/**
@@ -144,7 +144,8 @@ class FrostJSI @Inject internal constructor(
@JavascriptInterface
fun isReady() {
if (web.frostWebClient !is FrostWebViewClientMenu) {
- refresh.offer(false)
+ L.v { "JSI is ready" }
+ refreshEmit(false)
}
}
@@ -157,7 +158,7 @@ class FrostJSI @Inject internal constructor(
@JavascriptInterface
fun handleHeader(html: String?) {
html ?: return
- header?.offer(html)
+ headerEmit?.invoke(html)
}
@JavascriptInterface
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWeb.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWeb.kt
new file mode 100644
index 00000000..ba05a2c4
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWeb.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2021 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.web
+
+import com.pitchedapps.frost.contracts.FrostContentParent
+import com.pitchedapps.frost.views.FrostWebView
+import dagger.BindsInstance
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.DefineComponent
+import dagger.hilt.EntryPoint
+import dagger.hilt.InstallIn
+import dagger.hilt.android.components.ViewComponent
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharedFlow
+import javax.inject.Qualifier
+import javax.inject.Scope
+
+/**
+ * Defines a new scope for Frost web related content.
+ *
+ * This is a subset of [dagger.hilt.android.scopes.ViewScoped]
+ */
+@Scope
+@Retention(AnnotationRetention.BINARY)
+@Target(
+ AnnotationTarget.FUNCTION,
+ AnnotationTarget.TYPE,
+ AnnotationTarget.CLASS
+)
+annotation class FrostWebScoped
+
+@FrostWebScoped
+@DefineComponent(parent = ViewComponent::class)
+interface FrostWebComponent
+
+@DefineComponent.Builder
+interface FrostWebComponentBuilder {
+ fun frostParent(@BindsInstance parent: FrostContentParent): FrostWebComponentBuilder
+ fun frostWebView(@BindsInstance web: FrostWebView): FrostWebComponentBuilder
+ fun build(): FrostWebComponent
+}
+
+@EntryPoint
+@InstallIn(FrostWebComponent::class)
+interface FrostWebEntryPoint {
+ fun frostJsi(): FrostJSI
+}
+
+fun interface FrostEmitter<T> : (T) -> Unit
+
+fun <T> MutableSharedFlow<T>.asFrostEmitter(): FrostEmitter<T> = FrostEmitter { tryEmit(it) }
+
+@Module
+@InstallIn(FrostWebComponent::class)
+object FrostWebFlowModule {
+ @Provides
+ @FrostWebScoped
+ @FrostRefresh
+ fun refreshFlow(parent: FrostContentParent): SharedFlow<Boolean> = parent.refreshFlow
+
+ @Provides
+ @FrostWebScoped
+ @FrostRefresh
+ fun refreshEmit(parent: FrostContentParent): FrostEmitter<Boolean> = parent.refreshEmit
+}
+
+/**
+ * Observable to get data on whether view is refreshing or not
+ */
+@Qualifier
+@Retention(AnnotationRetention.BINARY)
+annotation class FrostRefresh
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 3b332199..ba19989d 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
@@ -53,7 +53,6 @@ import com.pitchedapps.frost.utils.isMessengerUrl
import com.pitchedapps.frost.utils.launchImageActivity
import com.pitchedapps.frost.utils.startActivityForUri
import com.pitchedapps.frost.views.FrostWebView
-import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.launch
/**
@@ -83,7 +82,7 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
protected val fbCookie: FbCookie get() = web.fbCookie
protected val prefs: Prefs get() = web.prefs
protected val themeProvider: ThemeProvider get() = web.themeProvider
- protected val refresh: SendChannel<Boolean> = web.parent.refreshChannel
+// protected val refresh: SendChannel<Boolean> = web.parent.refreshChannel
protected val isMain = web.parent.baseEnum != null
/**
@@ -156,7 +155,7 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
super.onPageStarted(view, url, favicon)
if (url == null) return
v { "loading $url ${web.settings.userAgentString}" }
- refresh.offer(true)
+// refresh.offer(true)
}
private fun injectBackgroundColor() {
@@ -182,7 +181,7 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
view.messengerJsInject()
}
else -> {
- refresh.offer(false)
+// refresh.offer(false)
}
}
}
@@ -191,7 +190,7 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
url ?: return
v { "finished $url" }
if (!url.isFacebookUrl && !url.isMessengerUrl) {
- refresh.offer(false)
+// refresh.offer(false)
return
}
onPageFinishedActions(url)
@@ -204,9 +203,10 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
injectAndFinish()
}
- internal fun injectAndFinish() {
+ // Temp open
+ internal open fun injectAndFinish() {
v { "page finished reveal" }
- refresh.offer(false)
+// refresh.offer(false)
injectBackgroundColor()
when {
web.url.isFacebookUrl -> {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients2.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients2.kt
new file mode 100644
index 00000000..008b1197
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients2.kt
@@ -0,0 +1,196 @@
+/*
+ * 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.web
+
+import android.graphics.Bitmap
+import android.graphics.Color
+import android.webkit.WebResourceRequest
+import android.webkit.WebView
+import ca.allanwang.kau.utils.withAlpha
+import com.pitchedapps.frost.enums.ThemeCategory
+import com.pitchedapps.frost.injectors.JsActions
+import com.pitchedapps.frost.injectors.JsAssets
+import com.pitchedapps.frost.injectors.jsInject
+import com.pitchedapps.frost.utils.L
+import com.pitchedapps.frost.utils.isFacebookUrl
+import com.pitchedapps.frost.utils.isMessengerUrl
+import com.pitchedapps.frost.utils.launchImageActivity
+import com.pitchedapps.frost.views.FrostWebView
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.EntryPoint
+import dagger.hilt.InstallIn
+import javax.inject.Inject
+import javax.inject.Qualifier
+
+/**
+ * Created by Allan Wang on 2017-05-31.
+ *
+ * Collection of webview clients
+ */
+
+@Qualifier
+@Retention(AnnotationRetention.BINARY)
+annotation class FrostWebClient
+
+@EntryPoint
+@InstallIn(FrostWebComponent::class)
+interface FrostWebClientEntryPoint {
+
+ @FrostWebScoped
+ @FrostWebClient
+ fun webClient(): FrostWebViewClient
+}
+
+@Module
+@InstallIn(FrostWebComponent::class)
+interface FrostWebViewClientModule {
+ @Binds
+ @FrostWebClient
+ fun webClient(binds: FrostWebViewClient2): FrostWebViewClient
+}
+
+/**
+ * The default webview client
+ */
+open class FrostWebViewClient2 @Inject constructor(
+ web: FrostWebView,
+ @FrostRefresh private val refreshEmit: FrostEmitter<Boolean>
+) : FrostWebViewClient(web) {
+
+ init {
+ L.i { "Refresh web client 2" }
+ }
+
+ override fun doUpdateVisitedHistory(view: WebView, url: String?, isReload: Boolean) {
+ super.doUpdateVisitedHistory(view, url, isReload)
+ urlSupportsRefresh = urlSupportsRefresh(url)
+ web.parent.swipeAllowedByPage = urlSupportsRefresh
+ view.jsInject(
+ JsAssets.AUTO_RESIZE_TEXTAREA.maybe(prefs.autoExpandTextBox),
+ prefs = prefs
+ )
+ v { "History $url; refresh $urlSupportsRefresh" }
+ }
+
+ private fun urlSupportsRefresh(url: String?): Boolean {
+ if (url == null) return false
+ if (url.isMessengerUrl) return false
+ if (!url.isFacebookUrl) return true
+ if (url.contains("soft=composer")) return false
+ if (url.contains("sharer.php") || url.contains("sharer-dialog.php")) return false
+ return true
+ }
+
+ private fun WebView.facebookJsInject() {
+ jsInject(*facebookJsInjectors.toTypedArray(), prefs = prefs)
+ }
+
+ private fun WebView.messengerJsInject() {
+ jsInject(
+ themeProvider.injector(ThemeCategory.MESSENGER),
+ prefs = prefs
+ )
+ }
+
+ override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) {
+ super.onPageStarted(view, url, favicon)
+ if (url == null) return
+ v { "loading $url ${web.settings.userAgentString}" }
+ refreshEmit(true)
+ }
+
+ private fun injectBackgroundColor() {
+ web.setBackgroundColor(
+ when {
+ isMain -> Color.TRANSPARENT
+ web.url.isFacebookUrl -> themeProvider.bgColor.withAlpha(255)
+ else -> Color.WHITE
+ }
+ )
+ }
+
+ override fun onPageCommitVisible(view: WebView, url: String?) {
+ super.onPageCommitVisible(view, url)
+ injectBackgroundColor()
+ when {
+ url.isFacebookUrl -> {
+ v { "FB Page commit visible" }
+ view.facebookJsInject()
+ }
+ url.isMessengerUrl -> {
+ v { "Messenger Page commit visible" }
+ view.messengerJsInject()
+ }
+ else -> {
+ refreshEmit(false)
+ }
+ }
+ }
+
+ override fun onPageFinished(view: WebView, url: String?) {
+ url ?: return
+ v { "finished $url" }
+ if (!url.isFacebookUrl && !url.isMessengerUrl) {
+ refreshEmit(false)
+ return
+ }
+ onPageFinishedActions(url)
+ }
+
+ internal override fun injectAndFinish() {
+ v { "page finished reveal" }
+ refreshEmit(false)
+ injectBackgroundColor()
+ when {
+ web.url.isFacebookUrl -> {
+ web.jsInject(
+ JsActions.LOGIN_CHECK,
+ JsAssets.TEXTAREA_LISTENER,
+ JsAssets.HEADER_BADGES.maybe(isMain),
+ prefs = prefs
+ )
+ web.facebookJsInject()
+ }
+ web.url.isMessengerUrl -> {
+ web.messengerJsInject()
+ }
+ }
+ }
+
+ /**
+ * Helper to format the request and launch it
+ * returns true to override the url
+ * returns false if we are already in an overlaying activity
+ */
+ private fun launchRequest(request: WebResourceRequest): Boolean {
+ v { "Launching url: ${request.url}" }
+ return web.requestWebOverlay(request.url.toString())
+ }
+
+ private fun launchImage(url: String, text: String? = null, cookie: String? = null): Boolean {
+ v { "Launching image: $url" }
+ web.context.launchImageActivity(url, text, cookie)
+ if (web.canGoBack()) web.goBack()
+ return true
+ }
+}
+
+private const val EMIT_THEME = 0b1
+private const val EMIT_ID = 0b10
+private const val EMIT_COMPLETE = EMIT_THEME or EMIT_ID
+private const val EMIT_FINISH = 0