add initial sync of extensions
This commit is contained in:
@@ -21,7 +21,6 @@ import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:nullability/nullability.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:weblibre/core/logger.dart';
|
||||
import 'package:weblibre/domain/entities/equatable_image.dart';
|
||||
@@ -61,12 +60,12 @@ class WebExtensionsState extends _$WebExtensionsState {
|
||||
title: data.title,
|
||||
enabled: data.enabled ?? current.enabled,
|
||||
badgeText: data.badgeText,
|
||||
badgeTextColor: data.badgeTextColor.mapNotNull(
|
||||
(color) => Color(color),
|
||||
),
|
||||
badgeBackgroundColor: data.badgeBackgroundColor.mapNotNull(
|
||||
(color) => Color(color),
|
||||
),
|
||||
badgeTextColor: data.badgeTextColor != null
|
||||
? Color(data.badgeTextColor!)
|
||||
: null,
|
||||
badgeBackgroundColor: data.badgeBackgroundColor != null
|
||||
? Color(data.badgeBackgroundColor!)
|
||||
: null,
|
||||
);
|
||||
} else {
|
||||
if (state.containsKey(extensionId)) {
|
||||
@@ -152,6 +151,40 @@ class WebExtensionsState extends _$WebExtensionsState {
|
||||
],
|
||||
};
|
||||
|
||||
// Sync extension events after engine is ready and listeners are set up
|
||||
// This ensures we get the current state even if we missed initial events
|
||||
ref.listen(
|
||||
fireImmediately: true,
|
||||
engineReadyStateProvider,
|
||||
(previous, next) async {
|
||||
if (next) {
|
||||
try {
|
||||
await GeckoTabService().syncEvents(
|
||||
onBrowserExtensionsChange:
|
||||
actionType == WebExtensionActionType.browser,
|
||||
onPageExtensionsChange: actionType == WebExtensionActionType.page,
|
||||
onBrowserExtensionIcons:
|
||||
actionType == WebExtensionActionType.browser,
|
||||
onPageExtensionIcons: actionType == WebExtensionActionType.page,
|
||||
);
|
||||
} catch (e, s) {
|
||||
logger.w(
|
||||
'Failed to sync extension events for $actionType',
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
onError: (error, stackTrace) {
|
||||
logger.e(
|
||||
'Error listening to engineReadyStateProvider',
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
ref.onDispose(() async {
|
||||
// Dispose all cached images
|
||||
_imageCache.clear();
|
||||
|
||||
@@ -62,7 +62,7 @@ final class WebExtensionsStateProvider
|
||||
}
|
||||
|
||||
String _$webExtensionsStateHash() =>
|
||||
r'28cd9c99bc167fa1a051eccf3d23917a417e54ea';
|
||||
r'13cbbea409b5b643eb6766689f6b23a4d1701204';
|
||||
|
||||
final class WebExtensionsStateFamily extends $Family
|
||||
with
|
||||
|
||||
+1
-5
@@ -37,11 +37,7 @@ class ExtensionBadgeIcon extends StatelessWidget {
|
||||
textColor: state.badgeTextColor,
|
||||
backgroundColor: state.badgeBackgroundColor,
|
||||
child: RepaintBoundary(
|
||||
child: SafeRawImage(
|
||||
image: state.icon,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
child: SafeRawImage(image: state.icon, width: 24, height: 24),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ class Components(val profileApplicationContext: ProfileContext,
|
||||
val logLevel: Log.Priority,
|
||||
val contentBlocking: ContentBlocking,
|
||||
val addonCollection: AddonCollection?,
|
||||
private val addonEvents: GeckoAddonEvents,
|
||||
val addonEvents: GeckoAddonEvents,
|
||||
private val tabContentEvents: GeckoTabContentEvents,
|
||||
private val extensionEvents: BrowserExtensionEvents
|
||||
) {
|
||||
|
||||
+117
@@ -14,6 +14,8 @@ import eu.weblibre.flutter_mozilla_components.pigeons.RecoverableBrowserState as
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.RestoreLocation as PigeonRestoreLocation
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.RecoverableTab as PigeonRecoverableTab
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.SourceValue
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.WebExtensionActionType
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.WebExtensionData
|
||||
import eu.weblibre.flutter_mozilla_components.GlobalComponents
|
||||
import eu.weblibre.flutter_mozilla_components.ext.toWebPBytes
|
||||
import eu.weblibre.flutter_mozilla_components.pigeons.FindResultState
|
||||
@@ -178,6 +180,10 @@ class GeckoTabsApiImpl : GeckoTabsApi {
|
||||
onHistoryStateChange: Boolean,
|
||||
onFindResults: Boolean,
|
||||
onThumbnailChange: Boolean,
|
||||
onBrowserExtensionsChange: Boolean,
|
||||
onPageExtensionsChange: Boolean,
|
||||
onBrowserExtensionIcons: Boolean,
|
||||
onPageExtensionIcons: Boolean,
|
||||
) {
|
||||
try {
|
||||
val tabs = components.core.store.state.tabs.map { it.copy() }
|
||||
@@ -274,11 +280,122 @@ class GeckoTabsApiImpl : GeckoTabsApi {
|
||||
coroutineScope.launch { handleThumbnailChange(tab) }
|
||||
}
|
||||
}
|
||||
|
||||
// Sync extension events
|
||||
if (onBrowserExtensionsChange || onPageExtensionsChange ||
|
||||
onBrowserExtensionIcons || onPageExtensionIcons) {
|
||||
syncExtensionEvents(
|
||||
onBrowserExtensionsChange,
|
||||
onPageExtensionsChange,
|
||||
onBrowserExtensionIcons,
|
||||
onPageExtensionIcons
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.error("$TAG: Failed to sync events", e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun syncExtensionEvents(
|
||||
onBrowserExtensionsChange: Boolean,
|
||||
onPageExtensionsChange: Boolean,
|
||||
onBrowserExtensionIcons: Boolean,
|
||||
onPageExtensionIcons: Boolean
|
||||
) {
|
||||
try {
|
||||
val extensions = components.core.store.state.extensions.values.filter { it.enabled }
|
||||
|
||||
extensions.forEach { extension ->
|
||||
val browserAction = extension.browserAction
|
||||
val pageAction = extension.pageAction
|
||||
|
||||
// Sync browser action
|
||||
if (browserAction != null) {
|
||||
if (onBrowserExtensionsChange) {
|
||||
val data = WebExtensionData(
|
||||
extensionId = extension.id,
|
||||
title = browserAction.title,
|
||||
enabled = browserAction.enabled,
|
||||
badgeText = browserAction.badgeText,
|
||||
badgeTextColor = browserAction.badgeTextColor?.toLong(),
|
||||
badgeBackgroundColor = browserAction.badgeBackgroundColor?.toLong(),
|
||||
)
|
||||
components.addonEvents.onUpsertWebExtensionAction(
|
||||
System.currentTimeMillis(),
|
||||
extension.id,
|
||||
WebExtensionActionType.BROWSER,
|
||||
data
|
||||
) { }
|
||||
}
|
||||
|
||||
if (onBrowserExtensionIcons) {
|
||||
coroutineScope.launch {
|
||||
try {
|
||||
val icon = browserAction.loadIcon?.invoke(128)
|
||||
icon?.let {
|
||||
val imageBytes = icon.toWebPBytes()
|
||||
withContext(Dispatchers.Main) {
|
||||
components.addonEvents.onUpdateWebExtensionIcon(
|
||||
System.currentTimeMillis(),
|
||||
extension.id,
|
||||
WebExtensionActionType.BROWSER,
|
||||
imageBytes
|
||||
) { }
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.error("$TAG: Failed to load browser action icon for ${extension.id}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sync page action
|
||||
if (pageAction != null && pageAction.enabled == true) {
|
||||
if (onPageExtensionsChange) {
|
||||
val data = WebExtensionData(
|
||||
extensionId = extension.id,
|
||||
title = pageAction.title,
|
||||
enabled = pageAction.enabled,
|
||||
badgeText = pageAction.badgeText,
|
||||
badgeTextColor = pageAction.badgeTextColor?.toLong(),
|
||||
badgeBackgroundColor = pageAction.badgeBackgroundColor?.toLong(),
|
||||
)
|
||||
components.addonEvents.onUpsertWebExtensionAction(
|
||||
System.currentTimeMillis(),
|
||||
extension.id,
|
||||
WebExtensionActionType.PAGE,
|
||||
data
|
||||
) { }
|
||||
}
|
||||
|
||||
if (onPageExtensionIcons) {
|
||||
coroutineScope.launch {
|
||||
try {
|
||||
val icon = pageAction.loadIcon?.invoke(128)
|
||||
icon?.let {
|
||||
val imageBytes = icon.toWebPBytes()
|
||||
withContext(Dispatchers.Main) {
|
||||
components.addonEvents.onUpdateWebExtensionIcon(
|
||||
System.currentTimeMillis(),
|
||||
extension.id,
|
||||
WebExtensionActionType.PAGE,
|
||||
imageBytes
|
||||
) { }
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.error("$TAG: Failed to load page action icon for ${extension.id}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.error("$TAG: Failed to sync extension events", e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun selectTab(tabId: String) {
|
||||
try {
|
||||
components.useCases.tabsUseCases.selectTab(tabId = tabId)
|
||||
|
||||
+6
-2
@@ -4344,7 +4344,7 @@ interface GeckoSessionApi {
|
||||
}
|
||||
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
|
||||
interface GeckoTabsApi {
|
||||
fun syncEvents(onSelectedTabChange: Boolean, onTabListChange: Boolean, onTabContentStateChange: Boolean, onIconChange: Boolean, onSecurityInfoStateChange: Boolean, onReaderableStateChange: Boolean, onHistoryStateChange: Boolean, onFindResults: Boolean, onThumbnailChange: Boolean)
|
||||
fun syncEvents(onSelectedTabChange: Boolean, onTabListChange: Boolean, onTabContentStateChange: Boolean, onIconChange: Boolean, onSecurityInfoStateChange: Boolean, onReaderableStateChange: Boolean, onHistoryStateChange: Boolean, onFindResults: Boolean, onThumbnailChange: Boolean, onBrowserExtensionsChange: Boolean, onPageExtensionsChange: Boolean, onBrowserExtensionIcons: Boolean, onPageExtensionIcons: Boolean)
|
||||
fun selectTab(tabId: String)
|
||||
fun removeTab(tabId: String)
|
||||
fun addTab(url: String, selectTab: Boolean, startLoading: Boolean, parentId: String?, flags: LoadUrlFlagsValue, contextId: String?, source: SourceValue, private: Boolean, historyMetadata: HistoryMetadataKey?, additionalHeaders: Map<String, String>?): String
|
||||
@@ -4390,8 +4390,12 @@ interface GeckoTabsApi {
|
||||
val onHistoryStateChangeArg = args[6] as Boolean
|
||||
val onFindResultsArg = args[7] as Boolean
|
||||
val onThumbnailChangeArg = args[8] as Boolean
|
||||
val onBrowserExtensionsChangeArg = args[9] as Boolean
|
||||
val onPageExtensionsChangeArg = args[10] as Boolean
|
||||
val onBrowserExtensionIconsArg = args[11] as Boolean
|
||||
val onPageExtensionIconsArg = args[12] as Boolean
|
||||
val wrapped: List<Any?> = try {
|
||||
api.syncEvents(onSelectedTabChangeArg, onTabListChangeArg, onTabContentStateChangeArg, onIconChangeArg, onSecurityInfoStateChangeArg, onReaderableStateChangeArg, onHistoryStateChangeArg, onFindResultsArg, onThumbnailChangeArg)
|
||||
api.syncEvents(onSelectedTabChangeArg, onTabListChangeArg, onTabContentStateChangeArg, onIconChangeArg, onSecurityInfoStateChangeArg, onReaderableStateChangeArg, onHistoryStateChangeArg, onFindResultsArg, onThumbnailChangeArg, onBrowserExtensionsChangeArg, onPageExtensionsChangeArg, onBrowserExtensionIconsArg, onPageExtensionIconsArg)
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
GeckoPigeonUtils.wrapError(exception)
|
||||
|
||||
@@ -25,6 +25,10 @@ class GeckoTabService {
|
||||
bool onHistoryStateChange = false,
|
||||
bool onFindResults = false,
|
||||
bool onThumbnailChange = false,
|
||||
bool onBrowserExtensionsChange = false,
|
||||
bool onPageExtensionsChange = false,
|
||||
bool onBrowserExtensionIcons = false,
|
||||
bool onPageExtensionIcons = false,
|
||||
}) {
|
||||
return _api.syncEvents(
|
||||
onSelectedTabChange: onSelectedTabChange,
|
||||
@@ -36,6 +40,10 @@ class GeckoTabService {
|
||||
onFindResults: onFindResults,
|
||||
onThumbnailChange: onThumbnailChange,
|
||||
onReaderableStateChange: false,
|
||||
onBrowserExtensionsChange: onBrowserExtensionsChange,
|
||||
onPageExtensionsChange: onPageExtensionsChange,
|
||||
onBrowserExtensionIcons: onBrowserExtensionIcons,
|
||||
onPageExtensionIcons: onPageExtensionIcons,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4935,14 +4935,14 @@ class GeckoTabsApi {
|
||||
|
||||
final String pigeonVar_messageChannelSuffix;
|
||||
|
||||
Future<void> syncEvents({required bool onSelectedTabChange, required bool onTabListChange, required bool onTabContentStateChange, required bool onIconChange, required bool onSecurityInfoStateChange, required bool onReaderableStateChange, required bool onHistoryStateChange, required bool onFindResults, required bool onThumbnailChange, }) async {
|
||||
Future<void> syncEvents({required bool onSelectedTabChange, required bool onTabListChange, required bool onTabContentStateChange, required bool onIconChange, required bool onSecurityInfoStateChange, required bool onReaderableStateChange, required bool onHistoryStateChange, required bool onFindResults, required bool onThumbnailChange, required bool onBrowserExtensionsChange, required bool onPageExtensionsChange, required bool onBrowserExtensionIcons, required bool onPageExtensionIcons, }) async {
|
||||
final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoTabsApi.syncEvents$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[onSelectedTabChange, onTabListChange, onTabContentStateChange, onIconChange, onSecurityInfoStateChange, onReaderableStateChange, onHistoryStateChange, onFindResults, onThumbnailChange]);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[onSelectedTabChange, onTabListChange, onTabContentStateChange, onIconChange, onSecurityInfoStateChange, onReaderableStateChange, onHistoryStateChange, onFindResults, onThumbnailChange, onBrowserExtensionsChange, onPageExtensionsChange, onBrowserExtensionIcons, onPageExtensionIcons]);
|
||||
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
|
||||
@@ -1113,6 +1113,10 @@ abstract class GeckoTabsApi {
|
||||
required bool onHistoryStateChange,
|
||||
required bool onFindResults,
|
||||
required bool onThumbnailChange,
|
||||
required bool onBrowserExtensionsChange,
|
||||
required bool onPageExtensionsChange,
|
||||
required bool onBrowserExtensionIcons,
|
||||
required bool onPageExtensionIcons,
|
||||
});
|
||||
|
||||
void selectTab({required String tabId});
|
||||
|
||||
Reference in New Issue
Block a user