added support for translations and printing
This commit is contained in:
+2
-2
@@ -227,8 +227,8 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
|
||||
|
||||
val engineView = createEngine(components)
|
||||
fragmentEngineView = engineView // Track for lifecycle management
|
||||
val originalContext = ActivityContextWrapper.getOriginalContext(requireActivity())
|
||||
?.let { ProfileContext(it, components.profileApplicationContext.relativePath) }
|
||||
val originalContext =
|
||||
ActivityContextWrapper.getOriginalContext(requireActivity()) ?: requireActivity()
|
||||
val engineNativeView = engineView.asView()
|
||||
engineNativeView.layoutParams = layoutParams
|
||||
|
||||
|
||||
+80
@@ -27,6 +27,9 @@ import eu.weblibre.flutter_mozilla_components.pigeons.ReaderableState
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.RestoreLocation
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.SecurityInfoState
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.TabContentState
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.TabTranslationStateData
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.TranslationEngineStateData
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.TranslationLanguage
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
@@ -39,6 +42,7 @@ import mozilla.components.browser.icons.IconRequest
|
||||
import mozilla.components.browser.session.storage.RecoverableBrowserState
|
||||
import mozilla.components.browser.state.action.EngineAction
|
||||
import mozilla.components.browser.state.action.TabListAction
|
||||
import mozilla.components.browser.state.action.TranslationsAction
|
||||
import mozilla.components.browser.state.selector.findTab
|
||||
import mozilla.components.browser.state.state.BrowserState
|
||||
import mozilla.components.browser.state.state.LastMediaAccessState
|
||||
@@ -55,6 +59,7 @@ import org.json.JSONObject
|
||||
import org.mozilla.gecko.util.ThreadUtils.runOnUiThread
|
||||
import mozilla.components.feature.addons.logger
|
||||
import mozilla.components.concept.engine.EngineSession
|
||||
import mozilla.components.concept.engine.translate.TranslationOperation
|
||||
|
||||
class GeckoTabsApiImpl : GeckoTabsApi {
|
||||
companion object {
|
||||
@@ -185,6 +190,7 @@ class GeckoTabsApiImpl : GeckoTabsApi {
|
||||
onPageExtensionsChange: Boolean,
|
||||
onBrowserExtensionIcons: Boolean,
|
||||
onPageExtensionIcons: Boolean,
|
||||
onTranslationStateChange: Boolean,
|
||||
) {
|
||||
try {
|
||||
val tabs = components.core.store.state.tabs.map { it.copy() }
|
||||
@@ -293,11 +299,85 @@ class GeckoTabsApiImpl : GeckoTabsApi {
|
||||
onPageExtensionIcons
|
||||
)
|
||||
}
|
||||
|
||||
// Sync translation events
|
||||
if (onTranslationStateChange) {
|
||||
syncTranslationEvents(tabs)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.error("$TAG: Failed to sync events", e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun syncTranslationEvents(tabs: List<mozilla.components.browser.state.state.TabSessionState>) {
|
||||
try {
|
||||
val browserState = components.core.store.state
|
||||
|
||||
// Retry initialization when support status is still unknown.
|
||||
if (browserState.translationEngine.isEngineSupported == null) {
|
||||
components.core.store.dispatch(TranslationsAction.InitTranslationsBrowserState)
|
||||
}
|
||||
|
||||
// Fetch supported languages when engine is supported but languages are still missing.
|
||||
if (
|
||||
browserState.translationEngine.isEngineSupported == true &&
|
||||
(
|
||||
browserState.translationEngine.supportedLanguages?.fromLanguages == null ||
|
||||
browserState.translationEngine.supportedLanguages?.toLanguages == null
|
||||
)
|
||||
) {
|
||||
components.core.store.dispatch(
|
||||
TranslationsAction.OperationRequestedAction(
|
||||
tabId = browserState.selectedTabId,
|
||||
operation = TranslationOperation.FETCH_SUPPORTED_LANGUAGES,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val translationEngine = browserState.translationEngine
|
||||
|
||||
// Emit browser-level engine state
|
||||
val fromLanguages = translationEngine.supportedLanguages?.fromLanguages?.map { lang ->
|
||||
TranslationLanguage(code = lang.code, localizedDisplayName = lang.localizedDisplayName ?: lang.code)
|
||||
}
|
||||
val toLanguages = translationEngine.supportedLanguages?.toLanguages?.map { lang ->
|
||||
TranslationLanguage(code = lang.code, localizedDisplayName = lang.localizedDisplayName ?: lang.code)
|
||||
}
|
||||
|
||||
components.flutterEvents.onTranslationEngineStateChange(
|
||||
EventSequence.next(),
|
||||
TranslationEngineStateData(
|
||||
isEngineSupported = translationEngine.isEngineSupported,
|
||||
fromLanguages = fromLanguages,
|
||||
toLanguages = toLanguages,
|
||||
)
|
||||
) { }
|
||||
|
||||
// Emit per-tab translation state
|
||||
tabs.forEach { tab ->
|
||||
val translationsState = tab.translationsState
|
||||
components.flutterEvents.onTabTranslationStateChange(
|
||||
EventSequence.next(),
|
||||
TabTranslationStateData(
|
||||
tabId = tab.id,
|
||||
isTranslated = translationsState.isTranslated,
|
||||
isTranslateProcessing = translationsState.isTranslateProcessing,
|
||||
isOfferTranslate = translationsState.isOfferTranslate,
|
||||
isExpectedTranslate = translationsState.isExpectedTranslate,
|
||||
detectedLanguageCode = translationsState.translationEngineState?.detectedLanguages?.documentLangTag,
|
||||
userPreferredLanguageCode = translationsState.translationEngineState?.detectedLanguages?.userPreferredLangTag,
|
||||
requestedFromLanguage = translationsState.translationEngineState?.requestedTranslationPair?.fromLanguage,
|
||||
requestedToLanguage = translationsState.translationEngineState?.requestedTranslationPair?.toLanguage,
|
||||
translationErrorName = translationsState.translationError?.errorName,
|
||||
displayError = translationsState.translationError?.displayError,
|
||||
)
|
||||
) { }
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.error("$TAG: Failed to sync translation events", e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun syncExtensionEvents(
|
||||
onBrowserExtensionsChange: Boolean,
|
||||
onPageExtensionsChange: Boolean,
|
||||
|
||||
+5
@@ -30,6 +30,7 @@ import mozilla.components.browser.icons.BrowserIcons
|
||||
import mozilla.components.browser.session.storage.SessionStorage
|
||||
import mozilla.components.browser.state.engine.EngineMiddleware
|
||||
import mozilla.components.browser.state.engine.middleware.SessionPrioritizationMiddleware
|
||||
import mozilla.components.browser.state.engine.middleware.TranslationsMiddleware
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.browser.storage.sync.PlacesBookmarksStorage
|
||||
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
|
||||
@@ -67,6 +68,7 @@ import mozilla.components.concept.base.crash.Breadcrumb
|
||||
import mozilla.components.concept.base.crash.CrashReporting
|
||||
import mozilla.components.support.base.worker.Frequency
|
||||
import org.mozilla.geckoview.GeckoRuntime
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.Job
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@@ -207,6 +209,9 @@ class Core(
|
||||
SaveToPDFMiddleware(),
|
||||
FileUploadsDirCleanerMiddleware(fileUploadsDirCleaner),
|
||||
LastMediaAccessMiddleware(),
|
||||
// Keep parity with Fenix: do not initialize translations on store init.
|
||||
// EngineObserver will dispatch InitTranslationsBrowserState after first completed page load.
|
||||
TranslationsMiddleware(engine, MainScope(), false),
|
||||
) + EngineMiddleware.create(
|
||||
engine,
|
||||
// We are disabling automatic suspending of engine sessions under memory pressure.
|
||||
|
||||
+68
@@ -23,6 +23,9 @@ import eu.weblibre.flutter_mozilla_components.pigeons.ShareTarget
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.ShareTargetFiles
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.ShareTargetParams
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.TabContentState
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.TabTranslationStateData
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.TranslationEngineStateData
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.TranslationLanguage
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
@@ -222,6 +225,71 @@ class Events(
|
||||
}
|
||||
}
|
||||
|
||||
// Translation engine state (browser-level)
|
||||
stateFlow.flowScoped { flow ->
|
||||
flow.map { state -> state.translationEngine }
|
||||
.distinctUntilChanged { old, new ->
|
||||
old.isEngineSupported == new.isEngineSupported &&
|
||||
old.supportedLanguages == new.supportedLanguages
|
||||
}
|
||||
.debounce(50)
|
||||
.collect { translationEngine ->
|
||||
val fromLanguages = translationEngine.supportedLanguages?.fromLanguages?.map { lang ->
|
||||
TranslationLanguage(code = lang.code, localizedDisplayName = lang.localizedDisplayName ?: lang.code)
|
||||
}
|
||||
val toLanguages = translationEngine.supportedLanguages?.toLanguages?.map { lang ->
|
||||
TranslationLanguage(code = lang.code, localizedDisplayName = lang.localizedDisplayName ?: lang.code)
|
||||
}
|
||||
|
||||
flutterEvents.onTranslationEngineStateChange(
|
||||
EventSequence.next(),
|
||||
TranslationEngineStateData(
|
||||
isEngineSupported = translationEngine.isEngineSupported,
|
||||
fromLanguages = fromLanguages,
|
||||
toLanguages = toLanguages,
|
||||
)
|
||||
) { _ -> }
|
||||
}
|
||||
}
|
||||
|
||||
// Per-tab translation state
|
||||
stateFlow.flowScoped { flow ->
|
||||
flow.mapNotNull { state -> state.tabs }
|
||||
.filterChanged {
|
||||
it.translationsState
|
||||
}
|
||||
.ifAnyChanged {
|
||||
arrayOf(
|
||||
it.translationsState.isTranslated,
|
||||
it.translationsState.isTranslateProcessing,
|
||||
it.translationsState.isOfferTranslate,
|
||||
it.translationsState.isExpectedTranslate,
|
||||
it.translationsState.translationEngineState,
|
||||
it.translationsState.translationError,
|
||||
)
|
||||
}
|
||||
.debounce(25)
|
||||
.collect { tab ->
|
||||
val ts = tab.translationsState
|
||||
flutterEvents.onTabTranslationStateChange(
|
||||
EventSequence.next(),
|
||||
TabTranslationStateData(
|
||||
tabId = tab.id,
|
||||
isTranslated = ts.isTranslated,
|
||||
isTranslateProcessing = ts.isTranslateProcessing,
|
||||
isOfferTranslate = ts.isOfferTranslate,
|
||||
isExpectedTranslate = ts.isExpectedTranslate,
|
||||
detectedLanguageCode = ts.translationEngineState?.detectedLanguages?.documentLangTag,
|
||||
userPreferredLanguageCode = ts.translationEngineState?.detectedLanguages?.userPreferredLangTag,
|
||||
requestedFromLanguage = ts.translationEngineState?.requestedTranslationPair?.fromLanguage,
|
||||
requestedToLanguage = ts.translationEngineState?.requestedTranslationPair?.toLanguage,
|
||||
translationErrorName = ts.translationError?.errorName,
|
||||
displayError = ts.translationError?.displayError,
|
||||
)
|
||||
) { _ -> }
|
||||
}
|
||||
}
|
||||
|
||||
// PWA manifest availability events - following Fenix MenuPresenter pattern
|
||||
stateFlow.flowScoped { flow ->
|
||||
flow.mapNotNull { state -> state.selectedTab }
|
||||
|
||||
+9
@@ -24,6 +24,15 @@ class SaveToPDFMiddleware : Middleware<BrowserState, BrowserAction> {
|
||||
is EngineAction.SaveToPdfExceptionAction -> {
|
||||
logger.error("Unable to save PDF", action.throwable)
|
||||
}
|
||||
is EngineAction.PrintContentAction -> {
|
||||
next(action)
|
||||
}
|
||||
is EngineAction.PrintContentCompletedAction -> {
|
||||
logger.info("Print completed successfully")
|
||||
}
|
||||
is EngineAction.PrintContentExceptionAction -> {
|
||||
logger.error("Unable to print content", action.throwable)
|
||||
}
|
||||
else -> {
|
||||
next(action)
|
||||
}
|
||||
|
||||
+419
-131
File diff suppressed because it is too large
Load Diff
@@ -94,9 +94,15 @@ export 'src/pigeons/gecko.g.dart'
|
||||
SyncRemoteTab,
|
||||
TabContent,
|
||||
TabContentState,
|
||||
TabTranslationStateData,
|
||||
TrackingProtectionException,
|
||||
TrackingProtectionPolicy,
|
||||
TrackingScope,
|
||||
TranslationDetectedLanguages,
|
||||
TranslationEngineStateData,
|
||||
TranslationLanguage,
|
||||
TranslationOptions,
|
||||
TranslationPair,
|
||||
UnknownHitResult,
|
||||
VideoHitResult,
|
||||
VisitInfo,
|
||||
|
||||
@@ -21,6 +21,8 @@ typedef FindResultsEvent = ({String tabId, List<FindResultState> results});
|
||||
typedef LongPressEvent = ({String tabId, HitResult hitResult});
|
||||
typedef ScrollEvent = ({String tabId, int scrollY});
|
||||
typedef ManifestUpdateEvent = ({String tabId, PwaManifest? manifest});
|
||||
typedef TabTranslationEvent = ({String tabId, TabTranslationStateData state});
|
||||
typedef TranslationEngineEvent = TranslationEngineStateData;
|
||||
|
||||
class GeckoEventService extends GeckoStateEvents {
|
||||
// Stream controllers
|
||||
@@ -46,6 +48,9 @@ class GeckoEventService extends GeckoStateEvents {
|
||||
final _tabAddedSubject = PublishSubject<String>();
|
||||
final _mlProgressSubject = PublishSubject<MlProgressData>();
|
||||
final _manifestUpdateSubject = PublishSubject<ManifestUpdateEvent>();
|
||||
final _translationEngineSubject =
|
||||
BehaviorSubject<TranslationEngineEvent>();
|
||||
final _tabTranslationSubject = ReplaySubject<TabTranslationEvent>();
|
||||
|
||||
// Event streams
|
||||
ValueStream<bool> get viewReadyStateEvents => _viewStateSubject.stream;
|
||||
@@ -72,6 +77,10 @@ class GeckoEventService extends GeckoStateEvents {
|
||||
Stream<MlProgressData> get mlProgressEvents => _mlProgressSubject.stream;
|
||||
Stream<ManifestUpdateEvent> get manifestUpdateEvents =>
|
||||
_manifestUpdateSubject.stream;
|
||||
ValueStream<TranslationEngineEvent> get translationEngineEvents =>
|
||||
_translationEngineSubject.stream;
|
||||
Stream<TabTranslationEvent> get tabTranslationEvents =>
|
||||
_tabTranslationSubject.stream;
|
||||
|
||||
@override
|
||||
void onViewReadyStateChange(int sequence, bool state) {
|
||||
@@ -210,6 +219,25 @@ class GeckoEventService extends GeckoStateEvents {
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
void onTranslationEngineStateChange(
|
||||
int sequence,
|
||||
TranslationEngineStateData state,
|
||||
) {
|
||||
_translationEngineSubject.addWhenMoreRecent(sequence, null, state);
|
||||
}
|
||||
|
||||
@override
|
||||
void onTabTranslationStateChange(
|
||||
int sequence,
|
||||
TabTranslationStateData state,
|
||||
) {
|
||||
_tabTranslationSubject.addWhenMoreRecent(sequence, state.tabId, (
|
||||
tabId: state.tabId,
|
||||
state: state,
|
||||
));
|
||||
}
|
||||
|
||||
GeckoEventService.setUp({
|
||||
BinaryMessenger? binaryMessenger,
|
||||
String messageChannelSuffix = '',
|
||||
@@ -241,5 +269,7 @@ class GeckoEventService extends GeckoStateEvents {
|
||||
await _siteAssignementSubject.close();
|
||||
await _mlProgressSubject.close();
|
||||
await _manifestUpdateSubject.close();
|
||||
await _translationEngineSubject.close();
|
||||
await _tabTranslationSubject.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ class GeckoTabService {
|
||||
bool onPageExtensionsChange = false,
|
||||
bool onBrowserExtensionIcons = false,
|
||||
bool onPageExtensionIcons = false,
|
||||
bool onTranslationStateChange = false,
|
||||
}) {
|
||||
return _api.syncEvents(
|
||||
onSelectedTabChange: onSelectedTabChange,
|
||||
@@ -44,6 +45,7 @@ class GeckoTabService {
|
||||
onPageExtensionsChange: onPageExtensionsChange,
|
||||
onBrowserExtensionIcons: onBrowserExtensionIcons,
|
||||
onPageExtensionIcons: onPageExtensionIcons,
|
||||
onTranslationStateChange: onTranslationStateChange,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,77 @@ class TranslationOptions {
|
||||
TranslationOptions({this.downloadModel = true});
|
||||
}
|
||||
|
||||
/// A language supported by the translation engine.
|
||||
class TranslationLanguage {
|
||||
final String code;
|
||||
final String localizedDisplayName;
|
||||
|
||||
TranslationLanguage({required this.code, required this.localizedDisplayName});
|
||||
}
|
||||
|
||||
/// Detected languages for a page.
|
||||
class TranslationDetectedLanguages {
|
||||
final String? documentLangTag;
|
||||
final bool? supportedDocumentLang;
|
||||
final String? userPreferredLangTag;
|
||||
|
||||
TranslationDetectedLanguages({
|
||||
this.documentLangTag,
|
||||
this.supportedDocumentLang,
|
||||
this.userPreferredLangTag,
|
||||
});
|
||||
}
|
||||
|
||||
/// A from/to language pair for translation.
|
||||
class TranslationPair {
|
||||
final String fromLanguage;
|
||||
final String toLanguage;
|
||||
|
||||
TranslationPair({required this.fromLanguage, required this.toLanguage});
|
||||
}
|
||||
|
||||
/// Browser-level translation engine state (global).
|
||||
class TranslationEngineStateData {
|
||||
final bool? isEngineSupported;
|
||||
final List<TranslationLanguage?>? fromLanguages;
|
||||
final List<TranslationLanguage?>? toLanguages;
|
||||
|
||||
TranslationEngineStateData({
|
||||
this.isEngineSupported,
|
||||
this.fromLanguages,
|
||||
this.toLanguages,
|
||||
});
|
||||
}
|
||||
|
||||
/// Per-tab translation state.
|
||||
class TabTranslationStateData {
|
||||
final String tabId;
|
||||
final bool isTranslated;
|
||||
final bool isTranslateProcessing;
|
||||
final bool isOfferTranslate;
|
||||
final bool isExpectedTranslate;
|
||||
final String? detectedLanguageCode;
|
||||
final String? userPreferredLanguageCode;
|
||||
final String? requestedFromLanguage;
|
||||
final String? requestedToLanguage;
|
||||
final String? translationErrorName;
|
||||
final bool? displayError;
|
||||
|
||||
TabTranslationStateData({
|
||||
required this.tabId,
|
||||
required this.isTranslated,
|
||||
required this.isTranslateProcessing,
|
||||
required this.isOfferTranslate,
|
||||
required this.isExpectedTranslate,
|
||||
this.detectedLanguageCode,
|
||||
this.userPreferredLanguageCode,
|
||||
this.requestedFromLanguage,
|
||||
this.requestedToLanguage,
|
||||
this.translationErrorName,
|
||||
this.displayError,
|
||||
});
|
||||
}
|
||||
|
||||
/// Value type that represents the state of reader mode/view.
|
||||
class ReaderState {
|
||||
/// Whether or not the current page can be transformed to
|
||||
@@ -1256,6 +1327,7 @@ abstract class GeckoTabsApi {
|
||||
required bool onPageExtensionsChange,
|
||||
required bool onBrowserExtensionIcons,
|
||||
required bool onPageExtensionIcons,
|
||||
required bool onTranslationStateChange,
|
||||
});
|
||||
|
||||
void selectTab({required String tabId});
|
||||
@@ -1562,6 +1634,15 @@ abstract class GeckoStateEvents {
|
||||
void onMlProgress(int sequence, MlProgressData progress);
|
||||
|
||||
void onManifestUpdate(int sequence, String tabId, PwaManifest? manifest);
|
||||
|
||||
void onTranslationEngineStateChange(
|
||||
int sequence,
|
||||
TranslationEngineStateData state,
|
||||
);
|
||||
void onTabTranslationStateChange(
|
||||
int sequence,
|
||||
TabTranslationStateData state,
|
||||
);
|
||||
}
|
||||
|
||||
@FlutterApi()
|
||||
|
||||
@@ -15,11 +15,7 @@ PlatformException _createConnectionError(String channelName) {
|
||||
);
|
||||
}
|
||||
|
||||
List<Object?> wrapResponse({
|
||||
Object? result,
|
||||
PlatformException? error,
|
||||
bool empty = false,
|
||||
}) {
|
||||
List<Object?> wrapResponse({Object? result, PlatformException? error, bool empty = false}) {
|
||||
if (empty) {
|
||||
return <Object?>[];
|
||||
}
|
||||
@@ -28,48 +24,37 @@ List<Object?> wrapResponse({
|
||||
}
|
||||
return <Object?>[error.code, error.message, error.details];
|
||||
}
|
||||
|
||||
bool _deepEquals(Object? a, Object? b) {
|
||||
if (a is List && b is List) {
|
||||
return a.length == b.length &&
|
||||
a.indexed.every(
|
||||
((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]),
|
||||
);
|
||||
a.indexed
|
||||
.every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]));
|
||||
}
|
||||
if (a is Map && b is Map) {
|
||||
return a.length == b.length &&
|
||||
a.entries.every(
|
||||
(MapEntry<Object?, Object?> entry) =>
|
||||
(b as Map<Object?, Object?>).containsKey(entry.key) &&
|
||||
_deepEquals(entry.value, b[entry.key]),
|
||||
);
|
||||
return a.length == b.length && a.entries.every((MapEntry<Object?, Object?> entry) =>
|
||||
(b as Map<Object?, Object?>).containsKey(entry.key) &&
|
||||
_deepEquals(entry.value, b[entry.key]));
|
||||
}
|
||||
return a == b;
|
||||
}
|
||||
|
||||
|
||||
/// Transport types for Tor connections
|
||||
enum TransportType {
|
||||
/// Direct Tor connection (no bridges)
|
||||
none,
|
||||
|
||||
/// obfs4 pluggable transport
|
||||
obfs4,
|
||||
|
||||
/// Snowflake pluggable transport (default broker)
|
||||
snowflake,
|
||||
|
||||
/// Snowflake via AMP cache
|
||||
snowflakeAmp,
|
||||
|
||||
/// Meek pluggable transport
|
||||
meek,
|
||||
|
||||
/// Meek via Azure CDN
|
||||
meekAzure,
|
||||
|
||||
/// WebTunnel pluggable transport
|
||||
webtunnel,
|
||||
|
||||
/// Custom bridge lines (passthrough)
|
||||
custom,
|
||||
}
|
||||
@@ -110,8 +95,7 @@ class TorConfiguration {
|
||||
}
|
||||
|
||||
Object encode() {
|
||||
return _toList();
|
||||
}
|
||||
return _toList(); }
|
||||
|
||||
static TorConfiguration decode(Object result) {
|
||||
result as List<Object?>;
|
||||
@@ -138,7 +122,8 @@ class TorConfiguration {
|
||||
|
||||
@override
|
||||
// ignore: avoid_equals_and_hash_code_on_mutable_classes
|
||||
int get hashCode => Object.hashAll(_toList());
|
||||
int get hashCode => Object.hashAll(_toList())
|
||||
;
|
||||
}
|
||||
|
||||
/// Current Tor status
|
||||
@@ -177,8 +162,7 @@ class TorStatus {
|
||||
}
|
||||
|
||||
Object encode() {
|
||||
return _toList();
|
||||
}
|
||||
return _toList(); }
|
||||
|
||||
static TorStatus decode(Object result) {
|
||||
result as List<Object?>;
|
||||
@@ -205,7 +189,8 @@ class TorStatus {
|
||||
|
||||
@override
|
||||
// ignore: avoid_equals_and_hash_code_on_mutable_classes
|
||||
int get hashCode => Object.hashAll(_toList());
|
||||
int get hashCode => Object.hashAll(_toList())
|
||||
;
|
||||
}
|
||||
|
||||
/// Log message from Tor
|
||||
@@ -226,12 +211,15 @@ class TorLogMessage {
|
||||
int timestamp;
|
||||
|
||||
List<Object?> _toList() {
|
||||
return <Object?>[severity, message, timestamp];
|
||||
return <Object?>[
|
||||
severity,
|
||||
message,
|
||||
timestamp,
|
||||
];
|
||||
}
|
||||
|
||||
Object encode() {
|
||||
return _toList();
|
||||
}
|
||||
return _toList(); }
|
||||
|
||||
static TorLogMessage decode(Object result) {
|
||||
result as List<Object?>;
|
||||
@@ -256,9 +244,11 @@ class TorLogMessage {
|
||||
|
||||
@override
|
||||
// ignore: avoid_equals_and_hash_code_on_mutable_classes
|
||||
int get hashCode => Object.hashAll(_toList());
|
||||
int get hashCode => Object.hashAll(_toList())
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
class _PigeonCodec extends StandardMessageCodec {
|
||||
const _PigeonCodec();
|
||||
@override
|
||||
@@ -266,16 +256,16 @@ class _PigeonCodec extends StandardMessageCodec {
|
||||
if (value is int) {
|
||||
buffer.putUint8(4);
|
||||
buffer.putInt64(value);
|
||||
} else if (value is TransportType) {
|
||||
} else if (value is TransportType) {
|
||||
buffer.putUint8(129);
|
||||
writeValue(buffer, value.index);
|
||||
} else if (value is TorConfiguration) {
|
||||
} else if (value is TorConfiguration) {
|
||||
buffer.putUint8(130);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is TorStatus) {
|
||||
} else if (value is TorStatus) {
|
||||
buffer.putUint8(131);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is TorLogMessage) {
|
||||
} else if (value is TorLogMessage) {
|
||||
buffer.putUint8(132);
|
||||
writeValue(buffer, value.encode());
|
||||
} else {
|
||||
@@ -286,14 +276,14 @@ class _PigeonCodec extends StandardMessageCodec {
|
||||
@override
|
||||
Object? readValueOfType(int type, ReadBuffer buffer) {
|
||||
switch (type) {
|
||||
case 129:
|
||||
case 129:
|
||||
final value = readValue(buffer) as int?;
|
||||
return value == null ? null : TransportType.values[value];
|
||||
case 130:
|
||||
case 130:
|
||||
return TorConfiguration.decode(readValue(buffer)!);
|
||||
case 131:
|
||||
case 131:
|
||||
return TorStatus.decode(readValue(buffer)!);
|
||||
case 132:
|
||||
case 132:
|
||||
return TorLogMessage.decode(readValue(buffer)!);
|
||||
default:
|
||||
return super.readValueOfType(type, buffer);
|
||||
@@ -307,10 +297,8 @@ class TorApi {
|
||||
/// available for dependency injection. If it is left null, the default
|
||||
/// BinaryMessenger will be used which routes to the host platform.
|
||||
TorApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
|
||||
: pigeonVar_binaryMessenger = binaryMessenger,
|
||||
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty
|
||||
? '.$messageChannelSuffix'
|
||||
: '';
|
||||
: pigeonVar_binaryMessenger = binaryMessenger,
|
||||
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
|
||||
final BinaryMessenger? pigeonVar_binaryMessenger;
|
||||
|
||||
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
|
||||
@@ -320,16 +308,13 @@ class TorApi {
|
||||
/// Start Tor with the given configuration
|
||||
/// Returns a Future to avoid blocking the main thread
|
||||
Future<int> startTor(TorConfiguration config) async {
|
||||
final pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.flutter_tor.TorApi.startTor$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.TorApi.startTor$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(
|
||||
<Object?>[config],
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[config]);
|
||||
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
@@ -351,8 +336,7 @@ class TorApi {
|
||||
|
||||
/// Stop Tor
|
||||
Future<void> stopTor() async {
|
||||
final pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.flutter_tor.TorApi.stopTor$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.TorApi.stopTor$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
@@ -375,8 +359,7 @@ class TorApi {
|
||||
|
||||
/// Get current status
|
||||
Future<TorStatus> getStatus() async {
|
||||
final pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.flutter_tor.TorApi.getStatus$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.TorApi.getStatus$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
@@ -404,8 +387,7 @@ class TorApi {
|
||||
|
||||
/// Request a new Tor identity (new circuit)
|
||||
Future<void> requestNewIdentity() async {
|
||||
final pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.flutter_tor.TorApi.requestNewIdentity$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.TorApi.requestNewIdentity$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
@@ -437,76 +419,54 @@ abstract class TorLogApi {
|
||||
/// Called when status changes
|
||||
void onStatusChanged(TorStatus status);
|
||||
|
||||
static void setUp(
|
||||
TorLogApi? api, {
|
||||
BinaryMessenger? binaryMessenger,
|
||||
String messageChannelSuffix = '',
|
||||
}) {
|
||||
messageChannelSuffix = messageChannelSuffix.isNotEmpty
|
||||
? '.$messageChannelSuffix'
|
||||
: '';
|
||||
static void setUp(TorLogApi? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) {
|
||||
messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
|
||||
{
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.flutter_tor.TorLogApi.onLogMessage$messageChannelSuffix',
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: binaryMessenger,
|
||||
);
|
||||
'dev.flutter.pigeon.flutter_tor.TorLogApi.onLogMessage$messageChannelSuffix', pigeonChannelCodec,
|
||||
binaryMessenger: binaryMessenger);
|
||||
if (api == null) {
|
||||
pigeonVar_channel.setMessageHandler(null);
|
||||
} else {
|
||||
pigeonVar_channel.setMessageHandler((Object? message) async {
|
||||
assert(
|
||||
message != null,
|
||||
'Argument for dev.flutter.pigeon.flutter_tor.TorLogApi.onLogMessage was null.',
|
||||
);
|
||||
assert(message != null,
|
||||
'Argument for dev.flutter.pigeon.flutter_tor.TorLogApi.onLogMessage was null.');
|
||||
final List<Object?> args = (message as List<Object?>?)!;
|
||||
final TorLogMessage? arg_log = (args[0] as TorLogMessage?);
|
||||
assert(
|
||||
arg_log != null,
|
||||
'Argument for dev.flutter.pigeon.flutter_tor.TorLogApi.onLogMessage was null, expected non-null TorLogMessage.',
|
||||
);
|
||||
assert(arg_log != null,
|
||||
'Argument for dev.flutter.pigeon.flutter_tor.TorLogApi.onLogMessage was null, expected non-null TorLogMessage.');
|
||||
try {
|
||||
api.onLogMessage(arg_log!);
|
||||
return wrapResponse(empty: true);
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: e);
|
||||
} catch (e) {
|
||||
return wrapResponse(
|
||||
error: PlatformException(code: 'error', message: e.toString()),
|
||||
);
|
||||
} catch (e) {
|
||||
return wrapResponse(error: PlatformException(code: 'error', message: e.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.flutter_tor.TorLogApi.onStatusChanged$messageChannelSuffix',
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: binaryMessenger,
|
||||
);
|
||||
'dev.flutter.pigeon.flutter_tor.TorLogApi.onStatusChanged$messageChannelSuffix', pigeonChannelCodec,
|
||||
binaryMessenger: binaryMessenger);
|
||||
if (api == null) {
|
||||
pigeonVar_channel.setMessageHandler(null);
|
||||
} else {
|
||||
pigeonVar_channel.setMessageHandler((Object? message) async {
|
||||
assert(
|
||||
message != null,
|
||||
'Argument for dev.flutter.pigeon.flutter_tor.TorLogApi.onStatusChanged was null.',
|
||||
);
|
||||
assert(message != null,
|
||||
'Argument for dev.flutter.pigeon.flutter_tor.TorLogApi.onStatusChanged was null.');
|
||||
final List<Object?> args = (message as List<Object?>?)!;
|
||||
final TorStatus? arg_status = (args[0] as TorStatus?);
|
||||
assert(
|
||||
arg_status != null,
|
||||
'Argument for dev.flutter.pigeon.flutter_tor.TorLogApi.onStatusChanged was null, expected non-null TorStatus.',
|
||||
);
|
||||
assert(arg_status != null,
|
||||
'Argument for dev.flutter.pigeon.flutter_tor.TorLogApi.onStatusChanged was null, expected non-null TorStatus.');
|
||||
try {
|
||||
api.onStatusChanged(arg_status!);
|
||||
return wrapResponse(empty: true);
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: e);
|
||||
} catch (e) {
|
||||
return wrapResponse(
|
||||
error: PlatformException(code: 'error', message: e.toString()),
|
||||
);
|
||||
} catch (e) {
|
||||
return wrapResponse(error: PlatformException(code: 'error', message: e.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -518,13 +478,9 @@ class IPtProxyController {
|
||||
/// Constructor for [IPtProxyController]. 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.
|
||||
IPtProxyController({
|
||||
BinaryMessenger? binaryMessenger,
|
||||
String messageChannelSuffix = '',
|
||||
}) : pigeonVar_binaryMessenger = binaryMessenger,
|
||||
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty
|
||||
? '.$messageChannelSuffix'
|
||||
: '';
|
||||
IPtProxyController({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
|
||||
: pigeonVar_binaryMessenger = binaryMessenger,
|
||||
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
|
||||
final BinaryMessenger? pigeonVar_binaryMessenger;
|
||||
|
||||
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
|
||||
@@ -532,16 +488,13 @@ class IPtProxyController {
|
||||
final String pigeonVar_messageChannelSuffix;
|
||||
|
||||
Future<int> start(TransportType proxyType, String proxy) async {
|
||||
final pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.flutter_tor.IPtProxyController.start$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.IPtProxyController.start$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(
|
||||
<Object?>[proxyType, proxy],
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[proxyType, proxy]);
|
||||
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
@@ -562,16 +515,13 @@ class IPtProxyController {
|
||||
}
|
||||
|
||||
Future<void> stop(TransportType proxyType) async {
|
||||
final pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.flutter_tor.IPtProxyController.stop$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.IPtProxyController.stop$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(
|
||||
<Object?>[proxyType],
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[proxyType]);
|
||||
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
|
||||
@@ -14,39 +14,40 @@ PlatformException _createConnectionError(String channelName) {
|
||||
message: 'Unable to establish connection on channel: "$channelName".',
|
||||
);
|
||||
}
|
||||
|
||||
bool _deepEquals(Object? a, Object? b) {
|
||||
if (a is List && b is List) {
|
||||
return a.length == b.length &&
|
||||
a.indexed.every(
|
||||
((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]),
|
||||
);
|
||||
a.indexed
|
||||
.every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]));
|
||||
}
|
||||
if (a is Map && b is Map) {
|
||||
return a.length == b.length &&
|
||||
a.entries.every(
|
||||
(MapEntry<Object?, Object?> entry) =>
|
||||
(b as Map<Object?, Object?>).containsKey(entry.key) &&
|
||||
_deepEquals(entry.value, b[entry.key]),
|
||||
);
|
||||
return a.length == b.length && a.entries.every((MapEntry<Object?, Object?> entry) =>
|
||||
(b as Map<Object?, Object?>).containsKey(entry.key) &&
|
||||
_deepEquals(entry.value, b[entry.key]));
|
||||
}
|
||||
return a == b;
|
||||
}
|
||||
|
||||
|
||||
class LocalizedResult {
|
||||
LocalizedResult({required this.languageName, this.countryName});
|
||||
LocalizedResult({
|
||||
required this.languageName,
|
||||
this.countryName,
|
||||
});
|
||||
|
||||
String languageName;
|
||||
|
||||
String? countryName;
|
||||
|
||||
List<Object?> _toList() {
|
||||
return <Object?>[languageName, countryName];
|
||||
return <Object?>[
|
||||
languageName,
|
||||
countryName,
|
||||
];
|
||||
}
|
||||
|
||||
Object encode() {
|
||||
return _toList();
|
||||
}
|
||||
return _toList(); }
|
||||
|
||||
static LocalizedResult decode(Object result) {
|
||||
result as List<Object?>;
|
||||
@@ -70,9 +71,11 @@ class LocalizedResult {
|
||||
|
||||
@override
|
||||
// ignore: avoid_equals_and_hash_code_on_mutable_classes
|
||||
int get hashCode => Object.hashAll(_toList());
|
||||
int get hashCode => Object.hashAll(_toList())
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
class _PigeonCodec extends StandardMessageCodec {
|
||||
const _PigeonCodec();
|
||||
@override
|
||||
@@ -80,7 +83,7 @@ class _PigeonCodec extends StandardMessageCodec {
|
||||
if (value is int) {
|
||||
buffer.putUint8(4);
|
||||
buffer.putInt64(value);
|
||||
} else if (value is LocalizedResult) {
|
||||
} else if (value is LocalizedResult) {
|
||||
buffer.putUint8(129);
|
||||
writeValue(buffer, value.encode());
|
||||
} else {
|
||||
@@ -91,7 +94,7 @@ class _PigeonCodec extends StandardMessageCodec {
|
||||
@override
|
||||
Object? readValueOfType(int type, ReadBuffer buffer) {
|
||||
switch (type) {
|
||||
case 129:
|
||||
case 129:
|
||||
return LocalizedResult.decode(readValue(buffer)!);
|
||||
default:
|
||||
return super.readValueOfType(type, buffer);
|
||||
@@ -103,33 +106,23 @@ class LocaleResolver {
|
||||
/// Constructor for [LocaleResolver]. 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.
|
||||
LocaleResolver({
|
||||
BinaryMessenger? binaryMessenger,
|
||||
String messageChannelSuffix = '',
|
||||
}) : pigeonVar_binaryMessenger = binaryMessenger,
|
||||
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty
|
||||
? '.$messageChannelSuffix'
|
||||
: '';
|
||||
LocaleResolver({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<LocalizedResult> resolve(
|
||||
String languageTag,
|
||||
String targetLangouageTag,
|
||||
) async {
|
||||
final pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.locale_resolver.LocaleResolver.resolve$pigeonVar_messageChannelSuffix';
|
||||
Future<LocalizedResult> resolve(String languageTag, String targetLangouageTag) async {
|
||||
final pigeonVar_channelName = 'dev.flutter.pigeon.locale_resolver.LocaleResolver.resolve$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(
|
||||
<Object?>[languageTag, targetLangouageTag],
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[languageTag, targetLangouageTag]);
|
||||
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
|
||||
@@ -8,11 +8,7 @@ import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
|
||||
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
List<Object?> wrapResponse({
|
||||
Object? result,
|
||||
PlatformException? error,
|
||||
bool empty = false,
|
||||
}) {
|
||||
List<Object?> wrapResponse({Object? result, PlatformException? error, bool empty = false}) {
|
||||
if (empty) {
|
||||
return <Object?>[];
|
||||
}
|
||||
@@ -21,25 +17,21 @@ List<Object?> wrapResponse({
|
||||
}
|
||||
return <Object?>[error.code, error.message, error.details];
|
||||
}
|
||||
|
||||
bool _deepEquals(Object? a, Object? b) {
|
||||
if (a is List && b is List) {
|
||||
return a.length == b.length &&
|
||||
a.indexed.every(
|
||||
((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]),
|
||||
);
|
||||
a.indexed
|
||||
.every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]));
|
||||
}
|
||||
if (a is Map && b is Map) {
|
||||
return a.length == b.length &&
|
||||
a.entries.every(
|
||||
(MapEntry<Object?, Object?> entry) =>
|
||||
(b as Map<Object?, Object?>).containsKey(entry.key) &&
|
||||
_deepEquals(entry.value, b[entry.key]),
|
||||
);
|
||||
return a.length == b.length && a.entries.every((MapEntry<Object?, Object?> entry) =>
|
||||
(b as Map<Object?, Object?>).containsKey(entry.key) &&
|
||||
_deepEquals(entry.value, b[entry.key]));
|
||||
}
|
||||
return a == b;
|
||||
}
|
||||
|
||||
|
||||
class Intent {
|
||||
Intent({
|
||||
this.fromPackageName,
|
||||
@@ -74,8 +66,7 @@ class Intent {
|
||||
}
|
||||
|
||||
Object encode() {
|
||||
return _toList();
|
||||
}
|
||||
return _toList(); }
|
||||
|
||||
static Intent decode(Object result) {
|
||||
result as List<Object?>;
|
||||
@@ -103,9 +94,11 @@ class Intent {
|
||||
|
||||
@override
|
||||
// ignore: avoid_equals_and_hash_code_on_mutable_classes
|
||||
int get hashCode => Object.hashAll(_toList());
|
||||
int get hashCode => Object.hashAll(_toList())
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
class _PigeonCodec extends StandardMessageCodec {
|
||||
const _PigeonCodec();
|
||||
@override
|
||||
@@ -113,7 +106,7 @@ class _PigeonCodec extends StandardMessageCodec {
|
||||
if (value is int) {
|
||||
buffer.putUint8(4);
|
||||
buffer.putInt64(value);
|
||||
} else if (value is Intent) {
|
||||
} else if (value is Intent) {
|
||||
buffer.putUint8(129);
|
||||
writeValue(buffer, value.encode());
|
||||
} else {
|
||||
@@ -124,7 +117,7 @@ class _PigeonCodec extends StandardMessageCodec {
|
||||
@override
|
||||
Object? readValueOfType(int type, ReadBuffer buffer) {
|
||||
switch (type) {
|
||||
case 129:
|
||||
case 129:
|
||||
return Intent.decode(readValue(buffer)!);
|
||||
default:
|
||||
return super.readValueOfType(type, buffer);
|
||||
@@ -137,48 +130,32 @@ abstract class IntentEvents {
|
||||
|
||||
void onIntentReceived(int sequence, Intent intent);
|
||||
|
||||
static void setUp(
|
||||
IntentEvents? api, {
|
||||
BinaryMessenger? binaryMessenger,
|
||||
String messageChannelSuffix = '',
|
||||
}) {
|
||||
messageChannelSuffix = messageChannelSuffix.isNotEmpty
|
||||
? '.$messageChannelSuffix'
|
||||
: '';
|
||||
static void setUp(IntentEvents? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) {
|
||||
messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
|
||||
{
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.simple_intent_receiver.IntentEvents.onIntentReceived$messageChannelSuffix',
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: binaryMessenger,
|
||||
);
|
||||
'dev.flutter.pigeon.simple_intent_receiver.IntentEvents.onIntentReceived$messageChannelSuffix', pigeonChannelCodec,
|
||||
binaryMessenger: binaryMessenger);
|
||||
if (api == null) {
|
||||
pigeonVar_channel.setMessageHandler(null);
|
||||
} else {
|
||||
pigeonVar_channel.setMessageHandler((Object? message) async {
|
||||
assert(
|
||||
message != null,
|
||||
'Argument for dev.flutter.pigeon.simple_intent_receiver.IntentEvents.onIntentReceived was null.',
|
||||
);
|
||||
assert(message != null,
|
||||
'Argument for dev.flutter.pigeon.simple_intent_receiver.IntentEvents.onIntentReceived was null.');
|
||||
final List<Object?> args = (message as List<Object?>?)!;
|
||||
final int? arg_sequence = (args[0] as int?);
|
||||
assert(
|
||||
arg_sequence != null,
|
||||
'Argument for dev.flutter.pigeon.simple_intent_receiver.IntentEvents.onIntentReceived was null, expected non-null int.',
|
||||
);
|
||||
assert(arg_sequence != null,
|
||||
'Argument for dev.flutter.pigeon.simple_intent_receiver.IntentEvents.onIntentReceived was null, expected non-null int.');
|
||||
final Intent? arg_intent = (args[1] as Intent?);
|
||||
assert(
|
||||
arg_intent != null,
|
||||
'Argument for dev.flutter.pigeon.simple_intent_receiver.IntentEvents.onIntentReceived was null, expected non-null Intent.',
|
||||
);
|
||||
assert(arg_intent != null,
|
||||
'Argument for dev.flutter.pigeon.simple_intent_receiver.IntentEvents.onIntentReceived was null, expected non-null Intent.');
|
||||
try {
|
||||
api.onIntentReceived(arg_sequence!, arg_intent!);
|
||||
return wrapResponse(empty: true);
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: e);
|
||||
} catch (e) {
|
||||
return wrapResponse(
|
||||
error: PlatformException(code: 'error', message: e.toString()),
|
||||
);
|
||||
} catch (e) {
|
||||
return wrapResponse(error: PlatformException(code: 'error', message: e.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,11 +15,7 @@ PlatformException _createConnectionError(String channelName) {
|
||||
);
|
||||
}
|
||||
|
||||
List<Object?> wrapResponse({
|
||||
Object? result,
|
||||
PlatformException? error,
|
||||
bool empty = false,
|
||||
}) {
|
||||
List<Object?> wrapResponse({Object? result, PlatformException? error, bool empty = false}) {
|
||||
if (empty) {
|
||||
return <Object?>[];
|
||||
}
|
||||
@@ -29,6 +25,7 @@ List<Object?> wrapResponse({
|
||||
return <Object?>[error.code, error.message, error.details];
|
||||
}
|
||||
|
||||
|
||||
class _PigeonCodec extends StandardMessageCodec {
|
||||
const _PigeonCodec();
|
||||
@override
|
||||
@@ -55,13 +52,9 @@ class SpeechToTextApi {
|
||||
/// Constructor for [SpeechToTextApi]. 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.
|
||||
SpeechToTextApi({
|
||||
BinaryMessenger? binaryMessenger,
|
||||
String messageChannelSuffix = '',
|
||||
}) : pigeonVar_binaryMessenger = binaryMessenger,
|
||||
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty
|
||||
? '.$messageChannelSuffix'
|
||||
: '';
|
||||
SpeechToTextApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
|
||||
: pigeonVar_binaryMessenger = binaryMessenger,
|
||||
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
|
||||
final BinaryMessenger? pigeonVar_binaryMessenger;
|
||||
|
||||
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
|
||||
@@ -76,16 +69,13 @@ class SpeechToTextApi {
|
||||
/// The [locale] parameter specifies the language locale for recognition
|
||||
/// (e.g., 'en-US', 'de-DE'). If null, uses the device default.
|
||||
Future<bool> showDialog({String? locale}) async {
|
||||
final pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextApi.showDialog$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channelName = 'dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextApi.showDialog$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(
|
||||
<Object?>[locale],
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[locale]);
|
||||
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
@@ -116,43 +106,29 @@ abstract class SpeechToTextEvents {
|
||||
/// recognition failed or was cancelled.
|
||||
void onTextReceived(String text);
|
||||
|
||||
static void setUp(
|
||||
SpeechToTextEvents? api, {
|
||||
BinaryMessenger? binaryMessenger,
|
||||
String messageChannelSuffix = '',
|
||||
}) {
|
||||
messageChannelSuffix = messageChannelSuffix.isNotEmpty
|
||||
? '.$messageChannelSuffix'
|
||||
: '';
|
||||
static void setUp(SpeechToTextEvents? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) {
|
||||
messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
|
||||
{
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextEvents.onTextReceived$messageChannelSuffix',
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: binaryMessenger,
|
||||
);
|
||||
'dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextEvents.onTextReceived$messageChannelSuffix', pigeonChannelCodec,
|
||||
binaryMessenger: binaryMessenger);
|
||||
if (api == null) {
|
||||
pigeonVar_channel.setMessageHandler(null);
|
||||
} else {
|
||||
pigeonVar_channel.setMessageHandler((Object? message) async {
|
||||
assert(
|
||||
message != null,
|
||||
'Argument for dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextEvents.onTextReceived was null.',
|
||||
);
|
||||
assert(message != null,
|
||||
'Argument for dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextEvents.onTextReceived was null.');
|
||||
final List<Object?> args = (message as List<Object?>?)!;
|
||||
final String? arg_text = (args[0] as String?);
|
||||
assert(
|
||||
arg_text != null,
|
||||
'Argument for dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextEvents.onTextReceived was null, expected non-null String.',
|
||||
);
|
||||
assert(arg_text != null,
|
||||
'Argument for dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextEvents.onTextReceived was null, expected non-null String.');
|
||||
try {
|
||||
api.onTextReceived(arg_text!);
|
||||
return wrapResponse(empty: true);
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: e);
|
||||
} catch (e) {
|
||||
return wrapResponse(
|
||||
error: PlatformException(code: 'error', message: e.toString()),
|
||||
);
|
||||
} catch (e) {
|
||||
return wrapResponse(error: PlatformException(code: 'error', message: e.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user