fix site clear for cookies/cache

This commit is contained in:
Fabian Freund
2026-05-05 07:35:49 +02:00
parent f1313628d1
commit 01c2cea856
9 changed files with 2539 additions and 3514 deletions
@@ -21,7 +21,9 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:nullability/nullability.dart';
import 'package:weblibre/core/logger.dart'; import 'package:weblibre/core/logger.dart';
import 'package:weblibre/features/geckoview/domain/controllers/bottom_sheet.dart';
import 'package:weblibre/features/geckoview/domain/providers/tab_session.dart'; import 'package:weblibre/features/geckoview/domain/providers/tab_session.dart';
import 'package:weblibre/features/geckoview/features/browser/presentation/dialogs/clear_site_data_dialog.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/dialogs/clear_site_data_dialog.dart';
import 'package:weblibre/utils/ui_helper.dart'; import 'package:weblibre/utils/ui_helper.dart';
@@ -52,6 +54,13 @@ class ClearSiteDataSection extends HookConsumerWidget {
newTypes.remove(type); newTypes.remove(type);
} else { } else {
newTypes.add(type); newTypes.add(type);
if (type == ClearDataType.allSiteData) {
newTypes.removeAll([
ClearDataType.onlyCaches,
ClearDataType.onlyCookies,
]);
}
} }
selectedTypes.value = newTypes; selectedTypes.value = newTypes;
} }
@@ -79,18 +88,13 @@ class ClearSiteDataSection extends HookConsumerWidget {
), ),
if (isExpanded.value) ...[ if (isExpanded.value) ...[
_DataTypeCheckbox( _DataTypeCheckbox(
label: 'Cookies', label: 'Auth Sessions',
subtitle: 'Login tokens, preferences, tracking data', subtitle: 'Saved logins, active sessions',
type: ClearDataType.cookies, type: ClearDataType.authSessions,
isSelected: selectedTypes.value.contains(ClearDataType.cookies), isSelected: selectedTypes.value.contains(
onChanged: (selected) => toggleType(ClearDataType.cookies), ClearDataType.authSessions,
), ),
_DataTypeCheckbox( onChanged: (selected) => toggleType(ClearDataType.authSessions),
label: 'Cached Files',
subtitle: 'Images, scripts, stylesheets',
type: ClearDataType.allCaches,
isSelected: selectedTypes.value.contains(ClearDataType.allCaches),
onChanged: (selected) => toggleType(ClearDataType.allCaches),
), ),
_DataTypeCheckbox( _DataTypeCheckbox(
label: 'Site Data', label: 'Site Data',
@@ -99,14 +103,33 @@ class ClearSiteDataSection extends HookConsumerWidget {
isSelected: selectedTypes.value.contains(ClearDataType.allSiteData), isSelected: selectedTypes.value.contains(ClearDataType.allSiteData),
onChanged: (selected) => toggleType(ClearDataType.allSiteData), onChanged: (selected) => toggleType(ClearDataType.allSiteData),
), ),
_DataTypeCheckbox( Padding(
label: 'Auth Sessions', padding: const EdgeInsets.only(left: 16.0),
subtitle: 'Saved logins, active sessions', child: _DataTypeCheckbox(
type: ClearDataType.authSessions, label: 'Cookies',
isSelected: selectedTypes.value.contains( subtitle: 'Login tokens, preferences, tracking data',
ClearDataType.authSessions, type: ClearDataType.onlyCookies,
isSelected:
selectedTypes.value.contains(ClearDataType.allSiteData) ||
selectedTypes.value.contains(ClearDataType.onlyCookies),
onChanged: selectedTypes.value.contains(ClearDataType.allSiteData)
? null
: (selected) => toggleType(ClearDataType.onlyCookies),
),
),
Padding(
padding: const EdgeInsets.only(left: 16.0),
child: _DataTypeCheckbox(
label: 'Cached Files',
subtitle: 'Images, scripts, stylesheets',
type: ClearDataType.onlyCaches,
isSelected:
selectedTypes.value.contains(ClearDataType.allSiteData) ||
selectedTypes.value.contains(ClearDataType.onlyCaches),
onChanged: selectedTypes.value.contains(ClearDataType.allSiteData)
? null
: (selected) => toggleType(ClearDataType.onlyCaches),
), ),
onChanged: (selected) => toggleType(ClearDataType.authSessions),
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@@ -163,6 +186,7 @@ class ClearSiteDataSection extends HookConsumerWidget {
await _clearData(ref, selectedTypes); await _clearData(ref, selectedTypes);
if (context.mounted) { if (context.mounted) {
showInfoMessage(context, 'Site data cleared'); showInfoMessage(context, 'Site data cleared');
ref.read(bottomSheetControllerProvider.notifier).requestDismiss();
} }
} catch (e, s) { } catch (e, s) {
logger.e('Failed to clear site data', error: e, stackTrace: s); logger.e('Failed to clear site data', error: e, stackTrace: s);
@@ -178,9 +202,9 @@ class ClearSiteDataSection extends HookConsumerWidget {
String _formatTypes(Set<ClearDataType> types) { String _formatTypes(Set<ClearDataType> types) {
final labels = types.map((t) { final labels = types.map((t) {
switch (t) { switch (t) {
case ClearDataType.cookies: case ClearDataType.onlyCookies:
return 'cookies'; return 'cookies';
case ClearDataType.allCaches: case ClearDataType.onlyCaches:
return 'cached files'; return 'cached files';
case ClearDataType.allSiteData: case ClearDataType.allSiteData:
return 'site data'; return 'site data';
@@ -218,7 +242,7 @@ class _DataTypeCheckbox extends StatelessWidget {
final String subtitle; final String subtitle;
final ClearDataType type; final ClearDataType type;
final bool isSelected; final bool isSelected;
final ValueChanged<bool> onChanged; final ValueChanged<bool>? onChanged;
const _DataTypeCheckbox({ const _DataTypeCheckbox({
required this.label, required this.label,
@@ -234,7 +258,10 @@ class _DataTypeCheckbox extends StatelessWidget {
title: Text(label), title: Text(label),
subtitle: Text(subtitle), subtitle: Text(subtitle),
value: isSelected, value: isSelected,
onChanged: (value) => onChanged(value ?? false), onChanged: onChanged.mapNotNull(
(onChanged) =>
(value) => onChanged(value ?? false),
),
controlAffinity: ListTileControlAffinity.trailing, controlAffinity: ListTileControlAffinity.trailing,
); );
} }
@@ -6,6 +6,7 @@
package eu.weblibre.flutter_mozilla_components.api package eu.weblibre.flutter_mozilla_components.api
import androidx.core.net.toUri
import eu.weblibre.flutter_mozilla_components.GlobalComponents import eu.weblibre.flutter_mozilla_components.GlobalComponents
import eu.weblibre.flutter_mozilla_components.pigeons.ClearDataType import eu.weblibre.flutter_mozilla_components.pigeons.ClearDataType
import eu.weblibre.flutter_mozilla_components.pigeons.GeckoDeleteBrowsingDataController import eu.weblibre.flutter_mozilla_components.pigeons.GeckoDeleteBrowsingDataController
@@ -16,6 +17,9 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import mozilla.components.browser.state.action.EngineAction import mozilla.components.browser.state.action.EngineAction
import mozilla.components.browser.state.action.RecentlyClosedAction import mozilla.components.browser.state.action.RecentlyClosedAction
import mozilla.components.browser.state.selector.allTabs
import mozilla.components.browser.state.state.SessionState
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.concept.engine.Engine import mozilla.components.concept.engine.Engine
import mozilla.components.concept.engine.translate.ModelManagementOptions import mozilla.components.concept.engine.translate.ModelManagementOptions
import mozilla.components.concept.engine.translate.ModelOperation import mozilla.components.concept.engine.translate.ModelOperation
@@ -30,6 +34,29 @@ class GeckoDeleteBrowsingDataControllerImpl : GeckoDeleteBrowsingDataController
requireNotNull(GlobalComponents.components) { "Components not initialized" } requireNotNull(GlobalComponents.components) { "Components not initialized" }
} }
/**
* GeckoView's storage clearing APIs warn that any open session may re-accumulate
* previously cleared data. We synchronously close the underlying [EngineSession]
* (so its in-memory cookie/storage state is torn down before the clear runs) and
* then unlink it from the browser store. The next reload spins up a fresh engine
* session that reads from the cleared storage.
*
* NOTE: We deliberately don't use [EngineAction.SuspendEngineSessionAction] here -
* its middleware runs `engineSession.close()` inside a `scope.launch`, racing with
* the `clearData` call we're about to issue.
*/
private fun closeMatchingSessions(
store: BrowserStore,
predicate: (SessionState) -> Boolean,
) {
val tabs = store.state.allTabs.filter {
it.engineState.engineSession != null && predicate(it)
}
tabs.forEach { it.engineState.engineSession?.close() }
tabs.forEach { store.dispatch(EngineAction.UnlinkEngineSessionAction(it.id)) }
}
override fun deleteTabs(callback: (Result<Unit>) -> Unit) { override fun deleteTabs(callback: (Result<Unit>) -> Unit) {
coroutineScope.launch { coroutineScope.launch {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
@@ -56,15 +83,22 @@ class GeckoDeleteBrowsingDataControllerImpl : GeckoDeleteBrowsingDataController
override fun deleteCookiesAndSiteData(callback: (Result<Unit>) -> Unit) { override fun deleteCookiesAndSiteData(callback: (Result<Unit>) -> Unit) {
coroutineScope.launch { coroutineScope.launch {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
closeMatchingSessions(components.core.store) { true }
components.core.engine.clearData( components.core.engine.clearData(
Engine.BrowsingData.select( Engine.BrowsingData.select(
Engine.BrowsingData.COOKIES, Engine.BrowsingData.COOKIES,
Engine.BrowsingData.AUTH_SESSIONS, Engine.BrowsingData.AUTH_SESSIONS,
), ),
onSuccess = {
components.core.engine.clearData(
Engine.BrowsingData.select(Engine.BrowsingData.DOM_STORAGES),
onSuccess = { callback(Result.success(Unit)) },
onError = { callback(Result.failure(it)) },
)
},
onError = { callback(Result.failure(it)) },
) )
components.core.engine.clearData(Engine.BrowsingData.select(Engine.BrowsingData.DOM_STORAGES))
callback(Result.success(Unit))
} }
} }
} }
@@ -82,9 +116,9 @@ class GeckoDeleteBrowsingDataControllerImpl : GeckoDeleteBrowsingDataController
) )
components.core.engine.clearData( components.core.engine.clearData(
Engine.BrowsingData.select(Engine.BrowsingData.ALL_CACHES), Engine.BrowsingData.select(Engine.BrowsingData.ALL_CACHES),
onSuccess = { callback(Result.success(Unit)) },
onError = { callback(Result.failure(it)) },
) )
callback(Result.success(Unit))
} }
} }
} }
@@ -94,10 +128,18 @@ class GeckoDeleteBrowsingDataControllerImpl : GeckoDeleteBrowsingDataController
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
components.core.engine.clearData( components.core.engine.clearData(
Engine.BrowsingData.select(Engine.BrowsingData.ALL_SITE_SETTINGS), Engine.BrowsingData.select(Engine.BrowsingData.ALL_SITE_SETTINGS),
onSuccess = {
coroutineScope.launch {
try {
components.core.permissionStorage.deleteAllSitePermissions()
callback(Result.success(Unit))
} catch (e: Throwable) {
callback(Result.failure(e))
}
}
},
onError = { callback(Result.failure(it)) },
) )
components.core.permissionStorage.deleteAllSitePermissions()
callback(Result.success(Unit))
} }
} }
} }
@@ -118,6 +160,14 @@ class GeckoDeleteBrowsingDataControllerImpl : GeckoDeleteBrowsingDataController
) { ) {
coroutineScope.launch { coroutineScope.launch {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
// Detach engine sessions for any tab in this context so they don't
// re-accumulate data while the (fire-and-forget) clear is processed.
closeMatchingSessions(components.core.store) { it.contextId == contextId }
// GeckoView's clearDataForSessionContext uses dispatch (fire-and-forget),
// so there's no completion signal we can chain against. Fire it and
// signal completion immediately - by suspending matching sessions above
// we've at least ensured the operation can take effect.
components.core.runtime.storageController.clearDataForSessionContext(contextId) components.core.runtime.storageController.clearDataForSessionContext(contextId)
callback(Result.success(Unit)) callback(Result.success(Unit))
@@ -133,17 +183,54 @@ class GeckoDeleteBrowsingDataControllerImpl : GeckoDeleteBrowsingDataController
coroutineScope.launch { coroutineScope.launch {
try { try {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (dataTypes.contains(ClearDataType.ALL_SITE_DATA) && (dataTypes.contains(
ClearDataType.ONLY_COOKIES
) || dataTypes.contains(ClearDataType.ONLY_CACHES))
) {
callback(Result.failure(Exception("Cookies/Cache must be exclusively!")))
}
// Convert ClearDataType to Engine.BrowsingData flags // Convert ClearDataType to Engine.BrowsingData flags
val browsingDataTypes = dataTypes.map { dataType -> val browsingDataTypes = dataTypes.map { dataType ->
when (dataType) { when (dataType) {
ClearDataType.AUTH_SESSIONS -> Engine.BrowsingData.AUTH_SESSIONS ClearDataType.AUTH_SESSIONS -> Engine.BrowsingData.AUTH_SESSIONS
ClearDataType.ALL_SITE_DATA -> Engine.BrowsingData.ALL_SITE_DATA ClearDataType.ALL_SITE_DATA -> Engine.BrowsingData.ALL_SITE_DATA
ClearDataType.COOKIES -> Engine.BrowsingData.COOKIES ClearDataType.ONLY_COOKIES -> Engine.BrowsingData.COOKIES
ClearDataType.ALL_CACHES -> Engine.BrowsingData.ALL_CACHES ClearDataType.ONLY_CACHES -> Engine.BrowsingData.ALL_CACHES
} }
}.toIntArray() }.toIntArray()
// Clear data for the specific host // Find tabs on this host (so we can detach their engine sessions and
// also discover any container/contextId partitions that need clearing).
val matchingTabs = components.core.store.state.allTabs.filter { tab ->
val tabHost = runCatching { tab.content.url.toUri().host }.getOrNull()
?: return@filter false
tabHost == host || tabHost.endsWith(".$host")
}
// GeckoView warns that open sessions may re-accumulate previously
// cleared data. Close them synchronously before clearing.
matchingTabs.forEach { it.engineState.engineSession?.close() }
matchingTabs.forEach {
components.core.store.dispatch(EngineAction.UnlinkEngineSessionAction(it.id))
}
// GeckoView's clearDataFromBaseDomain (used by engine.clearData(host=))
// only targets the default origin attributes partition. Tabs that live
// inside a contextual identity ("container") store their cookies/storage
// under a `geckoViewSessionContextId` origin attribute that the
// base-domain clear does not touch. To make clearing actually effective
// for container tabs, also fire clearDataForSessionContext for any
// contextIds we found. This is broader than ideal (it clears the whole
// container, not just this host) but there is no GeckoView API to
// combine host + context.
val contextIds = matchingTabs.mapNotNull { it.contextId }.toSet()
contextIds.forEach { contextId ->
components.core.runtime.storageController
.clearDataForSessionContext(contextId)
}
// Clear data for the specific host (default partition).
components.core.engine.clearData( components.core.engine.clearData(
data = Engine.BrowsingData.select(*browsingDataTypes), data = Engine.BrowsingData.select(*browsingDataTypes),
host = host, host = host,
@@ -160,4 +247,4 @@ class GeckoDeleteBrowsingDataControllerImpl : GeckoDeleteBrowsingDataController
} }
} }
} }
} }
@@ -681,12 +681,15 @@ enum class MlProgressStatus(val raw: Int) {
enum class ClearDataType(val raw: Int) { enum class ClearDataType(val raw: Int) {
/** Authentication sessions */ /** Authentication sessions */
AUTH_SESSIONS(0), AUTH_SESSIONS(0),
/** All site data (cookies, storage, etc.) */ /**
* All site data (cookies, storage, etc.)
* WARNING: If this is set it already includes cookies and allCaches. Passing the additionally will lead to issues
*/
ALL_SITE_DATA(1), ALL_SITE_DATA(1),
/** Cookies only */ /** Cookies only */
COOKIES(2), ONLY_COOKIES(2),
/** Cache only */ /** Cache only */
ALL_CACHES(3); ONLY_CACHES(3);
companion object { companion object {
fun ofRaw(raw: Int): ClearDataType? { fun ofRaw(raw: Int): ClearDataType? {
File diff suppressed because it is too large Load Diff
@@ -2087,13 +2087,14 @@ enum ClearDataType {
authSessions, authSessions,
/// All site data (cookies, storage, etc.) /// All site data (cookies, storage, etc.)
/// WARNING: If this is set it already includes cookies and allCaches. Passing the additionally will lead to issues
allSiteData, allSiteData,
/// Cookies only /// Cookies only
cookies, onlyCookies,
/// Cache only /// Cache only
allCaches, onlyCaches,
} }
@HostApi() @HostApi()
+78 -123
View File
@@ -10,9 +10,9 @@ import 'package:flutter/services.dart';
import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; import 'package:meta/meta.dart' show immutable, protected, visibleForTesting;
Object? _extractReplyValueOrThrow( Object? _extractReplyValueOrThrow(
List<Object?>? replyList, List<Object?>? replyList,
String channelName, { String channelName, {
required bool isNullValid, required bool isNullValid,
}) { }) {
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
@@ -34,11 +34,8 @@ Object? _extractReplyValueOrThrow(
return replyList.firstOrNull; return replyList.firstOrNull;
} }
List<Object?> wrapResponse({
Object? result, List<Object?> wrapResponse({Object? result, PlatformException? error, bool empty = false}) {
PlatformException? error,
bool empty = false,
}) {
if (empty) { if (empty) {
return <Object?>[]; return <Object?>[];
} }
@@ -47,7 +44,6 @@ List<Object?> wrapResponse({
} }
return <Object?>[error.code, error.message, error.details]; return <Object?>[error.code, error.message, error.details];
} }
bool _deepEquals(Object? a, Object? b) { bool _deepEquals(Object? a, Object? b) {
if (identical(a, b)) { if (identical(a, b)) {
return true; return true;
@@ -60,9 +56,8 @@ bool _deepEquals(Object? a, Object? b) {
} }
if (a is List && b is List) { if (a is List && b is List) {
return a.length == b.length && return a.length == b.length &&
a.indexed.every( a.indexed
((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]), .every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]));
);
} }
if (a is Map && b is Map) { if (a is Map && b is Map) {
if (a.length != b.length) { if (a.length != b.length) {
@@ -111,29 +106,23 @@ int _deepHash(Object? value) {
return value.hashCode; return value.hashCode;
} }
/// Transport types for Tor connections /// Transport types for Tor connections
enum TransportType { enum TransportType {
/// Direct Tor connection (no bridges) /// Direct Tor connection (no bridges)
none, none,
/// obfs4 pluggable transport /// obfs4 pluggable transport
obfs4, obfs4,
/// Snowflake pluggable transport (default broker) /// Snowflake pluggable transport (default broker)
snowflake, snowflake,
/// Snowflake via AMP cache /// Snowflake via AMP cache
snowflakeAmp, snowflakeAmp,
/// Meek pluggable transport /// Meek pluggable transport
meek, meek,
/// Meek via Azure CDN /// Meek via Azure CDN
meekAzure, meekAzure,
/// WebTunnel pluggable transport /// WebTunnel pluggable transport
webtunnel, webtunnel,
/// Custom bridge lines (passthrough) /// Custom bridge lines (passthrough)
custom, custom,
} }
@@ -174,8 +163,7 @@ class TorConfiguration {
} }
Object encode() { Object encode() {
return _toList(); return _toList(); }
}
static TorConfiguration decode(Object result) { static TorConfiguration decode(Object result) {
result as List<Object?>; result as List<Object?>;
@@ -197,11 +185,7 @@ class TorConfiguration {
if (identical(this, other)) { if (identical(this, other)) {
return true; return true;
} }
return _deepEquals(transport, other.transport) && return _deepEquals(transport, other.transport) && _deepEquals(bridgeLines, other.bridgeLines) && _deepEquals(entryNodeCountries, other.entryNodeCountries) && _deepEquals(exitNodeCountries, other.exitNodeCountries) && _deepEquals(strictNodes, other.strictNodes);
_deepEquals(bridgeLines, other.bridgeLines) &&
_deepEquals(entryNodeCountries, other.entryNodeCountries) &&
_deepEquals(exitNodeCountries, other.exitNodeCountries) &&
_deepEquals(strictNodes, other.strictNodes);
} }
@override @override
@@ -245,8 +229,7 @@ class TorStatus {
} }
Object encode() { Object encode() {
return _toList(); return _toList(); }
}
static TorStatus decode(Object result) { static TorStatus decode(Object result) {
result as List<Object?>; result as List<Object?>;
@@ -268,11 +251,7 @@ class TorStatus {
if (identical(this, other)) { if (identical(this, other)) {
return true; return true;
} }
return _deepEquals(isRunning, other.isRunning) && return _deepEquals(isRunning, other.isRunning) && _deepEquals(socksPort, other.socksPort) && _deepEquals(bootstrapProgress, other.bootstrapProgress) && _deepEquals(currentCircuit, other.currentCircuit) && _deepEquals(exitNodeCountry, other.exitNodeCountry);
_deepEquals(socksPort, other.socksPort) &&
_deepEquals(bootstrapProgress, other.bootstrapProgress) &&
_deepEquals(currentCircuit, other.currentCircuit) &&
_deepEquals(exitNodeCountry, other.exitNodeCountry);
} }
@override @override
@@ -298,12 +277,15 @@ class TorLogMessage {
int timestamp; int timestamp;
List<Object?> _toList() { List<Object?> _toList() {
return <Object?>[severity, message, timestamp]; return <Object?>[
severity,
message,
timestamp,
];
} }
Object encode() { Object encode() {
return _toList(); return _toList(); }
}
static TorLogMessage decode(Object result) { static TorLogMessage decode(Object result) {
result as List<Object?>; result as List<Object?>;
@@ -323,9 +305,7 @@ class TorLogMessage {
if (identical(this, other)) { if (identical(this, other)) {
return true; return true;
} }
return _deepEquals(severity, other.severity) && return _deepEquals(severity, other.severity) && _deepEquals(message, other.message) && _deepEquals(timestamp, other.timestamp);
_deepEquals(message, other.message) &&
_deepEquals(timestamp, other.timestamp);
} }
@override @override
@@ -333,6 +313,7 @@ class TorLogMessage {
int get hashCode => _deepHash(<Object?>[runtimeType, ..._toList()]); int get hashCode => _deepHash(<Object?>[runtimeType, ..._toList()]);
} }
class _PigeonCodec extends StandardMessageCodec { class _PigeonCodec extends StandardMessageCodec {
const _PigeonCodec(); const _PigeonCodec();
@override @override
@@ -340,16 +321,16 @@ class _PigeonCodec extends StandardMessageCodec {
if (value is int) { if (value is int) {
buffer.putUint8(4); buffer.putUint8(4);
buffer.putInt64(value); buffer.putInt64(value);
} else if (value is TransportType) { } else if (value is TransportType) {
buffer.putUint8(129); buffer.putUint8(129);
writeValue(buffer, value.index); writeValue(buffer, value.index);
} else if (value is TorConfiguration) { } else if (value is TorConfiguration) {
buffer.putUint8(130); buffer.putUint8(130);
writeValue(buffer, value.encode()); writeValue(buffer, value.encode());
} else if (value is TorStatus) { } else if (value is TorStatus) {
buffer.putUint8(131); buffer.putUint8(131);
writeValue(buffer, value.encode()); writeValue(buffer, value.encode());
} else if (value is TorLogMessage) { } else if (value is TorLogMessage) {
buffer.putUint8(132); buffer.putUint8(132);
writeValue(buffer, value.encode()); writeValue(buffer, value.encode());
} else { } else {
@@ -381,10 +362,8 @@ class TorApi {
/// available for dependency injection. If it is left null, the default /// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform. /// BinaryMessenger will be used which routes to the host platform.
TorApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) TorApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
: pigeonVar_binaryMessenger = binaryMessenger, : pigeonVar_binaryMessenger = binaryMessenger,
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
? '.$messageChannelSuffix'
: '';
final BinaryMessenger? pigeonVar_binaryMessenger; final BinaryMessenger? pigeonVar_binaryMessenger;
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec(); static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
@@ -394,30 +373,27 @@ class TorApi {
/// Start Tor with the given configuration /// Start Tor with the given configuration
/// Returns a Future to avoid blocking the main thread /// Returns a Future to avoid blocking the main thread
Future<int> startTor(TorConfiguration config) async { Future<int> startTor(TorConfiguration config) async {
final pigeonVar_channelName = final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.TorApi.startTor$pigeonVar_messageChannelSuffix';
'dev.flutter.pigeon.flutter_tor.TorApi.startTor$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send( final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[config]);
<Object?>[config],
);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?; final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( final Object? pigeonVar_replyValue = _extractReplyValueOrThrow(
pigeonVar_replyList, pigeonVar_replyList,
pigeonVar_channelName, pigeonVar_channelName,
isNullValid: false, isNullValid: false,
); )
;
return pigeonVar_replyValue! as int; return pigeonVar_replyValue! as int;
} }
/// Stop Tor /// Stop Tor
Future<void> stopTor() async { Future<void> stopTor() async {
final pigeonVar_channelName = final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.TorApi.stopTor$pigeonVar_messageChannelSuffix';
'dev.flutter.pigeon.flutter_tor.TorApi.stopTor$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
@@ -427,16 +403,16 @@ class TorApi {
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?; final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
_extractReplyValueOrThrow( _extractReplyValueOrThrow(
pigeonVar_replyList, pigeonVar_replyList,
pigeonVar_channelName, pigeonVar_channelName,
isNullValid: true, isNullValid: true,
); )
;
} }
/// Get current status /// Get current status
Future<TorStatus> getStatus() async { Future<TorStatus> getStatus() async {
final pigeonVar_channelName = final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.TorApi.getStatus$pigeonVar_messageChannelSuffix';
'dev.flutter.pigeon.flutter_tor.TorApi.getStatus$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
@@ -446,17 +422,17 @@ class TorApi {
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?; final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( final Object? pigeonVar_replyValue = _extractReplyValueOrThrow(
pigeonVar_replyList, pigeonVar_replyList,
pigeonVar_channelName, pigeonVar_channelName,
isNullValid: false, isNullValid: false,
); )
;
return pigeonVar_replyValue! as TorStatus; return pigeonVar_replyValue! as TorStatus;
} }
/// Request a new Tor identity (new circuit) /// Request a new Tor identity (new circuit)
Future<void> requestNewIdentity() async { Future<void> requestNewIdentity() async {
final pigeonVar_channelName = final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.TorApi.requestNewIdentity$pigeonVar_messageChannelSuffix';
'dev.flutter.pigeon.flutter_tor.TorApi.requestNewIdentity$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
@@ -466,10 +442,11 @@ class TorApi {
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?; final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
_extractReplyValueOrThrow( _extractReplyValueOrThrow(
pigeonVar_replyList, pigeonVar_replyList,
pigeonVar_channelName, pigeonVar_channelName,
isNullValid: true, isNullValid: true,
); )
;
} }
} }
@@ -483,20 +460,12 @@ abstract class TorLogApi {
/// Called when status changes /// Called when status changes
void onStatusChanged(TorStatus status); void onStatusChanged(TorStatus status);
static void setUp( static void setUp(TorLogApi? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) {
TorLogApi? api, { messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
BinaryMessenger? binaryMessenger,
String messageChannelSuffix = '',
}) {
messageChannelSuffix = messageChannelSuffix.isNotEmpty
? '.$messageChannelSuffix'
: '';
{ {
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.flutter_tor.TorLogApi.onLogMessage$messageChannelSuffix', 'dev.flutter.pigeon.flutter_tor.TorLogApi.onLogMessage$messageChannelSuffix', pigeonChannelCodec,
pigeonChannelCodec, binaryMessenger: binaryMessenger);
binaryMessenger: binaryMessenger,
);
if (api == null) { if (api == null) {
pigeonVar_channel.setMessageHandler(null); pigeonVar_channel.setMessageHandler(null);
} else { } else {
@@ -508,20 +477,16 @@ abstract class TorLogApi {
return wrapResponse(empty: true); return wrapResponse(empty: true);
} on PlatformException catch (e) { } on PlatformException catch (e) {
return wrapResponse(error: e); return wrapResponse(error: e);
} catch (e) { } catch (e) {
return wrapResponse( return wrapResponse(error: PlatformException(code: 'error', message: e.toString()));
error: PlatformException(code: 'error', message: e.toString()),
);
} }
}); });
} }
} }
{ {
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.flutter_tor.TorLogApi.onStatusChanged$messageChannelSuffix', 'dev.flutter.pigeon.flutter_tor.TorLogApi.onStatusChanged$messageChannelSuffix', pigeonChannelCodec,
pigeonChannelCodec, binaryMessenger: binaryMessenger);
binaryMessenger: binaryMessenger,
);
if (api == null) { if (api == null) {
pigeonVar_channel.setMessageHandler(null); pigeonVar_channel.setMessageHandler(null);
} else { } else {
@@ -533,10 +498,8 @@ abstract class TorLogApi {
return wrapResponse(empty: true); return wrapResponse(empty: true);
} on PlatformException catch (e) { } on PlatformException catch (e) {
return wrapResponse(error: e); return wrapResponse(error: e);
} catch (e) { } catch (e) {
return wrapResponse( return wrapResponse(error: PlatformException(code: 'error', message: e.toString()));
error: PlatformException(code: 'error', message: e.toString()),
);
} }
}); });
} }
@@ -548,13 +511,9 @@ class IPtProxyController {
/// Constructor for [IPtProxyController]. The [binaryMessenger] named argument is /// Constructor for [IPtProxyController]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default /// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform. /// BinaryMessenger will be used which routes to the host platform.
IPtProxyController({ IPtProxyController({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
BinaryMessenger? binaryMessenger, : pigeonVar_binaryMessenger = binaryMessenger,
String messageChannelSuffix = '', pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
}) : pigeonVar_binaryMessenger = binaryMessenger,
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty
? '.$messageChannelSuffix'
: '';
final BinaryMessenger? pigeonVar_binaryMessenger; final BinaryMessenger? pigeonVar_binaryMessenger;
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec(); static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
@@ -562,43 +521,39 @@ class IPtProxyController {
final String pigeonVar_messageChannelSuffix; final String pigeonVar_messageChannelSuffix;
Future<int> start(TransportType proxyType, String proxy) async { Future<int> start(TransportType proxyType, String proxy) async {
final pigeonVar_channelName = final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.IPtProxyController.start$pigeonVar_messageChannelSuffix';
'dev.flutter.pigeon.flutter_tor.IPtProxyController.start$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send( final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[proxyType, proxy]);
<Object?>[proxyType, proxy],
);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?; final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( final Object? pigeonVar_replyValue = _extractReplyValueOrThrow(
pigeonVar_replyList, pigeonVar_replyList,
pigeonVar_channelName, pigeonVar_channelName,
isNullValid: false, isNullValid: false,
); )
;
return pigeonVar_replyValue! as int; return pigeonVar_replyValue! as int;
} }
Future<void> stop(TransportType proxyType) async { Future<void> stop(TransportType proxyType) async {
final pigeonVar_channelName = final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.IPtProxyController.stop$pigeonVar_messageChannelSuffix';
'dev.flutter.pigeon.flutter_tor.IPtProxyController.stop$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send( final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[proxyType]);
<Object?>[proxyType],
);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?; final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
_extractReplyValueOrThrow( _extractReplyValueOrThrow(
pigeonVar_replyList, pigeonVar_replyList,
pigeonVar_channelName, pigeonVar_channelName,
isNullValid: true, isNullValid: true,
); )
;
} }
} }
@@ -10,9 +10,9 @@ import 'package:flutter/services.dart';
import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; import 'package:meta/meta.dart' show immutable, protected, visibleForTesting;
Object? _extractReplyValueOrThrow( Object? _extractReplyValueOrThrow(
List<Object?>? replyList, List<Object?>? replyList,
String channelName, { String channelName, {
required bool isNullValid, required bool isNullValid,
}) { }) {
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
@@ -46,9 +46,8 @@ bool _deepEquals(Object? a, Object? b) {
} }
if (a is List && b is List) { if (a is List && b is List) {
return a.length == b.length && return a.length == b.length &&
a.indexed.every( a.indexed
((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]), .every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]));
);
} }
if (a is Map && b is Map) { if (a is Map && b is Map) {
if (a.length != b.length) { if (a.length != b.length) {
@@ -97,20 +96,26 @@ int _deepHash(Object? value) {
return value.hashCode; return value.hashCode;
} }
class LocalizedResult { class LocalizedResult {
LocalizedResult({required this.languageName, this.countryName}); LocalizedResult({
required this.languageName,
this.countryName,
});
String languageName; String languageName;
String? countryName; String? countryName;
List<Object?> _toList() { List<Object?> _toList() {
return <Object?>[languageName, countryName]; return <Object?>[
languageName,
countryName,
];
} }
Object encode() { Object encode() {
return _toList(); return _toList(); }
}
static LocalizedResult decode(Object result) { static LocalizedResult decode(Object result) {
result as List<Object?>; result as List<Object?>;
@@ -129,8 +134,7 @@ class LocalizedResult {
if (identical(this, other)) { if (identical(this, other)) {
return true; return true;
} }
return _deepEquals(languageName, other.languageName) && return _deepEquals(languageName, other.languageName) && _deepEquals(countryName, other.countryName);
_deepEquals(countryName, other.countryName);
} }
@override @override
@@ -138,6 +142,7 @@ class LocalizedResult {
int get hashCode => _deepHash(<Object?>[runtimeType, ..._toList()]); int get hashCode => _deepHash(<Object?>[runtimeType, ..._toList()]);
} }
class _PigeonCodec extends StandardMessageCodec { class _PigeonCodec extends StandardMessageCodec {
const _PigeonCodec(); const _PigeonCodec();
@override @override
@@ -145,7 +150,7 @@ class _PigeonCodec extends StandardMessageCodec {
if (value is int) { if (value is int) {
buffer.putUint8(4); buffer.putUint8(4);
buffer.putInt64(value); buffer.putInt64(value);
} else if (value is LocalizedResult) { } else if (value is LocalizedResult) {
buffer.putUint8(129); buffer.putUint8(129);
writeValue(buffer, value.encode()); writeValue(buffer, value.encode());
} else { } else {
@@ -168,40 +173,31 @@ class LocaleResolver {
/// Constructor for [LocaleResolver]. The [binaryMessenger] named argument is /// Constructor for [LocaleResolver]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default /// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform. /// BinaryMessenger will be used which routes to the host platform.
LocaleResolver({ LocaleResolver({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
BinaryMessenger? binaryMessenger, : pigeonVar_binaryMessenger = binaryMessenger,
String messageChannelSuffix = '', pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
}) : pigeonVar_binaryMessenger = binaryMessenger,
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty
? '.$messageChannelSuffix'
: '';
final BinaryMessenger? pigeonVar_binaryMessenger; final BinaryMessenger? pigeonVar_binaryMessenger;
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec(); static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
final String pigeonVar_messageChannelSuffix; final String pigeonVar_messageChannelSuffix;
Future<LocalizedResult> resolve( Future<LocalizedResult> resolve(String languageTag, String targetLangouageTag) async {
String languageTag, final pigeonVar_channelName = 'dev.flutter.pigeon.locale_resolver.LocaleResolver.resolve$pigeonVar_messageChannelSuffix';
String targetLangouageTag,
) async {
final pigeonVar_channelName =
'dev.flutter.pigeon.locale_resolver.LocaleResolver.resolve$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send( final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[languageTag, targetLangouageTag]);
<Object?>[languageTag, targetLangouageTag],
);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?; final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( final Object? pigeonVar_replyValue = _extractReplyValueOrThrow(
pigeonVar_replyList, pigeonVar_replyList,
pigeonVar_channelName, pigeonVar_channelName,
isNullValid: false, isNullValid: false,
); )
;
return pigeonVar_replyValue! as LocalizedResult; return pigeonVar_replyValue! as LocalizedResult;
} }
} }
@@ -10,9 +10,9 @@ import 'package:flutter/services.dart';
import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; import 'package:meta/meta.dart' show immutable, protected, visibleForTesting;
Object? _extractReplyValueOrThrow( Object? _extractReplyValueOrThrow(
List<Object?>? replyList, List<Object?>? replyList,
String channelName, { String channelName, {
required bool isNullValid, required bool isNullValid,
}) { }) {
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
@@ -34,11 +34,8 @@ Object? _extractReplyValueOrThrow(
return replyList.firstOrNull; return replyList.firstOrNull;
} }
List<Object?> wrapResponse({
Object? result, List<Object?> wrapResponse({Object? result, PlatformException? error, bool empty = false}) {
PlatformException? error,
bool empty = false,
}) {
if (empty) { if (empty) {
return <Object?>[]; return <Object?>[];
} }
@@ -47,7 +44,6 @@ List<Object?> wrapResponse({
} }
return <Object?>[error.code, error.message, error.details]; return <Object?>[error.code, error.message, error.details];
} }
bool _deepEquals(Object? a, Object? b) { bool _deepEquals(Object? a, Object? b) {
if (identical(a, b)) { if (identical(a, b)) {
return true; return true;
@@ -60,9 +56,8 @@ bool _deepEquals(Object? a, Object? b) {
} }
if (a is List && b is List) { if (a is List && b is List) {
return a.length == b.length && return a.length == b.length &&
a.indexed.every( a.indexed
((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]), .every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]));
);
} }
if (a is Map && b is Map) { if (a is Map && b is Map) {
if (a.length != b.length) { if (a.length != b.length) {
@@ -111,6 +106,7 @@ int _deepHash(Object? value) {
return value.hashCode; return value.hashCode;
} }
class Intent { class Intent {
Intent({ Intent({
this.fromPackageName, this.fromPackageName,
@@ -145,8 +141,7 @@ class Intent {
} }
Object encode() { Object encode() {
return _toList(); return _toList(); }
}
static Intent decode(Object result) { static Intent decode(Object result) {
result as List<Object?>; result as List<Object?>;
@@ -169,12 +164,7 @@ class Intent {
if (identical(this, other)) { if (identical(this, other)) {
return true; return true;
} }
return _deepEquals(fromPackageName, other.fromPackageName) && return _deepEquals(fromPackageName, other.fromPackageName) && _deepEquals(action, other.action) && _deepEquals(data, other.data) && _deepEquals(categories, other.categories) && _deepEquals(mimeType, other.mimeType) && _deepEquals(extra, other.extra);
_deepEquals(action, other.action) &&
_deepEquals(data, other.data) &&
_deepEquals(categories, other.categories) &&
_deepEquals(mimeType, other.mimeType) &&
_deepEquals(extra, other.extra);
} }
@override @override
@@ -182,6 +172,7 @@ class Intent {
int get hashCode => _deepHash(<Object?>[runtimeType, ..._toList()]); int get hashCode => _deepHash(<Object?>[runtimeType, ..._toList()]);
} }
class _PigeonCodec extends StandardMessageCodec { class _PigeonCodec extends StandardMessageCodec {
const _PigeonCodec(); const _PigeonCodec();
@override @override
@@ -189,7 +180,7 @@ class _PigeonCodec extends StandardMessageCodec {
if (value is int) { if (value is int) {
buffer.putUint8(4); buffer.putUint8(4);
buffer.putInt64(value); buffer.putInt64(value);
} else if (value is Intent) { } else if (value is Intent) {
buffer.putUint8(129); buffer.putUint8(129);
writeValue(buffer, value.encode()); writeValue(buffer, value.encode());
} else { } else {
@@ -213,20 +204,12 @@ abstract class IntentEvents {
void onIntentReceived(int sequence, Intent intent); void onIntentReceived(int sequence, Intent intent);
static void setUp( static void setUp(IntentEvents? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) {
IntentEvents? api, { messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
BinaryMessenger? binaryMessenger,
String messageChannelSuffix = '',
}) {
messageChannelSuffix = messageChannelSuffix.isNotEmpty
? '.$messageChannelSuffix'
: '';
{ {
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.simple_intent_receiver.IntentEvents.onIntentReceived$messageChannelSuffix', 'dev.flutter.pigeon.simple_intent_receiver.IntentEvents.onIntentReceived$messageChannelSuffix', pigeonChannelCodec,
pigeonChannelCodec, binaryMessenger: binaryMessenger);
binaryMessenger: binaryMessenger,
);
if (api == null) { if (api == null) {
pigeonVar_channel.setMessageHandler(null); pigeonVar_channel.setMessageHandler(null);
} else { } else {
@@ -239,10 +222,8 @@ abstract class IntentEvents {
return wrapResponse(empty: true); return wrapResponse(empty: true);
} on PlatformException catch (e) { } on PlatformException catch (e) {
return wrapResponse(error: e); return wrapResponse(error: e);
} catch (e) { } catch (e) {
return wrapResponse( return wrapResponse(error: PlatformException(code: 'error', message: e.toString()));
error: PlatformException(code: 'error', message: e.toString()),
);
} }
}); });
} }
@@ -254,13 +235,9 @@ class IntentGatekeeperHostApi {
/// Constructor for [IntentGatekeeperHostApi]. The [binaryMessenger] named argument is /// Constructor for [IntentGatekeeperHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default /// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform. /// BinaryMessenger will be used which routes to the host platform.
IntentGatekeeperHostApi({ IntentGatekeeperHostApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
BinaryMessenger? binaryMessenger, : pigeonVar_binaryMessenger = binaryMessenger,
String messageChannelSuffix = '', pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
}) : pigeonVar_binaryMessenger = binaryMessenger,
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty
? '.$messageChannelSuffix'
: '';
final BinaryMessenger? pigeonVar_binaryMessenger; final BinaryMessenger? pigeonVar_binaryMessenger;
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec(); static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
@@ -270,46 +247,42 @@ class IntentGatekeeperHostApi {
/// Replicates the blocked-packages policy to the native side so the /// Replicates the blocked-packages policy to the native side so the
/// [IntentReceiverActivity] can reject intents without launching Flutter. /// [IntentReceiverActivity] can reject intents without launching Flutter.
Future<void> setConfig(bool enabled, List<String> blockedPackages) async { Future<void> setConfig(bool enabled, List<String> blockedPackages) async {
final pigeonVar_channelName = final pigeonVar_channelName = 'dev.flutter.pigeon.simple_intent_receiver.IntentGatekeeperHostApi.setConfig$pigeonVar_messageChannelSuffix';
'dev.flutter.pigeon.simple_intent_receiver.IntentGatekeeperHostApi.setConfig$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send( final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[enabled, blockedPackages]);
<Object?>[enabled, blockedPackages],
);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?; final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
_extractReplyValueOrThrow( _extractReplyValueOrThrow(
pigeonVar_replyList, pigeonVar_replyList,
pigeonVar_channelName, pigeonVar_channelName,
isNullValid: true, isNullValid: true,
); )
;
} }
/// Resolves a package name to its user-visible application label via /// Resolves a package name to its user-visible application label via
/// [PackageManager]. Returns `null` if the package is not installed or the /// [PackageManager]. Returns `null` if the package is not installed or the
/// label cannot be resolved. /// label cannot be resolved.
Future<String?> resolvePackageLabel(String packageName) async { Future<String?> resolvePackageLabel(String packageName) async {
final pigeonVar_channelName = final pigeonVar_channelName = 'dev.flutter.pigeon.simple_intent_receiver.IntentGatekeeperHostApi.resolvePackageLabel$pigeonVar_messageChannelSuffix';
'dev.flutter.pigeon.simple_intent_receiver.IntentGatekeeperHostApi.resolvePackageLabel$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send( final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[packageName]);
<Object?>[packageName],
);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?; final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( final Object? pigeonVar_replyValue = _extractReplyValueOrThrow(
pigeonVar_replyList, pigeonVar_replyList,
pigeonVar_channelName, pigeonVar_channelName,
isNullValid: true, isNullValid: true,
); )
;
return pigeonVar_replyValue as String?; return pigeonVar_replyValue as String?;
} }
@@ -319,8 +292,7 @@ class IntentGatekeeperHostApi {
/// [ackPendingAlwaysAllows] after Flutter settings were updated /// [ackPendingAlwaysAllows] after Flutter settings were updated
/// successfully. /// successfully.
Future<List<String>> getPendingAlwaysAllows() async { Future<List<String>> getPendingAlwaysAllows() async {
final pigeonVar_channelName = final pigeonVar_channelName = 'dev.flutter.pigeon.simple_intent_receiver.IntentGatekeeperHostApi.getPendingAlwaysAllows$pigeonVar_messageChannelSuffix';
'dev.flutter.pigeon.simple_intent_receiver.IntentGatekeeperHostApi.getPendingAlwaysAllows$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
@@ -330,32 +302,31 @@ class IntentGatekeeperHostApi {
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?; final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( final Object? pigeonVar_replyValue = _extractReplyValueOrThrow(
pigeonVar_replyList, pigeonVar_replyList,
pigeonVar_channelName, pigeonVar_channelName,
isNullValid: false, isNullValid: false,
); )
;
return (pigeonVar_replyValue! as List<Object?>).cast<String>(); return (pigeonVar_replyValue! as List<Object?>).cast<String>();
} }
/// Removes the given packages from the pending "Always allow" set after /// Removes the given packages from the pending "Always allow" set after
/// Flutter has successfully persisted them into its own policy store. /// Flutter has successfully persisted them into its own policy store.
Future<void> ackPendingAlwaysAllows(List<String> packageNames) async { Future<void> ackPendingAlwaysAllows(List<String> packageNames) async {
final pigeonVar_channelName = final pigeonVar_channelName = 'dev.flutter.pigeon.simple_intent_receiver.IntentGatekeeperHostApi.ackPendingAlwaysAllows$pigeonVar_messageChannelSuffix';
'dev.flutter.pigeon.simple_intent_receiver.IntentGatekeeperHostApi.ackPendingAlwaysAllows$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send( final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[packageNames]);
<Object?>[packageNames],
);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?; final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
_extractReplyValueOrThrow( _extractReplyValueOrThrow(
pigeonVar_replyList, pigeonVar_replyList,
pigeonVar_channelName, pigeonVar_channelName,
isNullValid: true, isNullValid: true,
); )
;
} }
} }
@@ -10,9 +10,9 @@ import 'package:flutter/services.dart';
import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; import 'package:meta/meta.dart' show immutable, protected, visibleForTesting;
Object? _extractReplyValueOrThrow( Object? _extractReplyValueOrThrow(
List<Object?>? replyList, List<Object?>? replyList,
String channelName, { String channelName, {
required bool isNullValid, required bool isNullValid,
}) { }) {
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
@@ -34,11 +34,8 @@ Object? _extractReplyValueOrThrow(
return replyList.firstOrNull; return replyList.firstOrNull;
} }
List<Object?> wrapResponse({
Object? result, List<Object?> wrapResponse({Object? result, PlatformException? error, bool empty = false}) {
PlatformException? error,
bool empty = false,
}) {
if (empty) { if (empty) {
return <Object?>[]; return <Object?>[];
} }
@@ -48,6 +45,7 @@ List<Object?> wrapResponse({
return <Object?>[error.code, error.message, error.details]; return <Object?>[error.code, error.message, error.details];
} }
class _PigeonCodec extends StandardMessageCodec { class _PigeonCodec extends StandardMessageCodec {
const _PigeonCodec(); const _PigeonCodec();
@override @override
@@ -74,13 +72,9 @@ class SpeechToTextApi {
/// Constructor for [SpeechToTextApi]. The [binaryMessenger] named argument is /// Constructor for [SpeechToTextApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default /// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform. /// BinaryMessenger will be used which routes to the host platform.
SpeechToTextApi({ SpeechToTextApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
BinaryMessenger? binaryMessenger, : pigeonVar_binaryMessenger = binaryMessenger,
String messageChannelSuffix = '', pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
}) : pigeonVar_binaryMessenger = binaryMessenger,
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty
? '.$messageChannelSuffix'
: '';
final BinaryMessenger? pigeonVar_binaryMessenger; final BinaryMessenger? pigeonVar_binaryMessenger;
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec(); static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
@@ -95,23 +89,21 @@ class SpeechToTextApi {
/// The [locale] parameter specifies the language locale for recognition /// The [locale] parameter specifies the language locale for recognition
/// (e.g., 'en-US', 'de-DE'). If null, uses the device default. /// (e.g., 'en-US', 'de-DE'). If null, uses the device default.
Future<bool> showDialog({String? locale}) async { Future<bool> showDialog({String? locale}) async {
final pigeonVar_channelName = final pigeonVar_channelName = 'dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextApi.showDialog$pigeonVar_messageChannelSuffix';
'dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextApi.showDialog$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send( final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[locale]);
<Object?>[locale],
);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?; final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( final Object? pigeonVar_replyValue = _extractReplyValueOrThrow(
pigeonVar_replyList, pigeonVar_replyList,
pigeonVar_channelName, pigeonVar_channelName,
isNullValid: false, isNullValid: false,
); )
;
return pigeonVar_replyValue! as bool; return pigeonVar_replyValue! as bool;
} }
} }
@@ -126,20 +118,12 @@ abstract class SpeechToTextEvents {
/// recognition failed or was cancelled. /// recognition failed or was cancelled.
void onTextReceived(String text); void onTextReceived(String text);
static void setUp( static void setUp(SpeechToTextEvents? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) {
SpeechToTextEvents? api, { messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
BinaryMessenger? binaryMessenger,
String messageChannelSuffix = '',
}) {
messageChannelSuffix = messageChannelSuffix.isNotEmpty
? '.$messageChannelSuffix'
: '';
{ {
final pigeonVar_channel = BasicMessageChannel<Object?>( final pigeonVar_channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextEvents.onTextReceived$messageChannelSuffix', 'dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextEvents.onTextReceived$messageChannelSuffix', pigeonChannelCodec,
pigeonChannelCodec, binaryMessenger: binaryMessenger);
binaryMessenger: binaryMessenger,
);
if (api == null) { if (api == null) {
pigeonVar_channel.setMessageHandler(null); pigeonVar_channel.setMessageHandler(null);
} else { } else {
@@ -151,10 +135,8 @@ abstract class SpeechToTextEvents {
return wrapResponse(empty: true); return wrapResponse(empty: true);
} on PlatformException catch (e) { } on PlatformException catch (e) {
return wrapResponse(error: e); return wrapResponse(error: e);
} catch (e) { } catch (e) {
return wrapResponse( return wrapResponse(error: PlatformException(code: 'error', message: e.toString()));
error: PlatformException(code: 'error', message: e.toString()),
);
} }
}); });
} }