1
0
mirror of https://github.com/AllanWang/Frost-for-Facebook.git synced 2024-11-09 12:32:30 +01:00

Merge pull request #1817 from AllanWang/hilt

This commit is contained in:
Allan Wang 2021-09-25 17:34:25 -07:00 committed by GitHub
commit eb9fc5c6a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 136 additions and 92 deletions

View File

@ -24,14 +24,11 @@ import android.content.res.ColorStateList
import android.graphics.PointF
import android.graphics.drawable.Drawable
import android.graphics.drawable.RippleDrawable
import android.net.Uri
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.webkit.ValueCallback
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.widget.FrameLayout
import android.widget.ImageView
@ -79,10 +76,9 @@ import com.mikepenz.iconics.typeface.IIcon
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.R
import com.pitchedapps.frost.contracts.FileChooserContract
import com.pitchedapps.frost.contracts.FileChooserDelegate
import com.pitchedapps.frost.contracts.MainActivityContract
import com.pitchedapps.frost.contracts.VideoViewHolder
import com.pitchedapps.frost.contracts.WebFileChooser
import com.pitchedapps.frost.databinding.ActivityMainBinding
import com.pitchedapps.frost.databinding.ActivityMainBottomTabsBinding
import com.pitchedapps.frost.databinding.ActivityMainDrawerWrapperBinding
@ -149,7 +145,6 @@ import kotlin.math.abs
abstract class BaseMainActivity :
BaseActivity(),
MainActivityContract,
FileChooserContract by FileChooserDelegate(),
VideoViewHolder,
SearchViewHolder {
@ -167,6 +162,9 @@ abstract class BaseMainActivity :
@Inject
lateinit var genericDao: GenericDao
@Inject
lateinit var webFileChooser: WebFileChooser
interface ActivityMainContentBinding {
val root: View
val toolbar: Toolbar
@ -715,16 +713,9 @@ abstract class BaseMainActivity :
return true
}
override fun openFileChooser(
filePathCallback: ValueCallback<Array<Uri>?>,
fileChooserParams: WebChromeClient.FileChooserParams
) {
openMediaPicker(filePathCallback, fileChooserParams)
}
@SuppressLint("NewApi")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (onActivityResultWeb(requestCode, resultCode, data)) return
if (webFileChooser.onActivityResultWeb(requestCode, resultCode, data)) return
super.onActivityResult(requestCode, resultCode, data)
fun hasRequest(flag: Int) = resultCode and flag > 0

View File

@ -18,12 +18,9 @@ package com.pitchedapps.frost.activities
import android.content.Intent
import android.graphics.PointF
import android.net.Uri
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.webkit.ValueCallback
import android.webkit.WebChromeClient
import android.widget.FrameLayout
import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout
@ -49,11 +46,9 @@ import ca.allanwang.kau.utils.withMainContext
import com.google.android.material.snackbar.BaseTransientBottomBar
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.pitchedapps.frost.R
import com.pitchedapps.frost.contracts.ActivityContract
import com.pitchedapps.frost.contracts.FileChooserContract
import com.pitchedapps.frost.contracts.FileChooserDelegate
import com.pitchedapps.frost.contracts.FrostContentContainer
import com.pitchedapps.frost.contracts.VideoViewHolder
import com.pitchedapps.frost.contracts.WebFileChooser
import com.pitchedapps.frost.enums.OverlayContext
import com.pitchedapps.frost.facebook.FB_URL_BASE
import com.pitchedapps.frost.facebook.FbItem
@ -70,10 +65,12 @@ import com.pitchedapps.frost.utils.frostSnackbar
import com.pitchedapps.frost.views.FrostContentWeb
import com.pitchedapps.frost.views.FrostVideoViewer
import com.pitchedapps.frost.views.FrostWebView
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import javax.inject.Inject
/**
* Created by Allan Wang on 2017-06-01.
@ -155,12 +152,11 @@ class WebOverlayDesktopActivity : WebOverlayActivityBase(USER_AGENT_DESKTOP_CONS
class WebOverlayActivity : WebOverlayActivityBase()
@UseExperimental(ExperimentalCoroutinesApi::class)
@AndroidEntryPoint
abstract class WebOverlayActivityBase(private val userAgent: String = USER_AGENT) :
BaseActivity(),
ActivityContract,
FrostContentContainer,
VideoViewHolder,
FileChooserContract by FileChooserDelegate() {
VideoViewHolder {
override val frameWrapper: FrameLayout by bindView(R.id.frame_wrapper)
val toolbar: Toolbar by bindView(R.id.overlay_toolbar)
@ -169,6 +165,9 @@ abstract class WebOverlayActivityBase(private val userAgent: String = USER_AGENT
get() = content.coreView
private val coordinator: CoordinatorLayout by bindView(R.id.overlay_main_content)
@Inject
lateinit var webFileChooser: WebFileChooser
private inline val urlTest: String?
get() = intent.getStringExtra(ARG_URL) ?: intent.dataString
@ -297,15 +296,8 @@ abstract class WebOverlayActivityBase(private val userAgent: String = USER_AGENT
kauSwipeOnDestroy()
}
override fun openFileChooser(
filePathCallback: ValueCallback<Array<Uri>?>,
fileChooserParams: WebChromeClient.FileChooserParams
) {
openMediaPicker(filePathCallback, fileChooserParams)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (onActivityResultWeb(requestCode, resultCode, data)) return
if (webFileChooser.onActivityResultWeb(requestCode, resultCode, data)) return
super.onActivityResult(requestCode, resultCode, data)
}

View File

@ -17,18 +17,12 @@
package com.pitchedapps.frost.contracts
import com.mikepenz.iconics.typeface.IIcon
import com.pitchedapps.frost.activities.MainActivity
import com.pitchedapps.frost.fragments.BaseFragment
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.BroadcastChannel
/**
* All the contracts for [MainActivity]
*/
interface ActivityContract : FileChooserActivityContract
@UseExperimental(ExperimentalCoroutinesApi::class)
interface MainActivityContract : ActivityContract, MainFabContract {
interface MainActivityContract : MainFabContract {
val fragmentChannel: BroadcastChannel<Int>
val headerBadgeChannel: BroadcastChannel<String>
fun setTitle(res: Int)

View File

@ -25,55 +25,63 @@ import ca.allanwang.kau.permissions.PERMISSION_WRITE_EXTERNAL_STORAGE
import ca.allanwang.kau.permissions.kauRequestPermissions
import ca.allanwang.kau.utils.string
import com.pitchedapps.frost.R
import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.frostSnackbar
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
import dagger.hilt.android.scopes.ActivityScoped
import javax.inject.Inject
/**
* Created by Allan Wang on 2017-07-04.
*/
const val MEDIA_CHOOSER_RESULT = 67
private const val MEDIA_CHOOSER_RESULT = 67
interface FileChooserActivityContract {
fun openFileChooser(
filePathCallback: ValueCallback<Array<Uri>?>,
fileChooserParams: WebChromeClient.FileChooserParams
)
}
interface FileChooserContract {
var filePathCallback: ValueCallback<Array<Uri>?>?
fun Activity.openMediaPicker(
interface WebFileChooser {
fun openMediaPicker(
filePathCallback: ValueCallback<Array<Uri>?>,
fileChooserParams: WebChromeClient.FileChooserParams
)
fun Activity.onActivityResultWeb(requestCode: Int, resultCode: Int, intent: Intent?): Boolean
fun onActivityResultWeb(
requestCode: Int,
resultCode: Int,
intent: Intent?
): Boolean
}
class FileChooserDelegate : FileChooserContract {
class WebFileChooserImpl @Inject internal constructor(
private val activity: Activity,
private val themeProvider: ThemeProvider
) : WebFileChooser {
private var filePathCallback: ValueCallback<Array<Uri>?>? = null
override var filePathCallback: ValueCallback<Array<Uri>?>? = null
override fun Activity.openMediaPicker(
override fun openMediaPicker(
filePathCallback: ValueCallback<Array<Uri>?>,
fileChooserParams: WebChromeClient.FileChooserParams
) {
kauRequestPermissions(PERMISSION_WRITE_EXTERNAL_STORAGE) { granted, _ ->
activity.kauRequestPermissions(PERMISSION_WRITE_EXTERNAL_STORAGE) { granted, _ ->
if (!granted) {
L.d { "Failed to get write permissions" }
activity.frostSnackbar(R.string.file_chooser_not_found, themeProvider)
filePathCallback.onReceiveValue(null)
return@kauRequestPermissions
}
this@FileChooserDelegate.filePathCallback = filePathCallback
this.filePathCallback = filePathCallback
val intent = Intent()
intent.type = fileChooserParams.acceptTypes.firstOrNull()
intent.action = Intent.ACTION_GET_CONTENT
startActivityForResult(
Intent.createChooser(intent, string(R.string.pick_image)),
activity.startActivityForResult(
Intent.createChooser(intent, activity.string(R.string.pick_image)),
MEDIA_CHOOSER_RESULT
)
}
}
override fun Activity.onActivityResultWeb(
override fun onActivityResultWeb(
requestCode: Int,
resultCode: Int,
intent: Intent?
@ -86,3 +94,11 @@ class FileChooserDelegate : FileChooserContract {
return true
}
}
@Module
@InstallIn(ActivityComponent::class)
interface WebFileChooserModule {
@Binds
@ActivityScoped
fun webFileChooser(to: WebFileChooserImpl): WebFileChooser
}

View File

@ -18,6 +18,7 @@ package com.pitchedapps.frost.views
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
@ -29,6 +30,7 @@ import ca.allanwang.kau.utils.launchMain
import com.pitchedapps.frost.contracts.FrostContentContainer
import com.pitchedapps.frost.contracts.FrostContentCore
import com.pitchedapps.frost.contracts.FrostContentParent
import com.pitchedapps.frost.contracts.WebFileChooser
import com.pitchedapps.frost.db.CookieDao
import com.pitchedapps.frost.db.currentCookie
import com.pitchedapps.frost.facebook.FB_HOME_URL
@ -43,8 +45,15 @@ import com.pitchedapps.frost.web.FrostChromeClient
import com.pitchedapps.frost.web.FrostJSI
import com.pitchedapps.frost.web.FrostWebViewClient
import com.pitchedapps.frost.web.NestedWebView
import dagger.BindsInstance
import dagger.hilt.DefineComponent
import dagger.hilt.EntryPoint
import dagger.hilt.EntryPoints
import dagger.hilt.InstallIn
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.components.ViewComponent
import javax.inject.Inject
import javax.inject.Scope
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
@ -60,6 +69,9 @@ class FrostWebView @JvmOverloads constructor(
defStyleAttr: Int = 0
) : NestedWebView(context, attrs, defStyleAttr), FrostContentCore {
@Inject
lateinit var activity: Activity
@Inject
lateinit var fbCookie: FbCookie
@ -69,9 +81,15 @@ class FrostWebView @JvmOverloads constructor(
@Inject
lateinit var themeProvider: ThemeProvider
@Inject
lateinit var webFileChooser: WebFileChooser
@Inject
lateinit var cookieDao: CookieDao
@Inject
lateinit var frostWebComponentBuilder: FrostWebComponentBuilder
override fun reload(animate: Boolean) {
if (parent.registerTransition(false, animate))
super.reload()
@ -86,6 +104,8 @@ class FrostWebView @JvmOverloads constructor(
@SuppressLint("SetJavaScriptEnabled")
override fun bind(container: FrostContentContainer): View {
val component = frostWebComponentBuilder.frostWebView(this).build()
val entryPoint = EntryPoints.get(component, FrostWebEntryPoint::class.java)
userAgentString = USER_AGENT
with(settings) {
javaScriptEnabled = true
@ -98,8 +118,8 @@ class FrostWebView @JvmOverloads constructor(
// attempt to get custom client; otherwise fallback to original
frostWebClient = (container as? WebFragment)?.client(this) ?: FrostWebViewClient(this)
webViewClient = frostWebClient
webChromeClient = FrostChromeClient(this, themeProvider)
addJavascriptInterface(FrostJSI(this), "Frost")
webChromeClient = FrostChromeClient(this, themeProvider, webFileChooser)
addJavascriptInterface(entryPoint.frostJsi(), "Frost")
setBackgroundColor(Color.TRANSPARENT)
setDownloadListener { url, userAgent, contentDisposition, mimetype, contentLength ->
context.ctxCoroutine.launchMain {
@ -231,3 +251,29 @@ class FrostWebView @JvmOverloads constructor(
super.destroy()
}
}
@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 frostWebView(@BindsInstance web: FrostWebView): FrostWebComponentBuilder
fun build(): FrostWebComponent
}
@EntryPoint
@InstallIn(FrostWebComponent::class)
interface FrostWebEntryPoint {
@FrostWebScoped
fun frostJsi(): FrostJSI
}

View File

@ -30,11 +30,9 @@ import ca.allanwang.kau.permissions.kauRequestPermissions
import ca.allanwang.kau.utils.materialDialog
import com.afollestad.materialdialogs.callbacks.onDismiss
import com.afollestad.materialdialogs.input.input
import com.pitchedapps.frost.R
import com.pitchedapps.frost.contracts.ActivityContract
import com.pitchedapps.frost.contracts.WebFileChooser
import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.frostSnackbar
import com.pitchedapps.frost.views.FrostWebView
import kotlinx.coroutines.channels.SendChannel
@ -49,13 +47,13 @@ import kotlinx.coroutines.channels.SendChannel
*/
class FrostChromeClient(
web: FrostWebView,
private val themeProvider: ThemeProvider
private val themeProvider: ThemeProvider,
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 activity = (web.context as? ActivityContract)
private val context = web.context!!
override fun getDefaultVideoPoster(): Bitmap? =
@ -83,9 +81,8 @@ class FrostChromeClient(
filePathCallback: ValueCallback<Array<Uri>?>,
fileChooserParams: FileChooserParams
): Boolean {
activity?.openFileChooser(filePathCallback, fileChooserParams)
?: webView.frostSnackbar(R.string.file_chooser_not_found, themeProvider)
return activity != null
webFileChooser.openMediaPicker(filePathCallback, fileChooserParams)
return true
}
private fun JsResult.frostCancel() {

View File

@ -16,12 +16,11 @@
*/
package com.pitchedapps.frost.web
import android.content.Context
import android.app.Activity
import android.webkit.JavascriptInterface
import ca.allanwang.kau.utils.ctxCoroutine
import com.pitchedapps.frost.activities.MainActivity
import com.pitchedapps.frost.activities.WebOverlayActivityBase
import com.pitchedapps.frost.contracts.MainActivityContract
import com.pitchedapps.frost.contracts.VideoViewHolder
import com.pitchedapps.frost.db.CookieEntity
import com.pitchedapps.frost.facebook.FbCookie
@ -35,19 +34,23 @@ 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.
*/
class FrostJSI(val web: FrostWebView) {
class FrostJSI @Inject internal constructor(
val web: FrostWebView,
private val activity: Activity,
private val fbCookie: FbCookie,
private val prefs: Prefs
) {
private val fbCookie: FbCookie get() = web.fbCookie
private val prefs: Prefs get() = web.prefs
private val context: Context = web.context
private val activity: MainActivity? = context as? MainActivity
private val header: SendChannel<String>? = activity?.headerBadgeChannel
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 cookies: List<CookieEntity> = activity?.cookies() ?: arrayListOf()
private val cookies: List<CookieEntity> = activity.cookies()
/**
* Attempts to load the url in an overlay
@ -61,7 +64,7 @@ class FrostJSI(val web: FrostWebView) {
fun loadVideo(url: String?, isGif: Boolean): Boolean =
if (url != null && prefs.enablePip) {
web.post {
(context as? VideoViewHolder)?.showVideo(url, isGif)
(activity as? VideoViewHolder)?.showVideo(url, isGif)
?: L.e { "Could not load video; contract not implemented" }
}
true
@ -82,7 +85,7 @@ class FrostJSI(val web: FrostWebView) {
fun contextMenu(url: String?, text: String?) {
// url will be formatted through webcontext
web.post {
context.showWebContextMenu(
activity.showWebContextMenu(
WebContext(url.takeIf { it.isIndependent }, text),
fbCookie,
prefs
@ -96,7 +99,7 @@ class FrostJSI(val web: FrostWebView) {
*/
@JavascriptInterface
fun longClick(start: Boolean) {
activity?.contentBinding?.viewpager?.enableSwipe = !start
mainActivity?.contentBinding?.viewpager?.enableSwipe = !start
if (web.frostWebClient.urlSupportsRefresh) {
web.parent.swipeDisabledByAction = start
}
@ -113,15 +116,15 @@ class FrostJSI(val web: FrostWebView) {
web.parent.swipeDisabledByAction = disable
if (disable) {
// locked onto an input field; ensure content is visible
(context as? MainActivityContract)?.collapseAppBar()
mainActivity?.collapseAppBar()
}
}
@JavascriptInterface
fun loadLogin() {
L.d { "Sign up button found; load login" }
context.ctxCoroutine.launch {
fbCookie.logout(context, deleteCookie = false)
activity.ctxCoroutine.launch {
fbCookie.logout(activity, deleteCookie = false)
}
}
@ -130,7 +133,7 @@ class FrostJSI(val web: FrostWebView) {
*/
@JavascriptInterface
fun loadImage(imageUrl: String, text: String?) {
context.launchImageActivity(imageUrl, text)
activity.launchImageActivity(imageUrl, text)
}
@JavascriptInterface
@ -159,8 +162,8 @@ class FrostJSI(val web: FrostWebView) {
@JavascriptInterface
fun allowHorizontalScrolling(enable: Boolean) {
activity?.contentBinding?.viewpager?.enableSwipe = enable
(context as? WebOverlayActivityBase)?.swipeBack?.disallowIntercept = !enable
mainActivity?.contentBinding?.viewpager?.enableSwipe = enable
webActivity?.swipeBack?.disallowIntercept = !enable
}
private var isScrolling = false

View File

@ -1,6 +1,3 @@
v3.1.0
v3.1.1
* Fix multi account sign in
* Only clear out cookies on explicit logout; Facebook logout redirects no longer erase cookies
* Update themes
* Big infra changes (please file bugs for new crashes)
* Many internal fixes to address 3.1.0 issues

View File

@ -5,6 +5,11 @@
<version title="v" />
<item text="" />
-->
<version title="v3.1.1" />
<item text="Many internal fixes to address 3.1.0 issues" />
<item text="" />
<item text="" />
<item text="" />
<version title="v3.1.0" />
<item text="Fix multi account sign in" />

View File

@ -1,5 +1,8 @@
# Changelog
## v3.1.1
* Many internal fixes to address 3.1.0 issues
## v3.1.0
* Fix multi account sign in
* Only clear out cookies on explicit logout; Facebook logout redirects no longer erase cookies