everything build but untested & migration not finished

This commit is contained in:
Fabian Freund
2024-10-09 13:27:42 +02:00
parent 37d2c84d7f
commit 2c71eeb670
132 changed files with 3790 additions and 2817 deletions
@@ -2,13 +2,13 @@ package eu.lensai.flutter_mozilla_components
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents
import eu.lensai.flutter_mozilla_components.feature.DefaultSelectionActionDelegate
import eu.lensai.flutter_mozilla_components.integration.ReaderViewIntegration
import eu.lensai.flutter_mozilla_components.pigeons.SelectionAction
import mozilla.components.browser.thumbnails.BrowserThumbnails
import mozilla.components.concept.engine.EngineView
import mozilla.components.feature.media.fullscreen.MediaSessionFullscreenFeature
@@ -24,16 +24,16 @@ import mozilla.components.support.ktx.android.view.exitImmersiveMode
*/
class BrowserFragment(private val context: Context) : BaseBrowserFragment(), UserInteractionHandler {
private val thumbnailsFeature = ViewBoundFeatureWrapper<BrowserThumbnails>()
private val readerViewFeature = ViewBoundFeatureWrapper<ReaderViewIntegration>()
private val fullScreenFeature = ViewBoundFeatureWrapper<FullScreenFeature>()
private val mediaSessionFullscreenFeature =
ViewBoundFeatureWrapper<MediaSessionFullscreenFeature>()
override fun createEngine(components: Components): EngineView {
return components.engine.createView(context).apply {
// selectionActionDelegate = DefaultSelectionActionDelegate(
// store = components.store,
// context = context,
// )
selectionActionDelegate = DefaultSelectionActionDelegate(
components.selectionAction
)
}
}
@@ -47,6 +47,19 @@ class BrowserFragment(private val context: Context) : BaseBrowserFragment(), Use
val binding = super.binding
readerViewFeature.set(
feature = ReaderViewIntegration(
requireContext(),
components.engine,
components.store,
binding.readerViewBar,
components.readerViewEvents,
components.readerViewController,
),
owner = this,
view = binding.root,
)
fullScreenFeature.set(
feature = FullScreenFeature(
components.store,
@@ -3,32 +3,28 @@ package eu.lensai.flutter_mozilla_components
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.util.Log
import android.widget.Toast
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import eu.lensai.flutter_mozilla_components.api.ReaderViewEventsImpl
import eu.lensai.flutter_mozilla_components.ext.toWebPBytes
import eu.lensai.flutter_mozilla_components.middleware.FlutterEventMiddleware
import eu.lensai.flutter_mozilla_components.pigeons.FindResultState
import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents
import eu.lensai.flutter_mozilla_components.pigeons.HistoryItem
import eu.lensai.flutter_mozilla_components.pigeons.HistoryState
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController
import eu.lensai.flutter_mozilla_components.pigeons.ReaderableState
import eu.lensai.flutter_mozilla_components.pigeons.SecurityInfoState
import eu.lensai.flutter_mozilla_components.pigeons.SelectionAction
import eu.lensai.flutter_mozilla_components.pigeons.TabContentState
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.launch
import mozilla.components.browser.engine.gecko.GeckoEngine
import mozilla.components.browser.icons.BrowserIcons
import mozilla.components.browser.session.storage.SessionStorage
import mozilla.components.browser.state.engine.EngineMiddleware
import mozilla.components.browser.state.engine.middleware.SessionPrioritizationMiddleware
import mozilla.components.browser.state.selector.selectedTab
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.browser.thumbnails.ThumbnailsMiddleware
import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
@@ -75,7 +71,12 @@ private const val DAY_IN_MINUTES = 24 * 60L
@SuppressLint("NewApi")
@Suppress("LargeClass")
open class DefaultComponents(private val applicationContext: Context, private val flutterEvents: GeckoStateEvents) {
open class DefaultComponents(
private val applicationContext: Context,
private val flutterEvents: GeckoStateEvents,
val readerViewController: ReaderViewController,
val selectionAction: SelectionAction,
) {
companion object {
const val SAMPLE_BROWSER_PREFERENCES = "sample_browser_preferences"
const val PREF_LAUNCH_EXTERNAL_APP = "sample_browser_launch_external_app"
@@ -277,6 +278,24 @@ open class DefaultComponents(private val applicationContext: Context, private va
}
}
this.flowScoped { flow ->
flow.mapNotNull { state -> state.tabs }
.filterChanged {
it.content.findResults
}
.collect { tab ->
tab.content.findResults
flutterEvents.onFindResults(
tab.id,
tab.content.findResults.map { result -> FindResultState(
activeMatchOrdinal = result.activeMatchOrdinal.toLong(),
numberOfMatches = result.numberOfMatches.toLong(),
isDoneCounting = result.isDoneCounting,
) }
) { _ -> }
}
}
WebNotificationFeature(
applicationContext,
engine,
@@ -294,6 +313,8 @@ open class DefaultComponents(private val applicationContext: Context, private va
val sessionUseCases by lazy { SessionUseCases(store) }
val tabsUseCases by lazy { TabsUseCases(store) }
val readerViewEvents by lazy { ReaderViewEventsImpl() }
// Addons
val addonManager by lazy {
AddonManager(store, engine, addonsProvider, addonUpdater)
@@ -3,28 +3,30 @@ package eu.lensai.flutter_mozilla_components
import android.app.Activity
import android.content.Context
import android.content.Intent
import androidx.annotation.NonNull
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import eu.lensai.flutter_mozilla_components.api.GeckoBrowserApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoCookieApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoEngineSettingsApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoFindApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoIconsApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoSessionApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoTabsApiImpl
import eu.lensai.flutter_mozilla_components.feature.CookieManagerFeature
import eu.lensai.flutter_mozilla_components.pigeons.GeckoBrowserApi
import eu.lensai.flutter_mozilla_components.pigeons.GeckoCookieApi
import eu.lensai.flutter_mozilla_components.pigeons.GeckoEngineSettingsApi
import eu.lensai.flutter_mozilla_components.pigeons.GeckoFindApi
import eu.lensai.flutter_mozilla_components.pigeons.GeckoIconsApi
import eu.lensai.flutter_mozilla_components.pigeons.GeckoSessionApi
import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents
import eu.lensai.flutter_mozilla_components.pigeons.GeckoTabsApi
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewEvents
import eu.lensai.flutter_mozilla_components.pigeons.SelectionAction
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import mozilla.components.browser.engine.gecko.GeckoEngine
import mozilla.components.browser.engine.gecko.fetch.GeckoViewFetchClient
import mozilla.components.concept.engine.Engine
@@ -32,7 +34,6 @@ import mozilla.components.experiment.NimbusExperimentDelegate
import mozilla.components.feature.webcompat.WebCompatFeature
import mozilla.components.lib.crash.handler.CrashHandlerService
import mozilla.components.support.base.log.Log
import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.base.log.sink.AndroidLogSink
import org.mozilla.geckoview.GeckoRuntime
import org.mozilla.geckoview.GeckoRuntimeSettings
@@ -40,7 +41,17 @@ import org.mozilla.geckoview.GeckoRuntimeSettings
/**
* Helper class for lazily instantiating components needed by the application.
*/
class Components(private val applicationContext: Context, flutterEvents: GeckoStateEvents) : DefaultComponents(applicationContext, flutterEvents) {
class Components(
private val applicationContext: Context,
flutterEvents: GeckoStateEvents,
readerViewController: ReaderViewController,
selectionAction: SelectionAction,
) : DefaultComponents(
applicationContext,
flutterEvents,
readerViewController,
selectionAction
) {
private val runtime by lazy {
// Allow for exfiltrating Gecko metrics through the Glean SDK.
val builder = GeckoRuntimeSettings.Builder().aboutConfigEnabled(true)
@@ -85,8 +96,16 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
_flutterPluginBinding = flutterPluginBinding
val flutterEvents = GeckoStateEvents(_flutterPluginBinding.binaryMessenger)
val readerViewController =
ReaderViewController(_flutterPluginBinding.binaryMessenger)
val selectionActionDelegate = SelectionAction(_flutterPluginBinding.binaryMessenger)
GlobalComponents.setUp(flutterPluginBinding.applicationContext, flutterEvents)
GlobalComponents.setUp(
flutterPluginBinding.applicationContext,
flutterEvents,
readerViewController,
selectionActionDelegate
)
val intent = Intent(flutterPluginBinding.applicationContext, NotificationActivity::class.java)
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -96,10 +115,17 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
showNativeFragment()
})
GeckoEngineSettingsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoEngineSettingsApiImpl())
GeckoSessionApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoSessionApiImpl())
GeckoTabsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoTabsApiImpl())
GeckoIconsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoIconsApiImpl())
GeckoCookieApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoCookieApiImpl())
GeckoFindApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoFindApiImpl())
ReaderViewEvents.setUp(
_flutterPluginBinding.binaryMessenger,
GlobalComponents.components!!.readerViewEvents
)
}
private fun showNativeFragment() {
@@ -2,6 +2,8 @@ package eu.lensai.flutter_mozilla_components
import android.content.Context
import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController
import eu.lensai.flutter_mozilla_components.pigeons.SelectionAction
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
@@ -29,8 +31,18 @@ object GlobalComponents {
.whenSessionsChange()
}
fun setUp(applicationContext: Context, flutterEvents: GeckoStateEvents) {
val newComponents = Components(applicationContext, flutterEvents)
fun setUp(
applicationContext: Context,
flutterEvents: GeckoStateEvents,
readerViewController: ReaderViewController,
selectionAction: SelectionAction
) {
val newComponents = Components(
applicationContext,
flutterEvents,
readerViewController,
selectionAction
)
newComponents.crashReporter.install(applicationContext)
Facts.registerProcessor(LogFactProcessor())
@@ -0,0 +1,13 @@
package eu.lensai.flutter_mozilla_components.api
import eu.lensai.flutter_mozilla_components.GlobalComponents
import eu.lensai.flutter_mozilla_components.pigeons.GeckoEngineSettingsApi
import mozilla.components.concept.engine.Engine
class GeckoEngineSettingsApiImpl : GeckoEngineSettingsApi {
private val engine: Engine by lazy { GlobalComponents.components!!.engine }
override fun javaScriptEnabled(state: Boolean) {
engine.settings.javascriptEnabled = state
}
}
@@ -0,0 +1,38 @@
package eu.lensai.flutter_mozilla_components.api
import eu.lensai.flutter_mozilla_components.GlobalComponents
import eu.lensai.flutter_mozilla_components.pigeons.GeckoFindApi
import mozilla.components.browser.state.selector.findTabOrCustomTab
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.concept.engine.EngineSession
class GeckoFindApiImpl : GeckoFindApi {
private val state: BrowserState by lazy { GlobalComponents.components!!.store.state }
private fun sessionByTabId(tabId: String?) : EngineSession? {
val loadSessionId = tabId
?: state.selectedTabId
if (loadSessionId == null) {
return null
}
val tab = state.findTabOrCustomTab(loadSessionId)
return tab?.engineState?.engineSession
}
override fun findAll(tabId: String?, text: String) {
val engineSession = sessionByTabId(tabId)
engineSession?.findAll(text)
}
override fun findNext(tabId: String?, forward: Boolean) {
val engineSession = sessionByTabId(tabId)
engineSession?.findNext(forward)
}
override fun clearMatches(tabId: String?) {
val engineSession = sessionByTabId(tabId)
engineSession?.clearFindMatches()
}
}
@@ -1,7 +1,5 @@
package eu.lensai.flutter_mozilla_components.api
import android.graphics.Bitmap
import android.os.Build
import eu.lensai.flutter_mozilla_components.GlobalComponents
import eu.lensai.flutter_mozilla_components.ext.toWebPBytes
import eu.lensai.flutter_mozilla_components.pigeons.*
@@ -9,7 +7,6 @@ import kotlinx.coroutines.*
import mozilla.components.browser.icons.BrowserIcons
import mozilla.components.browser.icons.Icon
import mozilla.components.concept.engine.manifest.Size as HtmlSize
import java.io.ByteArrayOutputStream
typealias MozillaIconRequest = mozilla.components.browser.icons.IconRequest
typealias MozillaIconSize = mozilla.components.browser.icons.IconRequest.Size
@@ -86,11 +83,11 @@ class GeckoIconsApiImpl() : GeckoIconsApi {
IconType.MANIFEST_ICON -> MozillaIconResourceType.MANIFEST_ICON
}
private fun Icon.Source.toApiSource(): Source = when (this) {
Icon.Source.GENERATOR -> Source.GENERATOR
Icon.Source.DOWNLOAD -> Source.DOWNLOAD
Icon.Source.INLINE -> Source.INLINE
Icon.Source.MEMORY -> Source.MEMORY
Icon.Source.DISK -> Source.DISK
private fun Icon.Source.toApiSource(): IconSource = when (this) {
Icon.Source.GENERATOR -> IconSource.GENERATOR
Icon.Source.DOWNLOAD -> IconSource.DOWNLOAD
Icon.Source.INLINE -> IconSource.INLINE
Icon.Source.MEMORY -> IconSource.MEMORY
Icon.Source.DISK -> IconSource.DISK
}
}
@@ -0,0 +1,32 @@
package eu.lensai.flutter_mozilla_components.api
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewEvents
// Interface for the listener
interface ReaderViewControllerListener {
fun onReaderViewToggled(enabled: Boolean)
fun onAppearanceButtonTap()
}
class ReaderViewEventsImpl : ReaderViewEvents {
private val listeners = mutableSetOf<ReaderViewControllerListener>()
override fun onToggleReaderView(enable: Boolean) {
listeners.forEach { it.onReaderViewToggled(enable) }
}
override fun onAppearanceButtonTap() {
listeners.forEach { it.onAppearanceButtonTap() }
}
// Method to add a listener
fun addListener(listener: ReaderViewControllerListener) {
listeners.add(listener)
}
// Method to remove a listener
fun removeListener(listener: ReaderViewControllerListener) {
listeners.remove(listener)
}
}
@@ -0,0 +1,51 @@
package eu.lensai.flutter_mozilla_components.feature
import eu.lensai.flutter_mozilla_components.pigeons.SelectionAction
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.suspendCancellableCoroutine
import mozilla.components.concept.engine.selection.SelectionActionDelegate
import kotlin.coroutines.resume
class DefaultSelectionActionDelegate(
private val selectionAction: SelectionAction
) : SelectionActionDelegate {
override fun getActionTitle(id: String): CharSequence? = runBlocking {
suspendCancellableCoroutine { continuation ->
selectionAction.getActionTitle(id) { result ->
continuation.resume(result.getOrNull())
}
}
}
override fun getAllActions(): Array<String> = runBlocking {
suspendCancellableCoroutine { continuation ->
selectionAction.getAllActions() { result ->
continuation.resume(result.getOrNull()!!.toTypedArray())
}
}
}
override fun isActionAvailable(id: String, selectedText: String): Boolean = runBlocking {
suspendCancellableCoroutine { continuation ->
selectionAction.isActionAvailable(id, selectedText) { result ->
continuation.resume(result.getOrNull()!!)
}
}
}
override fun performAction(id: String, selectedText: String): Boolean = runBlocking {
suspendCancellableCoroutine { continuation ->
selectionAction.performAction(id, selectedText) { result ->
continuation.resume(result.getOrNull()!!)
}
}
}
override fun sortedActions(actions: Array<String>): Array<String> = runBlocking {
suspendCancellableCoroutine { continuation ->
selectionAction.sortedActions(actions.toList()) { result ->
continuation.resume(result.getOrNull()!!.toTypedArray())
}
}
}
}
@@ -0,0 +1,72 @@
package eu.lensai.flutter_mozilla_components.integration
import android.content.Context
import android.graphics.drawable.Drawable
import androidx.core.content.ContextCompat
import eu.lensai.flutter_mozilla_components.GlobalComponents
import eu.lensai.flutter_mozilla_components.api.ReaderViewEventsImpl
import eu.lensai.flutter_mozilla_components.api.ReaderViewControllerListener
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController
import mozilla.components.browser.state.selector.selectedTab
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.concept.engine.Engine
import mozilla.components.feature.readerview.ReaderViewFeature
import mozilla.components.feature.readerview.view.ReaderViewControlsView
import mozilla.components.support.base.feature.LifecycleAwareFeature
import mozilla.components.support.base.feature.UserInteractionHandler
@Suppress("UndocumentedPublicClass")
class ReaderViewIntegration(
context: Context,
engine: Engine,
store: BrowserStore,
view: ReaderViewControlsView,
readerViewEvents: ReaderViewEventsImpl,
readerViewController: ReaderViewController
) : LifecycleAwareFeature, UserInteractionHandler {
private val controllerListener = object : ReaderViewControllerListener {
override fun onReaderViewToggled(enabled: Boolean) {
if (enabled) {
feature.showReaderView()
readerViewController.appearanceButtonVisibility(true) { _ -> };
} else {
feature.hideReaderView()
feature.hideControls()
readerViewController.appearanceButtonVisibility(false) { _ -> };
}
}
override fun onAppearanceButtonTap() {
feature.showControls()
}
}
init {
readerViewEvents.addListener(controllerListener)
}
private val feature = ReaderViewFeature(context, engine, store, view)
// Will be event based in flutter
// { available, active ->
// readerViewButtonVisible = available
// readerViewButton.setSelected(active)
//
// if (active) readerViewAppearanceButton.show() else readerViewAppearanceButton.hide()
// toolbar.invalidateActions()
// }
override fun start() {
feature.start()
}
override fun stop() {
feature.stop()
}
override fun onBackPressed(): Boolean {
return feature.onBackPressed()
}
}
@@ -1,4 +1,4 @@
// Autogenerated from Pigeon (v22.3.0), do not edit directly.
// Autogenerated from Pigeon (v22.4.2), do not edit directly.
// See also: https://pub.dev/packages/pigeon
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
@@ -865,6 +865,30 @@ data class TabContentState (
)
}
}
/** Generated class from Pigeon that represents data sent in messages. */
data class FindResultState (
val activeMatchOrdinal: Long,
val numberOfMatches: Long,
val isDoneCounting: Boolean
)
{
companion object {
fun fromList(pigeonVar_list: List<Any?>): FindResultState {
val activeMatchOrdinal = pigeonVar_list[0] as Long
val numberOfMatches = pigeonVar_list[1] as Long
val isDoneCounting = pigeonVar_list[2] as Boolean
return FindResultState(activeMatchOrdinal, numberOfMatches, isDoneCounting)
}
}
fun toList(): List<Any?> {
return listOf(
activeMatchOrdinal,
numberOfMatches,
isDoneCounting,
)
}
}
private open class GeckoPigeonCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
return when (type) {
@@ -1003,6 +1027,11 @@ private open class GeckoPigeonCodec : StandardMessageCodec() {
TabContentState.fromList(it)
}
}
156.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
FindResultState.fromList(it)
}
}
else -> super.readValueOfType(type, buffer)
}
}
@@ -1116,6 +1145,10 @@ private open class GeckoPigeonCodec : StandardMessageCodec() {
stream.write(155)
writeValue(stream, value.toList())
}
is FindResultState -> {
stream.write(156)
writeValue(stream, value.toList())
}
else -> super.writeValue(stream, value)
}
}
@@ -1155,6 +1188,40 @@ interface GeckoBrowserApi {
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface GeckoEngineSettingsApi {
fun javaScriptEnabled(state: Boolean)
companion object {
/** The codec used by GeckoEngineSettingsApi. */
val codec: MessageCodec<Any?> by lazy {
GeckoPigeonCodec()
}
/** Sets up an instance of `GeckoEngineSettingsApi` to handle messages through the `binaryMessenger`. */
@JvmOverloads
fun setUp(binaryMessenger: BinaryMessenger, api: GeckoEngineSettingsApi?, messageChannelSuffix: String = "") {
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoEngineSettingsApi.javaScriptEnabled$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val stateArg = args[0] as Boolean
val wrapped: List<Any?> = try {
api.javaScriptEnabled(stateArg)
listOf(null)
} catch (exception: Throwable) {
wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface GeckoSessionApi {
fun loadUrl(tabId: String?, url: String, flags: LoadUrlFlagsValue, additionalHeaders: Map<String, String>?)
fun loadData(tabId: String?, data: String, mimeType: String, encoding: String)
@@ -1802,6 +1869,80 @@ interface GeckoTabsApi {
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface GeckoFindApi {
fun findAll(tabId: String?, text: String)
fun findNext(tabId: String?, forward: Boolean)
fun clearMatches(tabId: String?)
companion object {
/** The codec used by GeckoFindApi. */
val codec: MessageCodec<Any?> by lazy {
GeckoPigeonCodec()
}
/** Sets up an instance of `GeckoFindApi` to handle messages through the `binaryMessenger`. */
@JvmOverloads
fun setUp(binaryMessenger: BinaryMessenger, api: GeckoFindApi?, messageChannelSuffix: String = "") {
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoFindApi.findAll$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val tabIdArg = args[0] as String?
val textArg = args[1] as String
val wrapped: List<Any?> = try {
api.findAll(tabIdArg, textArg)
listOf(null)
} catch (exception: Throwable) {
wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoFindApi.findNext$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val tabIdArg = args[0] as String?
val forwardArg = args[1] as Boolean
val wrapped: List<Any?> = try {
api.findNext(tabIdArg, forwardArg)
listOf(null)
} catch (exception: Throwable) {
wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoFindApi.clearMatches$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val tabIdArg = args[0] as String?
val wrapped: List<Any?> = try {
api.clearMatches(tabIdArg)
listOf(null)
} catch (exception: Throwable) {
wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface GeckoIconsApi {
fun loadIcon(request: IconRequest, callback: (Result<IconResult>) -> Unit)
@@ -2102,4 +2243,249 @@ class GeckoStateEvents(private val binaryMessenger: BinaryMessenger, private val
}
}
}
fun onFindResults(idArg: String, resultsArg: List<FindResultState>, callback: (Result<Unit>) -> Unit)
{
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
val channelName = "dev.flutter.pigeon.flutter_mozilla_components.GeckoStateEvents.onFindResults$separatedMessageChannelSuffix"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(listOf(idArg, resultsArg)) {
if (it is List<*>) {
if (it.size > 1) {
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
} else {
callback(Result.success(Unit))
}
} else {
callback(Result.failure(createConnectionError(channelName)))
}
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface ReaderViewEvents {
fun onToggleReaderView(enable: Boolean)
fun onAppearanceButtonTap()
companion object {
/** The codec used by ReaderViewEvents. */
val codec: MessageCodec<Any?> by lazy {
GeckoPigeonCodec()
}
/** Sets up an instance of `ReaderViewEvents` to handle messages through the `binaryMessenger`. */
@JvmOverloads
fun setUp(binaryMessenger: BinaryMessenger, api: ReaderViewEvents?, messageChannelSuffix: String = "") {
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.ReaderViewEvents.onToggleReaderView$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val enableArg = args[0] as Boolean
val wrapped: List<Any?> = try {
api.onToggleReaderView(enableArg)
listOf(null)
} catch (exception: Throwable) {
wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.ReaderViewEvents.onAppearanceButtonTap$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
val wrapped: List<Any?> = try {
api.onAppearanceButtonTap()
listOf(null)
} catch (exception: Throwable) {
wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
}
}
}
/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */
class ReaderViewController(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") {
companion object {
/** The codec used by ReaderViewController. */
val codec: MessageCodec<Any?> by lazy {
GeckoPigeonCodec()
}
}
fun appearanceButtonVisibility(visibleArg: Boolean, callback: (Result<Unit>) -> Unit)
{
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
val channelName = "dev.flutter.pigeon.flutter_mozilla_components.ReaderViewController.appearanceButtonVisibility$separatedMessageChannelSuffix"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(listOf(visibleArg)) {
if (it is List<*>) {
if (it.size > 1) {
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
} else {
callback(Result.success(Unit))
}
} else {
callback(Result.failure(createConnectionError(channelName)))
}
}
}
fun readerViewButtonVisibility(visibleArg: Boolean, callback: (Result<Unit>) -> Unit)
{
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
val channelName = "dev.flutter.pigeon.flutter_mozilla_components.ReaderViewController.readerViewButtonVisibility$separatedMessageChannelSuffix"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(listOf(visibleArg)) {
if (it is List<*>) {
if (it.size > 1) {
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
} else {
callback(Result.success(Unit))
}
} else {
callback(Result.failure(createConnectionError(channelName)))
}
}
}
}
/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */
class SelectionAction(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") {
companion object {
/** The codec used by SelectionAction. */
val codec: MessageCodec<Any?> by lazy {
GeckoPigeonCodec()
}
}
/**
* Gets Strings representing all possible selection actions.
*
* @returns String IDs for each action that could possibly be shown in the context menu. This
* array must include all actions, available or not, and must not change over the class lifetime.
*/
fun getAllActions(callback: (Result<List<String>>) -> Unit)
{
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
val channelName = "dev.flutter.pigeon.flutter_mozilla_components.SelectionAction.getAllActions$separatedMessageChannelSuffix"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(null) {
if (it is List<*>) {
if (it.size > 1) {
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
} else if (it[0] == null) {
callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")))
} else {
val output = it[0] as List<String>
callback(Result.success(output))
}
} else {
callback(Result.failure(createConnectionError(channelName)))
}
}
}
/**
* Checks if an action can be shown on a new selection context menu.
*
* @returns whether or not the the custom action with the id of [id] is currently available
* which may be informed by [selectedText].
*/
fun isActionAvailable(idArg: String, selectedTextArg: String, callback: (Result<Boolean>) -> Unit)
{
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
val channelName = "dev.flutter.pigeon.flutter_mozilla_components.SelectionAction.isActionAvailable$separatedMessageChannelSuffix"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(listOf(idArg, selectedTextArg)) {
if (it is List<*>) {
if (it.size > 1) {
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
} else if (it[0] == null) {
callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")))
} else {
val output = it[0] as Boolean
callback(Result.success(output))
}
} else {
callback(Result.failure(createConnectionError(channelName)))
}
}
}
/**
* Gets a title to be shown in the selection context menu.
*
* @returns the text that should be shown on the action.
*/
fun getActionTitle(idArg: String, callback: (Result<String?>) -> Unit)
{
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
val channelName = "dev.flutter.pigeon.flutter_mozilla_components.SelectionAction.getActionTitle$separatedMessageChannelSuffix"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(listOf(idArg)) {
if (it is List<*>) {
if (it.size > 1) {
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
} else {
val output = it[0] as String?
callback(Result.success(output))
}
} else {
callback(Result.failure(createConnectionError(channelName)))
}
}
}
/**
* Should perform the action with the id of [id].
*
* @returns [true] if the action was consumed.
*/
fun performAction(idArg: String, selectedTextArg: String, callback: (Result<Boolean>) -> Unit)
{
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
val channelName = "dev.flutter.pigeon.flutter_mozilla_components.SelectionAction.performAction$separatedMessageChannelSuffix"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(listOf(idArg, selectedTextArg)) {
if (it is List<*>) {
if (it.size > 1) {
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
} else if (it[0] == null) {
callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")))
} else {
val output = it[0] as Boolean
callback(Result.success(output))
}
} else {
callback(Result.failure(createConnectionError(channelName)))
}
}
}
/**
* Takes in a list of actions and sorts them.
*
* @returns the sorted list.
*/
fun sortedActions(actionsArg: List<String>, callback: (Result<List<String>>) -> Unit)
{
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
val channelName = "dev.flutter.pigeon.flutter_mozilla_components.SelectionAction.sortedActions$separatedMessageChannelSuffix"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(listOf(actionsArg)) {
if (it is List<*>) {
if (it.size > 1) {
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
} else if (it[0] == null) {
callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")))
} else {
val output = it[0] as List<String>
callback(Result.success(output))
}
} else {
callback(Result.failure(createConnectionError(channelName)))
}
}
}
}
@@ -20,6 +20,16 @@
android:layout_height="match_parent">
<!-- Inject engine here -->
</mozilla.components.ui.widgets.VerticalSwipeRefreshLayout>
<mozilla.components.feature.readerview.view.ReaderViewControlsBar
android:id="@+id/readerViewBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#FFFFFFFF"
android:elevation="10dp"
android:paddingBottom="55dp"
android:visibility="gone" />
</FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>