This commit is contained in:
Fabian Freund
2025-02-03 15:09:04 +01:00
parent 36acd46318
commit 025ecaf2e3
132 changed files with 4431 additions and 1644 deletions
@@ -140,8 +140,9 @@ dependencies {
implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'com.google.android.material:material:1.12.0'
//https://stackoverflow.com/questions/73782320/onbackinvokedcallback-is-not-enabled-for-the-application-in-set-androidenableo
implementation 'androidx.activity:activity-ktx:1.9.3'
implementation 'androidx.activity:activity-ktx:1.10.0'
implementation 'androidx.paging:paging-runtime-ktx:3.3.5'
testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.mockito:mockito-core:5.2.0")
testImplementation("org.mockito:mockito-core:5.15.2")
}
@@ -7,6 +7,7 @@ import eu.lensai.flutter_mozilla_components.activities.NotificationActivity
import eu.lensai.flutter_mozilla_components.api.GeckoAddonsApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoBrowserApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoCookieApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoDeleteBrowsingDataControllerImpl
import eu.lensai.flutter_mozilla_components.api.GeckoEngineSettingsApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoFindApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoIconsApiImpl
@@ -20,6 +21,7 @@ import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonEvents
import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonsApi
import eu.lensai.flutter_mozilla_components.pigeons.GeckoBrowserApi
import eu.lensai.flutter_mozilla_components.pigeons.GeckoCookieApi
import eu.lensai.flutter_mozilla_components.pigeons.GeckoDeleteBrowsingDataController
import eu.lensai.flutter_mozilla_components.pigeons.GeckoEngineSettingsApi
import eu.lensai.flutter_mozilla_components.pigeons.GeckoFindApi
import eu.lensai.flutter_mozilla_components.pigeons.GeckoIconsApi
@@ -98,6 +100,7 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
GeckoSelectionActionController.setUp(_flutterPluginBinding.binaryMessenger, GeckoSelectionActionControllerImpl(
selectionActionDelegate
))
GeckoDeleteBrowsingDataController.setUp(_flutterPluginBinding.binaryMessenger, GeckoDeleteBrowsingDataControllerImpl())
ReaderViewEvents.setUp(
_flutterPluginBinding.binaryMessenger,
@@ -0,0 +1,78 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package eu.lensai.flutter_mozilla_components
import androidx.paging.DataSource
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import mozilla.components.concept.engine.permission.SitePermissions
import mozilla.components.concept.engine.permission.SitePermissionsStorage
import kotlin.coroutines.CoroutineContext
class PermissionStorage(
private val permissionsStorage: SitePermissionsStorage,
private val dispatcher: CoroutineContext = Dispatchers.IO,
) {
/**
* Persists the [sitePermissions] provided as a parameter.
*
* @param sitePermissions The [SitePermissions] to be stored.
* @param private Indicates if the [SitePermissions] belongs to a private session.
*/
suspend fun add(sitePermissions: SitePermissions, private: Boolean) = withContext(dispatcher) {
permissionsStorage.save(sitePermissions, private = private)
}
/**
* Finds all [SitePermissions] that match the [origin].
*
* @param origin The site to be used as filter in the search.
* @param private Indicates if the [origin] belongs to a private session.
*/
suspend fun findSitePermissionsBy(origin: String, private: Boolean): SitePermissions? =
withContext(dispatcher) {
permissionsStorage.findSitePermissionsBy(origin, private = private)
}
/**
* Replaces an existing SitePermissions with the values of provided [sitePermissions].
*
* @param sitePermissions The [SitePermissions] to be updated.
* @param private Indicates if the [SitePermissions] belongs to a private session.
*/
suspend fun updateSitePermissions(sitePermissions: SitePermissions, private: Boolean) =
withContext(dispatcher) {
permissionsStorage.update(sitePermissions, private = private)
}
/**
* Returns all saved [SitePermissions] instances as a [DataSource.Factory].
*
* A consuming app can transform the data source into a `LiveData<PagedList>` of when using RxJava2 into a
* `Flowable<PagedList>` or `Observable<PagedList>`, that can be observed.
*
* - https://developer.android.com/topic/libraries/architecture/paging/data
* - https://developer.android.com/topic/libraries/architecture/paging/ui
*/
suspend fun getSitePermissionsPaged(): DataSource.Factory<Int, SitePermissions> {
return permissionsStorage.getSitePermissionsPaged()
}
/**
* Deletes all sitePermissions that match the sitePermissions provided as a parameter.
* @param sitePermissions The [SitePermissions] to be deleted from the storage.
*/
suspend fun deleteSitePermissions(sitePermissions: SitePermissions) = withContext(dispatcher) {
permissionsStorage.remove(sitePermissions, private = false)
}
/**
* Deletes all sitePermissions sitePermissions.
*/
suspend fun deleteAllSitePermissions() = withContext(dispatcher) {
permissionsStorage.removeAll()
}
}
@@ -282,11 +282,11 @@ class WebExtensionPromptFeature(
var title = context.getString(MozComp.string.mozac_feature_addons_cant_install_extension, "")
val message = when (exception) {
is WebExtensionInstallException.Blocklisted -> {
context.getString(MozComp.string.mozac_feature_addons_blocklisted_1, addonName)
context.getString(MozComp.string.mozac_feature_addons_blocklisted_2, addonName)
}
is WebExtensionInstallException.SoftBlocked -> {
context.getString(MozComp.string.mozac_feature_addons_soft_blocked, addonName)
context.getString(MozComp.string.mozac_feature_addons_soft_blocked_1, addonName)
}
is WebExtensionInstallException.UserCancelled -> {
@@ -0,0 +1,107 @@
package eu.lensai.flutter_mozilla_components.api
import eu.lensai.flutter_mozilla_components.GlobalComponents
import eu.lensai.flutter_mozilla_components.pigeons.GeckoDeleteBrowsingDataController
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import mozilla.components.browser.state.action.EngineAction
import mozilla.components.browser.state.action.RecentlyClosedAction
import mozilla.components.concept.engine.Engine
import mozilla.components.concept.engine.translate.ModelManagementOptions
import mozilla.components.concept.engine.translate.ModelOperation
import mozilla.components.concept.engine.translate.OperationLevel
class GeckoDeleteBrowsingDataControllerImpl : GeckoDeleteBrowsingDataController {
companion object {
private val coroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
}
private val components by lazy {
requireNotNull(GlobalComponents.components) { "Components not initialized" }
}
override fun deleteTabs(callback: (Result<Unit>) -> Unit) {
coroutineScope.launch {
withContext(Dispatchers.Main) {
components.useCases.tabsUseCases.removeAllTabs.invoke(false)
callback(Result.success(Unit))
}
}
}
override fun deleteBrowsingHistory(callback: (Result<Unit>) -> Unit) {
coroutineScope.launch {
withContext(Dispatchers.Main) {
components.core.historyStorage.deleteEverything()
components.core.store.dispatch(EngineAction.PurgeHistoryAction)
components.core.icons.clear()
components.core.store.dispatch(RecentlyClosedAction.RemoveAllClosedTabAction)
callback(Result.success(Unit))
}
}
}
override fun deleteCookiesAndSiteData(callback: (Result<Unit>) -> Unit) {
coroutineScope.launch {
withContext(Dispatchers.Main) {
components.core.engine.clearData(
Engine.BrowsingData.select(
Engine.BrowsingData.COOKIES,
Engine.BrowsingData.AUTH_SESSIONS,
),
)
components.core.engine.clearData(Engine.BrowsingData.select(Engine.BrowsingData.DOM_STORAGES))
callback(Result.success(Unit))
}
}
}
override fun deleteCachedFiles(callback: (Result<Unit>) -> Unit) {
coroutineScope.launch {
withContext(Dispatchers.Main) {
components.core.engine.manageTranslationsLanguageModel(
options = ModelManagementOptions(
operation = ModelOperation.DELETE,
operationLevel = OperationLevel.CACHE,
),
onSuccess = { },
onError = { },
)
components.core.engine.clearData(
Engine.BrowsingData.select(Engine.BrowsingData.ALL_CACHES),
)
callback(Result.success(Unit))
}
}
}
override fun deleteSitePermissions(callback: (Result<Unit>) -> Unit) {
coroutineScope.launch {
withContext(Dispatchers.Main) {
components.core.engine.clearData(
Engine.BrowsingData.select(Engine.BrowsingData.ALL_SITE_SETTINGS),
)
components.core.permissionStorage.deleteAllSitePermissions()
callback(Result.success(Unit))
}
}
}
override fun deleteDownloads(callback: (Result<Unit>) -> Unit) {
coroutineScope.launch {
withContext(Dispatchers.Main) {
components.useCases.downloadsUseCases.removeAllDownloads.invoke()
callback(Result.success(Unit))
}
}
}
}
@@ -27,6 +27,24 @@ class GeckoEngineSettingsApiImpl : GeckoEngineSettingsApi {
requireNotNull(GlobalComponents.components) { "Components not initialized" }
}
private fun updateFingerprintingProtection(trackingProtectionPolicy: eu.lensai.flutter_mozilla_components.pigeons.TrackingProtectionPolicy) {
when(trackingProtectionPolicy) {
eu.lensai.flutter_mozilla_components.pigeons.TrackingProtectionPolicy.STRICT -> {
components.core.engineSettings.fingerprintingProtection = true
components.core.engineSettings.fingerprintingProtectionPrivateBrowsing = true
}
eu.lensai.flutter_mozilla_components.pigeons.TrackingProtectionPolicy.RECOMMENDED -> {
components.core.engineSettings.fingerprintingProtection = false
components.core.engineSettings.fingerprintingProtectionPrivateBrowsing = true
}
eu.lensai.flutter_mozilla_components.pigeons.TrackingProtectionPolicy.CUSTOM -> TODO()
eu.lensai.flutter_mozilla_components.pigeons.TrackingProtectionPolicy.NONE -> {
components.core.engineSettings.fingerprintingProtection = false
components.core.engineSettings.fingerprintingProtectionPrivateBrowsing = true
}
}
}
override fun setDefaultSettings(settings: GeckoEngineSettings) {
if(settings.javascriptEnabled != null) {
components.core.engineSettings.javascriptEnabled = settings.javascriptEnabled;
@@ -38,6 +56,8 @@ class GeckoEngineSettingsApiImpl : GeckoEngineSettingsApi {
eu.lensai.flutter_mozilla_components.pigeons.TrackingProtectionPolicy.STRICT -> TrackingProtectionPolicy.strict()
eu.lensai.flutter_mozilla_components.pigeons.TrackingProtectionPolicy.CUSTOM -> TODO()
}
updateFingerprintingProtection(settings.trackingProtectionPolicy)
}
if(settings.httpsOnlyMode != null) {
components.core.engineSettings.httpsOnlyMode = when(settings.httpsOnlyMode) {
@@ -89,13 +109,18 @@ class GeckoEngineSettingsApiImpl : GeckoEngineSettingsApi {
//First parse and set default values
setDefaultSettings(settings);
var reloadSession = false
//Then copy default settings into runtime
if(settings.javascriptEnabled != null) {
components.core.engine.settings.javascriptEnabled = components.core.engineSettings.javascriptEnabled
reloadSession = true
}
if(settings.trackingProtectionPolicy != null) {
components.useCases.settingsUseCases.updateTrackingProtection(components.core.engineSettings.trackingProtectionPolicy!!)
components.useCases.sessionUseCases.reload()
components.core.engine.settings.fingerprintingProtection = components.core.engineSettings.fingerprintingProtection
components.core.engine.settings.fingerprintingProtectionPrivateBrowsing = components.core.engineSettings.fingerprintingProtectionPrivateBrowsing
reloadSession = true
}
if(settings.httpsOnlyMode != null) {
components.core.engineSettings.httpsOnlyMode = components.core.engineSettings.httpsOnlyMode
@@ -105,12 +130,15 @@ class GeckoEngineSettingsApiImpl : GeckoEngineSettingsApi {
}
if(settings.preferredColorScheme != null) {
components.core.engineSettings.preferredColorScheme = components.core.engineSettings.preferredColorScheme
reloadSession = true
}
if(settings.cookieBannerHandlingMode != null) {
components.core.engineSettings.cookieBannerHandlingMode = components.core.engineSettings.cookieBannerHandlingMode
reloadSession = true
}
if(settings.cookieBannerHandlingModePrivateBrowsing != null) {
components.core.engineSettings.cookieBannerHandlingModePrivateBrowsing = components.core.engineSettings.cookieBannerHandlingModePrivateBrowsing
reloadSession = true
}
if(settings.cookieBannerHandlingGlobalRules != null) {
components.core.engineSettings.cookieBannerHandlingGlobalRules = components.core.engineSettings.cookieBannerHandlingGlobalRules
@@ -121,5 +149,9 @@ class GeckoEngineSettingsApiImpl : GeckoEngineSettingsApi {
if(settings.webContentIsolationStrategy != null) {
components.core.engineSettings.webContentIsolationStrategy = components.core.engineSettings.webContentIsolationStrategy
}
if(reloadSession) {
components.useCases.sessionUseCases.reload()
}
}
}
@@ -33,6 +33,7 @@ import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.LastMediaAccessState
import mozilla.components.browser.state.state.ReaderState
import mozilla.components.browser.state.state.SessionState
import mozilla.components.browser.state.state.createTab
import mozilla.components.browser.state.state.recover.RecoverableTab
import mozilla.components.browser.state.state.recover.TabState
import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
@@ -450,17 +451,33 @@ class GeckoTabsApiImpl : GeckoTabsApi {
}
}
override fun duplicateTab(selectTabId: String?, selectNewTab: Boolean): String {
override fun duplicateTab(
selectTabId: String?,
selectNewTab: Boolean,
newContextId: String?
): String {
try {
val tabState = selectTabId?.let { components.core.store.state.findTab(it) }
?: throw IllegalArgumentException("Tab not found")
return components.useCases.tabsUseCases.duplicateTab(
tab = tabState,
selectNewTab = selectNewTab
).also {
logger.debug("$TAG: Duplicated tab $selectTabId to new tab $it")
}
val duplicate = createTab(
url = tabState.content.url,
private = tabState.content.private,
contextId = newContextId,
parent = tabState,
engineSessionState = tabState.engineState.engineSessionState,
)
components.core.store.dispatch(
TabListAction.AddTabAction(
duplicate,
select = selectNewTab,
),
)
logger.debug("$TAG: Duplicated tab $selectTabId to new tab ${duplicate.id}")
return duplicate.id
} catch (e: Exception) {
logger.error("$TAG: Failed to duplicate tab", e)
throw e
@@ -8,6 +8,7 @@ import eu.lensai.flutter_mozilla_components.Components
import eu.lensai.flutter_mozilla_components.interceptor.AppRequestInterceptor
import eu.lensai.flutter_mozilla_components.services.DownloadService
import eu.lensai.flutter_mozilla_components.EngineProvider
import eu.lensai.flutter_mozilla_components.PermissionStorage
import eu.lensai.flutter_mozilla_components.services.MediaSessionService
import eu.lensai.flutter_mozilla_components.activities.NotificationActivity
import eu.lensai.flutter_mozilla_components.R
@@ -212,6 +213,8 @@ class Core(private val context: Context,
*/
val historyStorage by lazy { lazyHistoryStorage.value }
val permissionStorage by lazy { PermissionStorage( geckoSitePermissionsStorage ) }
/**
* Constructs a [TrackingProtectionPolicy] based on current preferences.
*
@@ -2017,7 +2017,7 @@ interface GeckoTabsApi {
fun selectOrAddTabByHistory(url: String, historyMetadata: HistoryMetadataKey): String
/** Selects an already existing tab displaying [url] or otherwise creates a new tab. */
fun selectOrAddTabByUrl(url: String, private: Boolean, source: SourceValue, flags: LoadUrlFlagsValue, ignoreFragment: Boolean): String
fun duplicateTab(selectTabId: String?, selectNewTab: Boolean): String
fun duplicateTab(selectTabId: String?, selectNewTab: Boolean, newContextId: String?): String
fun moveTabs(tabIds: List<String>, targetTabId: String, placeAfter: Boolean)
fun migratePrivateTabUseCase(tabId: String, alternativeUrl: String?): String
@@ -2287,8 +2287,9 @@ interface GeckoTabsApi {
val args = message as List<Any?>
val selectTabIdArg = args[0] as String?
val selectNewTabArg = args[1] as Boolean
val newContextIdArg = args[2] as String?
val wrapped: List<Any?> = try {
listOf(api.duplicateTab(selectTabIdArg, selectNewTabArg))
listOf(api.duplicateTab(selectTabIdArg, selectNewTabArg, newContextIdArg))
} catch (exception: Throwable) {
wrapError(exception)
}
@@ -3213,3 +3214,126 @@ class GeckoTabContentEvents(private val binaryMessenger: BinaryMessenger, privat
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface GeckoDeleteBrowsingDataController {
fun deleteTabs(callback: (Result<Unit>) -> Unit)
fun deleteBrowsingHistory(callback: (Result<Unit>) -> Unit)
fun deleteCookiesAndSiteData(callback: (Result<Unit>) -> Unit)
fun deleteCachedFiles(callback: (Result<Unit>) -> Unit)
fun deleteSitePermissions(callback: (Result<Unit>) -> Unit)
fun deleteDownloads(callback: (Result<Unit>) -> Unit)
companion object {
/** The codec used by GeckoDeleteBrowsingDataController. */
val codec: MessageCodec<Any?> by lazy {
GeckoPigeonCodec()
}
/** Sets up an instance of `GeckoDeleteBrowsingDataController` to handle messages through the `binaryMessenger`. */
@JvmOverloads
fun setUp(binaryMessenger: BinaryMessenger, api: GeckoDeleteBrowsingDataController?, messageChannelSuffix: String = "") {
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoDeleteBrowsingDataController.deleteTabs$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
api.deleteTabs{ result: Result<Unit> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
reply.reply(wrapResult(null))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoDeleteBrowsingDataController.deleteBrowsingHistory$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
api.deleteBrowsingHistory{ result: Result<Unit> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
reply.reply(wrapResult(null))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoDeleteBrowsingDataController.deleteCookiesAndSiteData$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
api.deleteCookiesAndSiteData{ result: Result<Unit> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
reply.reply(wrapResult(null))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoDeleteBrowsingDataController.deleteCachedFiles$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
api.deleteCachedFiles{ result: Result<Unit> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
reply.reply(wrapResult(null))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoDeleteBrowsingDataController.deleteSitePermissions$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
api.deleteSitePermissions{ result: Result<Unit> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
reply.reply(wrapResult(null))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoDeleteBrowsingDataController.deleteDownloads$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
api.deleteDownloads{ result: Result<Unit> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
reply.reply(wrapResult(null))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
}
}
}
@@ -4,6 +4,7 @@ export 'src/data/models/source.dart';
export 'src/domain/entities/default_selection_actions.dart';
export 'src/domain/services/gecko_addon.dart';
export 'src/domain/services/gecko_cookie.dart';
export 'src/domain/services/gecko_delete_browser_data.dart';
export 'src/domain/services/gecko_engine_settings.dart';
export 'src/domain/services/gecko_event.dart';
export 'src/domain/services/gecko_find_in_page.dart';
@@ -0,0 +1,34 @@
import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart';
final _apiInstance = GeckoDeleteBrowsingDataController();
class GeckoDeleteBrowserDataService {
final GeckoDeleteBrowsingDataController _api;
GeckoDeleteBrowserDataService({GeckoDeleteBrowsingDataController? api})
: _api = api ?? _apiInstance;
Future<void> deleteTabs() {
return _api.deleteTabs();
}
Future<void> deleteBrowsingHistory() {
return _api.deleteBrowsingHistory();
}
Future<void> deleteCookiesAndSiteData() {
return _api.deleteCookiesAndSiteData();
}
Future<void> deleteCachedFiles() {
return _api.deleteCachedFiles();
}
Future<void> deleteSitePermissions() {
return _api.deleteSitePermissions();
}
Future<void> deleteDownloads() {
return _api.deleteDownloads();
}
}
@@ -8,7 +8,71 @@ class GeckoEngineSettingsService {
GeckoEngineSettingsService({GeckoEngineSettingsApi? api})
: _api = api ?? _apiInstance;
Future<void> javaScriptEnabled(bool state) {
return _api.javaScriptEnabled(state);
Future<void> setDefaultSettings(GeckoEngineSettings settings,
{bool updateRuntime = true}) {
return updateRuntime
? _api.updateRuntimeSettings(settings)
: _api.setDefaultSettings(settings);
}
Future<void> javascriptEnabled(bool state) {
return _api.updateRuntimeSettings(
GeckoEngineSettings(javascriptEnabled: state),
);
}
Future<void> trackingProtectionPolicy(TrackingProtectionPolicy state) {
return _api.updateRuntimeSettings(
GeckoEngineSettings(trackingProtectionPolicy: state),
);
}
Future<void> httpsOnlyMode(HttpsOnlyMode state) {
return _api
.updateRuntimeSettings(GeckoEngineSettings(httpsOnlyMode: state));
}
Future<void> globalPrivacyControlEnabled(bool state) {
return _api.updateRuntimeSettings(
GeckoEngineSettings(globalPrivacyControlEnabled: state),
);
}
Future<void> preferredColorScheme(ColorScheme state) {
return _api.updateRuntimeSettings(
GeckoEngineSettings(preferredColorScheme: state),
);
}
Future<void> cookieBannerHandlingMode(CookieBannerHandlingMode state) {
return _api.updateRuntimeSettings(
GeckoEngineSettings(cookieBannerHandlingMode: state),
);
}
Future<void> cookieBannerHandlingModePrivateBrowsing(
CookieBannerHandlingMode state,
) {
return _api.updateRuntimeSettings(
GeckoEngineSettings(cookieBannerHandlingModePrivateBrowsing: state),
);
}
Future<void> cookieBannerHandlingGlobalRules(bool state) {
return _api.updateRuntimeSettings(
GeckoEngineSettings(cookieBannerHandlingGlobalRules: state),
);
}
Future<void> cookieBannerHandlingGlobalRulesSubFrames(bool state) {
return _api.updateRuntimeSettings(
GeckoEngineSettings(cookieBannerHandlingGlobalRulesSubFrames: state),
);
}
Future<void> webContentIsolationStrategy(WebContentIsolationStrategy state) {
return _api.updateRuntimeSettings(
GeckoEngineSettings(webContentIsolationStrategy: state),
);
}
}
@@ -142,12 +142,14 @@ class GeckoTabService {
}
Future<String> duplicateTab({
String? selectTabId,
required String? selectTabId,
required String? newContextId,
bool selectNewTab = true,
}) {
return _api.duplicateTab(
selectTabId: selectTabId,
selectNewTab: selectNewTab,
newContextId: newContextId,
);
}
@@ -10,8 +10,13 @@ import 'package:flutter_mozilla_components/src/domain/services/gecko_browser.dar
class GeckoView extends StatefulWidget {
final FutureOr<void> Function()? preInitializationStep;
final FutureOr<void> Function()? postInitializationStep;
const GeckoView({super.key, this.preInitializationStep});
const GeckoView({
super.key,
this.preInitializationStep,
this.postInitializationStep,
});
@override
State<GeckoView> createState() => _GeckoViewState();
@@ -70,6 +75,7 @@ class _GeckoViewState extends State<GeckoView> {
Duration(milliseconds: ((1000 / 60) * 2).toInt()),
).whenComplete(() async {
await browserService.showNativeFragment();
await widget.postInitializationStep?.call();
});
});
})
@@ -2334,7 +2334,7 @@ class GeckoTabsApi {
}
}
Future<String> duplicateTab({required String? selectTabId, required bool selectNewTab}) async {
Future<String> duplicateTab({required String? selectTabId, required bool selectNewTab, required String? newContextId, }) async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoTabsApi.duplicateTab$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
@@ -2342,7 +2342,7 @@ class GeckoTabsApi {
binaryMessenger: pigeonVar_binaryMessenger,
);
final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[selectTabId, selectNewTab]) as List<Object?>?;
await pigeonVar_channel.send(<Object?>[selectTabId, selectNewTab, newContextId]) as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
@@ -3602,3 +3602,149 @@ abstract class GeckoTabContentEvents {
}
}
}
class GeckoDeleteBrowsingDataController {
/// Constructor for [GeckoDeleteBrowsingDataController]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
GeckoDeleteBrowsingDataController({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
: pigeonVar_binaryMessenger = binaryMessenger,
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
final BinaryMessenger? pigeonVar_binaryMessenger;
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
final String pigeonVar_messageChannelSuffix;
Future<void> deleteTabs() async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoDeleteBrowsingDataController.deleteTabs$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(null) as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
throw PlatformException(
code: pigeonVar_replyList[0]! as String,
message: pigeonVar_replyList[1] as String?,
details: pigeonVar_replyList[2],
);
} else {
return;
}
}
Future<void> deleteBrowsingHistory() async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoDeleteBrowsingDataController.deleteBrowsingHistory$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(null) as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
throw PlatformException(
code: pigeonVar_replyList[0]! as String,
message: pigeonVar_replyList[1] as String?,
details: pigeonVar_replyList[2],
);
} else {
return;
}
}
Future<void> deleteCookiesAndSiteData() async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoDeleteBrowsingDataController.deleteCookiesAndSiteData$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(null) as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
throw PlatformException(
code: pigeonVar_replyList[0]! as String,
message: pigeonVar_replyList[1] as String?,
details: pigeonVar_replyList[2],
);
} else {
return;
}
}
Future<void> deleteCachedFiles() async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoDeleteBrowsingDataController.deleteCachedFiles$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(null) as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
throw PlatformException(
code: pigeonVar_replyList[0]! as String,
message: pigeonVar_replyList[1] as String?,
details: pigeonVar_replyList[2],
);
} else {
return;
}
}
Future<void> deleteSitePermissions() async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoDeleteBrowsingDataController.deleteSitePermissions$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(null) as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
throw PlatformException(
code: pigeonVar_replyList[0]! as String,
message: pigeonVar_replyList[1] as String?,
details: pigeonVar_replyList[2],
);
} else {
return;
}
}
Future<void> deleteDownloads() async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoDeleteBrowsingDataController.deleteDownloads$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(null) as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
throw PlatformException(
code: pigeonVar_replyList[0]! as String,
message: pigeonVar_replyList[1] as String?,
details: pigeonVar_replyList[2],
);
} else {
return;
}
}
}
@@ -835,6 +835,7 @@ abstract class GeckoTabsApi {
String duplicateTab({
required String? selectTabId,
required bool selectNewTab,
required String? newContextId,
});
void moveTabs({
@@ -1016,3 +1017,19 @@ abstract class GeckoTabContentEvents {
TabContent content,
);
}
@HostApi()
abstract class GeckoDeleteBrowsingDataController {
@async
void deleteTabs();
@async
void deleteBrowsingHistory();
@async
void deleteCookiesAndSiteData();
@async
void deleteCachedFiles();
@async
void deleteSitePermissions();
@async
void deleteDownloads();
}
@@ -1,4 +1,4 @@
# This is a generated file; do not edit or check into version control.
integration_test=/home/fafre/development/flutter/packages/integration_test/
sqlite3_flutter_libs=/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.29/
sqlite3_flutter_libs=/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.29+1/
sqlite3_vec=/home/fafre/development/repos/lensai/packages/sqlite3_vec/
@@ -1 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"integration_test","path":"/home/fafre/development/flutter/packages/integration_test/","native_build":true,"dependencies":[]},{"name":"sqlite3_flutter_libs","path":"/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.29/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"integration_test","path":"/home/fafre/development/flutter/packages/integration_test/","native_build":true,"dependencies":[]},{"name":"sqlite3_flutter_libs","path":"/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.29/","native_build":true,"dependencies":[]},{"name":"sqlite3_vec","path":"/home/fafre/development/repos/lensai/packages/sqlite3_vec/","native_build":true,"dependencies":[]}],"macos":[{"name":"sqlite3_flutter_libs","path":"/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.29/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"sqlite3_flutter_libs","path":"/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.29/","native_build":true,"dependencies":[]},{"name":"sqlite3_vec","path":"/home/fafre/development/repos/lensai/packages/sqlite3_vec/","native_build":true,"dependencies":[]}],"windows":[{"name":"sqlite3_flutter_libs","path":"/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.29/","native_build":true,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"integration_test","dependencies":[]},{"name":"sqlite3_flutter_libs","dependencies":[]},{"name":"sqlite3_vec","dependencies":[]}],"date_created":"2025-01-26 00:44:40.809594","version":"3.27.3","swift_package_manager_enabled":false}
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"integration_test","path":"/home/fafre/development/flutter/packages/integration_test/","native_build":true,"dependencies":[]},{"name":"sqlite3_flutter_libs","path":"/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.29+1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"integration_test","path":"/home/fafre/development/flutter/packages/integration_test/","native_build":true,"dependencies":[]},{"name":"sqlite3_flutter_libs","path":"/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.29+1/","native_build":true,"dependencies":[]},{"name":"sqlite3_vec","path":"/home/fafre/development/repos/lensai/packages/sqlite3_vec/","native_build":true,"dependencies":[]}],"macos":[{"name":"sqlite3_flutter_libs","path":"/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.29+1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"sqlite3_flutter_libs","path":"/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.29+1/","native_build":true,"dependencies":[]},{"name":"sqlite3_vec","path":"/home/fafre/development/repos/lensai/packages/sqlite3_vec/","native_build":true,"dependencies":[]}],"windows":[{"name":"sqlite3_flutter_libs","path":"/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.29+1/","native_build":true,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"integration_test","dependencies":[]},{"name":"sqlite3_flutter_libs","dependencies":[]},{"name":"sqlite3_vec","dependencies":[]}],"date_created":"2025-01-31 01:49:54.251398","version":"3.27.3","swift_package_manager_enabled":false}
@@ -1 +1 @@
/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.29/
/home/fafre/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.29+1/
+1 -1
View File
@@ -29,7 +29,7 @@ dependencies:
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
sqlite3: ^2.7.2
sqlite3_flutter_libs: ^0.5.29
sqlite3_flutter_libs: ^0.5.29+1
dev_dependencies:
integration_test: