diff --git a/app/lib/features/geckoview/features/history/domain/providers.dart b/app/lib/features/geckoview/features/history/domain/providers.dart
new file mode 100644
index 00000000..0a01ddab
--- /dev/null
+++ b/app/lib/features/geckoview/features/history/domain/providers.dart
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2024-2025 Fabian Freund.
+ *
+ * This file is part of WebLibre
+ * (see https://weblibre.eu).
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
+import 'package:riverpod/riverpod.dart';
+import 'package:riverpod_annotation/riverpod_annotation.dart';
+
+part 'providers.g.dart';
+
+@Riverpod()
+Future> browsingHistory(
+ Ref red, {
+ required DateTime start,
+ required DateTime end,
+ required Set types,
+}) {
+ final service = GeckoHistoryService();
+ return service.getDetailedVisits(start, end, types);
+}
diff --git a/app/lib/features/geckoview/features/history/domain/providers.g.dart b/app/lib/features/geckoview/features/history/domain/providers.g.dart
new file mode 100644
index 00000000..ed2b7655
--- /dev/null
+++ b/app/lib/features/geckoview/features/history/domain/providers.g.dart
@@ -0,0 +1,191 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'providers.dart';
+
+// **************************************************************************
+// RiverpodGenerator
+// **************************************************************************
+
+String _$browsingHistoryHash() => r'1f644757c60473f00dd94c9d312647baeaec525a';
+
+/// Copied from Dart SDK
+class _SystemHash {
+ _SystemHash._();
+
+ static int combine(int hash, int value) {
+ // ignore: parameter_assignments
+ hash = 0x1fffffff & (hash + value);
+ // ignore: parameter_assignments
+ hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+ return hash ^ (hash >> 6);
+ }
+
+ static int finish(int hash) {
+ // ignore: parameter_assignments
+ hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+ // ignore: parameter_assignments
+ hash = hash ^ (hash >> 11);
+ return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+ }
+}
+
+/// See also [browsingHistory].
+@ProviderFor(browsingHistory)
+const browsingHistoryProvider = BrowsingHistoryFamily();
+
+/// See also [browsingHistory].
+class BrowsingHistoryFamily extends Family>> {
+ /// See also [browsingHistory].
+ const BrowsingHistoryFamily();
+
+ /// See also [browsingHistory].
+ BrowsingHistoryProvider call({
+ required DateTime start,
+ required DateTime end,
+ required Set types,
+ }) {
+ return BrowsingHistoryProvider(start: start, end: end, types: types);
+ }
+
+ @override
+ BrowsingHistoryProvider getProviderOverride(
+ covariant BrowsingHistoryProvider provider,
+ ) {
+ return call(
+ start: provider.start,
+ end: provider.end,
+ types: provider.types,
+ );
+ }
+
+ static const Iterable? _dependencies = null;
+
+ @override
+ Iterable? get dependencies => _dependencies;
+
+ static const Iterable? _allTransitiveDependencies = null;
+
+ @override
+ Iterable? get allTransitiveDependencies =>
+ _allTransitiveDependencies;
+
+ @override
+ String? get name => r'browsingHistoryProvider';
+}
+
+/// See also [browsingHistory].
+class BrowsingHistoryProvider
+ extends AutoDisposeFutureProvider> {
+ /// See also [browsingHistory].
+ BrowsingHistoryProvider({
+ required DateTime start,
+ required DateTime end,
+ required Set types,
+ }) : this._internal(
+ (ref) => browsingHistory(
+ ref as BrowsingHistoryRef,
+ start: start,
+ end: end,
+ types: types,
+ ),
+ from: browsingHistoryProvider,
+ name: r'browsingHistoryProvider',
+ debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
+ ? null
+ : _$browsingHistoryHash,
+ dependencies: BrowsingHistoryFamily._dependencies,
+ allTransitiveDependencies:
+ BrowsingHistoryFamily._allTransitiveDependencies,
+ start: start,
+ end: end,
+ types: types,
+ );
+
+ BrowsingHistoryProvider._internal(
+ super._createNotifier, {
+ required super.name,
+ required super.dependencies,
+ required super.allTransitiveDependencies,
+ required super.debugGetCreateSourceHash,
+ required super.from,
+ required this.start,
+ required this.end,
+ required this.types,
+ }) : super.internal();
+
+ final DateTime start;
+ final DateTime end;
+ final Set types;
+
+ @override
+ Override overrideWith(
+ FutureOr> Function(BrowsingHistoryRef provider) create,
+ ) {
+ return ProviderOverride(
+ origin: this,
+ override: BrowsingHistoryProvider._internal(
+ (ref) => create(ref as BrowsingHistoryRef),
+ from: from,
+ name: null,
+ dependencies: null,
+ allTransitiveDependencies: null,
+ debugGetCreateSourceHash: null,
+ start: start,
+ end: end,
+ types: types,
+ ),
+ );
+ }
+
+ @override
+ AutoDisposeFutureProviderElement> createElement() {
+ return _BrowsingHistoryProviderElement(this);
+ }
+
+ @override
+ bool operator ==(Object other) {
+ return other is BrowsingHistoryProvider &&
+ other.start == start &&
+ other.end == end &&
+ other.types == types;
+ }
+
+ @override
+ int get hashCode {
+ var hash = _SystemHash.combine(0, runtimeType.hashCode);
+ hash = _SystemHash.combine(hash, start.hashCode);
+ hash = _SystemHash.combine(hash, end.hashCode);
+ hash = _SystemHash.combine(hash, types.hashCode);
+
+ return _SystemHash.finish(hash);
+ }
+}
+
+@Deprecated('Will be removed in 3.0. Use Ref instead')
+// ignore: unused_element
+mixin BrowsingHistoryRef on AutoDisposeFutureProviderRef> {
+ /// The parameter `start` of this provider.
+ DateTime get start;
+
+ /// The parameter `end` of this provider.
+ DateTime get end;
+
+ /// The parameter `types` of this provider.
+ Set get types;
+}
+
+class _BrowsingHistoryProviderElement
+ extends AutoDisposeFutureProviderElement>
+ with BrowsingHistoryRef {
+ _BrowsingHistoryProviderElement(super.provider);
+
+ @override
+ DateTime get start => (origin as BrowsingHistoryProvider).start;
+ @override
+ DateTime get end => (origin as BrowsingHistoryProvider).end;
+ @override
+ Set get types => (origin as BrowsingHistoryProvider).types;
+}
+
+// ignore_for_file: type=lint
+// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
diff --git a/app/lib/features/geckoview/features/history/presentation/screens/history.dart b/app/lib/features/geckoview/features/history/presentation/screens/history.dart
new file mode 100644
index 00000000..93c7e991
--- /dev/null
+++ b/app/lib/features/geckoview/features/history/presentation/screens/history.dart
@@ -0,0 +1,23 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:weblibre/features/geckoview/features/history/domain/providers.dart';
+
+class HistoryScreen extends HookConsumerWidget {
+ const HistoryScreen({super.key});
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final history = ref.watch(
+ browsingHistoryProvider(
+ start: DateTime(0),
+ end: DateTime.now(),
+ types: {
+ VisitType.link,
+ VisitType.redirectPermanent,
+ VisitType.redirectTemporary,
+ VisitType.typed,
+ },
+ ),
+ );
+ }
+}
diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/api/GeckoBrowserApiImpl.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/api/GeckoBrowserApiImpl.kt
index f2f9b8ae..2c9f4c9c 100644
--- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/api/GeckoBrowserApiImpl.kt
+++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/api/GeckoBrowserApiImpl.kt
@@ -27,6 +27,7 @@ import eu.weblibre.flutter_mozilla_components.pigeons.GeckoDeleteBrowsingDataCon
import eu.weblibre.flutter_mozilla_components.pigeons.GeckoDownloadsApi
import eu.weblibre.flutter_mozilla_components.pigeons.GeckoEngineSettingsApi
import eu.weblibre.flutter_mozilla_components.pigeons.GeckoFindApi
+import eu.weblibre.flutter_mozilla_components.pigeons.GeckoHistoryApi
import eu.weblibre.flutter_mozilla_components.pigeons.GeckoIconsApi
import eu.weblibre.flutter_mozilla_components.pigeons.GeckoLogging
import eu.weblibre.flutter_mozilla_components.pigeons.GeckoMlApi
@@ -214,6 +215,7 @@ class GeckoBrowserApiImpl : GeckoBrowserApi {
GeckoDeleteBrowsingDataController.setUp(_flutterPluginBinding.binaryMessenger, GeckoDeleteBrowsingDataControllerImpl())
GeckoDownloadsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoDownloadsApiImpl())
GeckoBrowserExtensionApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoBrowserExtensionApiImpl())
+ GeckoHistoryApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoHistoryApiImpl())
ReaderViewEvents.setUp(
_flutterPluginBinding.binaryMessenger,
diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/api/GeckoHistoryApiImpl.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/api/GeckoHistoryApiImpl.kt
new file mode 100644
index 00000000..269507c0
--- /dev/null
+++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/api/GeckoHistoryApiImpl.kt
@@ -0,0 +1,72 @@
+package eu.weblibre.flutter_mozilla_components.api
+
+import eu.weblibre.flutter_mozilla_components.GlobalComponents
+import eu.weblibre.flutter_mozilla_components.pigeons.AutocompleteResult
+import eu.weblibre.flutter_mozilla_components.pigeons.GeckoHistoryApi
+import eu.weblibre.flutter_mozilla_components.pigeons.VisitInfo
+import eu.weblibre.flutter_mozilla_components.pigeons.VisitType
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+class GeckoHistoryApiImpl() : GeckoHistoryApi {
+ companion object {
+ private val coroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
+ }
+
+ private val components by lazy {
+ requireNotNull(GlobalComponents.components) { "Components not initialized" }
+ }
+
+ override fun getDetailedVisits(
+ startMillis: Long,
+ endMillis: Long,
+ excludeTypes: List,
+ callback: (Result>) -> Unit
+ ) {
+ coroutineScope.launch {
+ withContext(Dispatchers.Main) {
+ val visits = components.core.historyStorage.getDetailedVisits(
+ startMillis,
+ endMillis,
+ excludeTypes.map {
+ when (it) {
+ VisitType.LINK -> mozilla.components.concept.storage.VisitType.LINK
+ VisitType.TYPED -> mozilla.components.concept.storage.VisitType.TYPED
+ VisitType.BOOKMARK -> mozilla.components.concept.storage.VisitType.BOOKMARK
+ VisitType.EMBED -> mozilla.components.concept.storage.VisitType.EMBED
+ VisitType.REDIRECT_PERMANENT -> mozilla.components.concept.storage.VisitType.REDIRECT_PERMANENT
+ VisitType.REDIRECT_TEMPORARY -> mozilla.components.concept.storage.VisitType.REDIRECT_TEMPORARY
+ VisitType.DOWNLOAD -> mozilla.components.concept.storage.VisitType.DOWNLOAD
+ VisitType.FRAMED_LINK -> mozilla.components.concept.storage.VisitType.FRAMED_LINK
+ VisitType.RELOAD -> mozilla.components.concept.storage.VisitType.RELOAD
+ }
+ })
+
+ callback(Result.success(visits.map {
+ VisitInfo(
+ url = it.url,
+ title = it.title,
+ visitTime = it.visitTime,
+ visitType = when (it.visitType) {
+ mozilla.components.concept.storage.VisitType.LINK -> VisitType.LINK
+ mozilla.components.concept.storage.VisitType.TYPED -> VisitType.TYPED
+ mozilla.components.concept.storage.VisitType.BOOKMARK -> VisitType.BOOKMARK
+ mozilla.components.concept.storage.VisitType.EMBED -> VisitType.EMBED
+ mozilla.components.concept.storage.VisitType.REDIRECT_PERMANENT -> VisitType.REDIRECT_PERMANENT
+ mozilla.components.concept.storage.VisitType.REDIRECT_TEMPORARY -> VisitType.REDIRECT_TEMPORARY
+ mozilla.components.concept.storage.VisitType.DOWNLOAD -> VisitType.DOWNLOAD
+ mozilla.components.concept.storage.VisitType.FRAMED_LINK -> VisitType.FRAMED_LINK
+ mozilla.components.concept.storage.VisitType.RELOAD -> VisitType.RELOAD
+ },
+ previewImageUrl = it.previewImageUrl,
+ isRemote = it.isRemote
+ )
+ }
+ ))
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/pigeons/Gecko.g.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/pigeons/Gecko.g.kt
index 8429e87d..7f891028 100644
--- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/pigeons/Gecko.g.kt
+++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/pigeons/Gecko.g.kt
@@ -166,6 +166,24 @@ enum class CookieSameSiteStatus(val raw: Int) {
}
}
+enum class VisitType(val raw: Int) {
+ LINK(0),
+ TYPED(1),
+ BOOKMARK(2),
+ EMBED(3),
+ REDIRECT_PERMANENT(4),
+ REDIRECT_TEMPORARY(5),
+ DOWNLOAD(6),
+ FRAMED_LINK(7),
+ RELOAD(8);
+
+ companion object {
+ fun ofRaw(raw: Int): VisitType? {
+ return values().firstOrNull { it.raw == raw }
+ }
+ }
+}
+
enum class SelectionPattern(val raw: Int) {
PHONE(0),
EMAIL(1);
@@ -1102,6 +1120,49 @@ data class Cookie (
override fun hashCode(): Int = toList().hashCode()
}
+/** Generated class from Pigeon that represents data sent in messages. */
+data class VisitInfo (
+ val url: String,
+ val title: String? = null,
+ val visitTime: Long,
+ val visitType: VisitType,
+ val previewImageUrl: String? = null,
+ val isRemote: Boolean
+)
+ {
+ companion object {
+ fun fromList(pigeonVar_list: List): VisitInfo {
+ val url = pigeonVar_list[0] as String
+ val title = pigeonVar_list[1] as String?
+ val visitTime = pigeonVar_list[2] as Long
+ val visitType = pigeonVar_list[3] as VisitType
+ val previewImageUrl = pigeonVar_list[4] as String?
+ val isRemote = pigeonVar_list[5] as Boolean
+ return VisitInfo(url, title, visitTime, visitType, previewImageUrl, isRemote)
+ }
+ }
+ fun toList(): List {
+ return listOf(
+ url,
+ title,
+ visitTime,
+ visitType,
+ previewImageUrl,
+ isRemote,
+ )
+ }
+ override fun equals(other: Any?): Boolean {
+ if (other !is VisitInfo) {
+ return false
+ }
+ if (this === other) {
+ return true
+ }
+ return GeckoPigeonUtils.deepEquals(toList(), other.toList()) }
+
+ override fun hashCode(): Int = toList().hashCode()
+}
+
/** Generated class from Pigeon that represents data sent in messages. */
data class HistoryItem (
val url: String,
@@ -2051,260 +2112,270 @@ private open class GeckoPigeonCodec : StandardMessageCodec() {
}
134.toByte() -> {
return (readValue(buffer) as Long?)?.let {
- SelectionPattern.ofRaw(it.toInt())
+ VisitType.ofRaw(it.toInt())
}
}
135.toByte() -> {
return (readValue(buffer) as Long?)?.let {
- WebExtensionActionType.ofRaw(it.toInt())
+ SelectionPattern.ofRaw(it.toInt())
}
}
136.toByte() -> {
return (readValue(buffer) as Long?)?.let {
- GeckoSuggestionType.ofRaw(it.toInt())
+ WebExtensionActionType.ofRaw(it.toInt())
}
}
137.toByte() -> {
return (readValue(buffer) as Long?)?.let {
- TrackingProtectionPolicy.ofRaw(it.toInt())
+ GeckoSuggestionType.ofRaw(it.toInt())
}
}
138.toByte() -> {
return (readValue(buffer) as Long?)?.let {
- HttpsOnlyMode.ofRaw(it.toInt())
+ TrackingProtectionPolicy.ofRaw(it.toInt())
}
}
139.toByte() -> {
return (readValue(buffer) as Long?)?.let {
- QueryParameterStripping.ofRaw(it.toInt())
+ HttpsOnlyMode.ofRaw(it.toInt())
}
}
140.toByte() -> {
return (readValue(buffer) as Long?)?.let {
- BounceTrackingProtectionMode.ofRaw(it.toInt())
+ QueryParameterStripping.ofRaw(it.toInt())
}
}
141.toByte() -> {
return (readValue(buffer) as Long?)?.let {
- ColorScheme.ofRaw(it.toInt())
+ BounceTrackingProtectionMode.ofRaw(it.toInt())
}
}
142.toByte() -> {
return (readValue(buffer) as Long?)?.let {
- CookieBannerHandlingMode.ofRaw(it.toInt())
+ ColorScheme.ofRaw(it.toInt())
}
}
143.toByte() -> {
return (readValue(buffer) as Long?)?.let {
- WebContentIsolationStrategy.ofRaw(it.toInt())
+ CookieBannerHandlingMode.ofRaw(it.toInt())
}
}
144.toByte() -> {
return (readValue(buffer) as Long?)?.let {
- DownloadStatus.ofRaw(it.toInt())
+ WebContentIsolationStrategy.ofRaw(it.toInt())
}
}
145.toByte() -> {
return (readValue(buffer) as Long?)?.let {
- LogLevel.ofRaw(it.toInt())
+ DownloadStatus.ofRaw(it.toInt())
}
}
146.toByte() -> {
- return (readValue(buffer) as? List)?.let {
- TranslationOptions.fromList(it)
+ return (readValue(buffer) as Long?)?.let {
+ LogLevel.ofRaw(it.toInt())
}
}
147.toByte() -> {
return (readValue(buffer) as? List)?.let {
- ReaderState.fromList(it)
+ TranslationOptions.fromList(it)
}
}
148.toByte() -> {
return (readValue(buffer) as? List)?.let {
- LastMediaAccessState.fromList(it)
+ ReaderState.fromList(it)
}
}
149.toByte() -> {
return (readValue(buffer) as? List)?.let {
- HistoryMetadataKey.fromList(it)
+ LastMediaAccessState.fromList(it)
}
}
150.toByte() -> {
return (readValue(buffer) as? List)?.let {
- PackageCategoryValue.fromList(it)
+ HistoryMetadataKey.fromList(it)
}
}
151.toByte() -> {
return (readValue(buffer) as? List)?.let {
- ExternalPackage.fromList(it)
+ PackageCategoryValue.fromList(it)
}
}
152.toByte() -> {
return (readValue(buffer) as? List)?.let {
- LoadUrlFlagsValue.fromList(it)
+ ExternalPackage.fromList(it)
}
}
153.toByte() -> {
return (readValue(buffer) as? List)?.let {
- SourceValue.fromList(it)
+ LoadUrlFlagsValue.fromList(it)
}
}
154.toByte() -> {
return (readValue(buffer) as? List)?.let {
- TabState.fromList(it)
+ SourceValue.fromList(it)
}
}
155.toByte() -> {
return (readValue(buffer) as? List)?.let {
- RecoverableTab.fromList(it)
+ TabState.fromList(it)
}
}
156.toByte() -> {
return (readValue(buffer) as? List)?.let {
- RecoverableBrowserState.fromList(it)
+ RecoverableTab.fromList(it)
}
}
157.toByte() -> {
return (readValue(buffer) as? List)?.let {
- IconRequest.fromList(it)
+ RecoverableBrowserState.fromList(it)
}
}
158.toByte() -> {
return (readValue(buffer) as? List)?.let {
- ResourceSize.fromList(it)
+ IconRequest.fromList(it)
}
}
159.toByte() -> {
return (readValue(buffer) as? List)?.let {
- Resource.fromList(it)
+ ResourceSize.fromList(it)
}
}
160.toByte() -> {
return (readValue(buffer) as? List)?.let {
- IconResult.fromList(it)
+ Resource.fromList(it)
}
}
161.toByte() -> {
return (readValue(buffer) as? List)?.let {
- CookiePartitionKey.fromList(it)
+ IconResult.fromList(it)
}
}
162.toByte() -> {
return (readValue(buffer) as? List)?.let {
- Cookie.fromList(it)
+ CookiePartitionKey.fromList(it)
}
}
163.toByte() -> {
return (readValue(buffer) as? List)?.let {
- HistoryItem.fromList(it)
+ Cookie.fromList(it)
}
}
164.toByte() -> {
return (readValue(buffer) as? List)?.let {
- HistoryState.fromList(it)
+ VisitInfo.fromList(it)
}
}
165.toByte() -> {
return (readValue(buffer) as? List)?.let {
- ReaderableState.fromList(it)
+ HistoryItem.fromList(it)
}
}
166.toByte() -> {
return (readValue(buffer) as? List)?.let {
- SecurityInfoState.fromList(it)
+ HistoryState.fromList(it)
}
}
167.toByte() -> {
return (readValue(buffer) as? List)?.let {
- TabContentState.fromList(it)
+ ReaderableState.fromList(it)
}
}
168.toByte() -> {
return (readValue(buffer) as? List)?.let {
- FindResultState.fromList(it)
+ SecurityInfoState.fromList(it)
}
}
169.toByte() -> {
return (readValue(buffer) as? List)?.let {
- CustomSelectionAction.fromList(it)
+ TabContentState.fromList(it)
}
}
170.toByte() -> {
return (readValue(buffer) as? List)?.let {
- WebExtensionData.fromList(it)
+ FindResultState.fromList(it)
}
}
171.toByte() -> {
return (readValue(buffer) as? List)?.let {
- GeckoSuggestion.fromList(it)
+ CustomSelectionAction.fromList(it)
}
}
172.toByte() -> {
return (readValue(buffer) as? List)?.let {
- TabContent.fromList(it)
+ WebExtensionData.fromList(it)
}
}
173.toByte() -> {
return (readValue(buffer) as? List)?.let {
- ContentBlocking.fromList(it)
+ GeckoSuggestion.fromList(it)
}
}
174.toByte() -> {
return (readValue(buffer) as? List)?.let {
- GeckoEngineSettings.fromList(it)
+ TabContent.fromList(it)
}
}
175.toByte() -> {
return (readValue(buffer) as? List)?.let {
- AutocompleteResult.fromList(it)
+ ContentBlocking.fromList(it)
}
}
176.toByte() -> {
return (readValue(buffer) as? List)?.let {
- UnknownHitResult.fromList(it)
+ GeckoEngineSettings.fromList(it)
}
}
177.toByte() -> {
return (readValue(buffer) as? List)?.let {
- ImageHitResult.fromList(it)
+ AutocompleteResult.fromList(it)
}
}
178.toByte() -> {
return (readValue(buffer) as? List)?.let {
- VideoHitResult.fromList(it)
+ UnknownHitResult.fromList(it)
}
}
179.toByte() -> {
return (readValue(buffer) as? List)?.let {
- AudioHitResult.fromList(it)
+ ImageHitResult.fromList(it)
}
}
180.toByte() -> {
return (readValue(buffer) as? List)?.let {
- ImageSrcHitResult.fromList(it)
+ VideoHitResult.fromList(it)
}
}
181.toByte() -> {
return (readValue(buffer) as? List)?.let {
- PhoneHitResult.fromList(it)
+ AudioHitResult.fromList(it)
}
}
182.toByte() -> {
return (readValue(buffer) as? List)?.let {
- EmailHitResult.fromList(it)
+ ImageSrcHitResult.fromList(it)
}
}
183.toByte() -> {
return (readValue(buffer) as? List)?.let {
- GeoHitResult.fromList(it)
+ PhoneHitResult.fromList(it)
}
}
184.toByte() -> {
return (readValue(buffer) as? List)?.let {
- DownloadState.fromList(it)
+ EmailHitResult.fromList(it)
}
}
185.toByte() -> {
+ return (readValue(buffer) as? List)?.let {
+ GeoHitResult.fromList(it)
+ }
+ }
+ 186.toByte() -> {
+ return (readValue(buffer) as? List)?.let {
+ DownloadState.fromList(it)
+ }
+ }
+ 187.toByte() -> {
return (readValue(buffer) as? List)?.let {
ShareInternetResourceState.fromList(it)
}
@@ -2334,214 +2405,222 @@ private open class GeckoPigeonCodec : StandardMessageCodec() {
stream.write(133)
writeValue(stream, value.raw)
}
- is SelectionPattern -> {
+ is VisitType -> {
stream.write(134)
writeValue(stream, value.raw)
}
- is WebExtensionActionType -> {
+ is SelectionPattern -> {
stream.write(135)
writeValue(stream, value.raw)
}
- is GeckoSuggestionType -> {
+ is WebExtensionActionType -> {
stream.write(136)
writeValue(stream, value.raw)
}
- is TrackingProtectionPolicy -> {
+ is GeckoSuggestionType -> {
stream.write(137)
writeValue(stream, value.raw)
}
- is HttpsOnlyMode -> {
+ is TrackingProtectionPolicy -> {
stream.write(138)
writeValue(stream, value.raw)
}
- is QueryParameterStripping -> {
+ is HttpsOnlyMode -> {
stream.write(139)
writeValue(stream, value.raw)
}
- is BounceTrackingProtectionMode -> {
+ is QueryParameterStripping -> {
stream.write(140)
writeValue(stream, value.raw)
}
- is ColorScheme -> {
+ is BounceTrackingProtectionMode -> {
stream.write(141)
writeValue(stream, value.raw)
}
- is CookieBannerHandlingMode -> {
+ is ColorScheme -> {
stream.write(142)
writeValue(stream, value.raw)
}
- is WebContentIsolationStrategy -> {
+ is CookieBannerHandlingMode -> {
stream.write(143)
writeValue(stream, value.raw)
}
- is DownloadStatus -> {
+ is WebContentIsolationStrategy -> {
stream.write(144)
writeValue(stream, value.raw)
}
- is LogLevel -> {
+ is DownloadStatus -> {
stream.write(145)
writeValue(stream, value.raw)
}
- is TranslationOptions -> {
+ is LogLevel -> {
stream.write(146)
- writeValue(stream, value.toList())
+ writeValue(stream, value.raw)
}
- is ReaderState -> {
+ is TranslationOptions -> {
stream.write(147)
writeValue(stream, value.toList())
}
- is LastMediaAccessState -> {
+ is ReaderState -> {
stream.write(148)
writeValue(stream, value.toList())
}
- is HistoryMetadataKey -> {
+ is LastMediaAccessState -> {
stream.write(149)
writeValue(stream, value.toList())
}
- is PackageCategoryValue -> {
+ is HistoryMetadataKey -> {
stream.write(150)
writeValue(stream, value.toList())
}
- is ExternalPackage -> {
+ is PackageCategoryValue -> {
stream.write(151)
writeValue(stream, value.toList())
}
- is LoadUrlFlagsValue -> {
+ is ExternalPackage -> {
stream.write(152)
writeValue(stream, value.toList())
}
- is SourceValue -> {
+ is LoadUrlFlagsValue -> {
stream.write(153)
writeValue(stream, value.toList())
}
- is TabState -> {
+ is SourceValue -> {
stream.write(154)
writeValue(stream, value.toList())
}
- is RecoverableTab -> {
+ is TabState -> {
stream.write(155)
writeValue(stream, value.toList())
}
- is RecoverableBrowserState -> {
+ is RecoverableTab -> {
stream.write(156)
writeValue(stream, value.toList())
}
- is IconRequest -> {
+ is RecoverableBrowserState -> {
stream.write(157)
writeValue(stream, value.toList())
}
- is ResourceSize -> {
+ is IconRequest -> {
stream.write(158)
writeValue(stream, value.toList())
}
- is Resource -> {
+ is ResourceSize -> {
stream.write(159)
writeValue(stream, value.toList())
}
- is IconResult -> {
+ is Resource -> {
stream.write(160)
writeValue(stream, value.toList())
}
- is CookiePartitionKey -> {
+ is IconResult -> {
stream.write(161)
writeValue(stream, value.toList())
}
- is Cookie -> {
+ is CookiePartitionKey -> {
stream.write(162)
writeValue(stream, value.toList())
}
- is HistoryItem -> {
+ is Cookie -> {
stream.write(163)
writeValue(stream, value.toList())
}
- is HistoryState -> {
+ is VisitInfo -> {
stream.write(164)
writeValue(stream, value.toList())
}
- is ReaderableState -> {
+ is HistoryItem -> {
stream.write(165)
writeValue(stream, value.toList())
}
- is SecurityInfoState -> {
+ is HistoryState -> {
stream.write(166)
writeValue(stream, value.toList())
}
- is TabContentState -> {
+ is ReaderableState -> {
stream.write(167)
writeValue(stream, value.toList())
}
- is FindResultState -> {
+ is SecurityInfoState -> {
stream.write(168)
writeValue(stream, value.toList())
}
- is CustomSelectionAction -> {
+ is TabContentState -> {
stream.write(169)
writeValue(stream, value.toList())
}
- is WebExtensionData -> {
+ is FindResultState -> {
stream.write(170)
writeValue(stream, value.toList())
}
- is GeckoSuggestion -> {
+ is CustomSelectionAction -> {
stream.write(171)
writeValue(stream, value.toList())
}
- is TabContent -> {
+ is WebExtensionData -> {
stream.write(172)
writeValue(stream, value.toList())
}
- is ContentBlocking -> {
+ is GeckoSuggestion -> {
stream.write(173)
writeValue(stream, value.toList())
}
- is GeckoEngineSettings -> {
+ is TabContent -> {
stream.write(174)
writeValue(stream, value.toList())
}
- is AutocompleteResult -> {
+ is ContentBlocking -> {
stream.write(175)
writeValue(stream, value.toList())
}
- is UnknownHitResult -> {
+ is GeckoEngineSettings -> {
stream.write(176)
writeValue(stream, value.toList())
}
- is ImageHitResult -> {
+ is AutocompleteResult -> {
stream.write(177)
writeValue(stream, value.toList())
}
- is VideoHitResult -> {
+ is UnknownHitResult -> {
stream.write(178)
writeValue(stream, value.toList())
}
- is AudioHitResult -> {
+ is ImageHitResult -> {
stream.write(179)
writeValue(stream, value.toList())
}
- is ImageSrcHitResult -> {
+ is VideoHitResult -> {
stream.write(180)
writeValue(stream, value.toList())
}
- is PhoneHitResult -> {
+ is AudioHitResult -> {
stream.write(181)
writeValue(stream, value.toList())
}
- is EmailHitResult -> {
+ is ImageSrcHitResult -> {
stream.write(182)
writeValue(stream, value.toList())
}
- is GeoHitResult -> {
+ is PhoneHitResult -> {
stream.write(183)
writeValue(stream, value.toList())
}
- is DownloadState -> {
+ is EmailHitResult -> {
stream.write(184)
writeValue(stream, value.toList())
}
- is ShareInternetResourceState -> {
+ is GeoHitResult -> {
stream.write(185)
writeValue(stream, value.toList())
}
+ is DownloadState -> {
+ stream.write(186)
+ writeValue(stream, value.toList())
+ }
+ is ShareInternetResourceState -> {
+ stream.write(187)
+ writeValue(stream, value.toList())
+ }
else -> super.writeValue(stream, value)
}
}
@@ -4650,6 +4729,44 @@ interface GeckoDeleteBrowsingDataController {
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
+interface GeckoHistoryApi {
+ fun getDetailedVisits(startMillis: Long, endMillis: Long, excludeTypes: List, callback: (Result>) -> Unit)
+
+ companion object {
+ /** The codec used by GeckoHistoryApi. */
+ val codec: MessageCodec by lazy {
+ GeckoPigeonCodec()
+ }
+ /** Sets up an instance of `GeckoHistoryApi` to handle messages through the `binaryMessenger`. */
+ @JvmOverloads
+ fun setUp(binaryMessenger: BinaryMessenger, api: GeckoHistoryApi?, messageChannelSuffix: String = "") {
+ val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
+ run {
+ val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoHistoryApi.getDetailedVisits$separatedMessageChannelSuffix", codec)
+ if (api != null) {
+ channel.setMessageHandler { message, reply ->
+ val args = message as List
+ val startMillisArg = args[0] as Long
+ val endMillisArg = args[1] as Long
+ val excludeTypesArg = args[2] as List
+ api.getDetailedVisits(startMillisArg, endMillisArg, excludeTypesArg) { result: Result> ->
+ val error = result.exceptionOrNull()
+ if (error != null) {
+ reply.reply(GeckoPigeonUtils.wrapError(error))
+ } else {
+ val data = result.getOrNull()
+ reply.reply(GeckoPigeonUtils.wrapResult(data))
+ }
+ }
+ }
+ } else {
+ channel.setMessageHandler(null)
+ }
+ }
+ }
+ }
+}
+/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface GeckoDownloadsApi {
fun requestDownload(tabId: String, state: DownloadState)
fun copyInternetResource(tabId: String, state: ShareInternetResourceState)
diff --git a/packages/flutter_mozilla_components/lib/flutter_mozilla_components.dart b/packages/flutter_mozilla_components/lib/flutter_mozilla_components.dart
index 7052636a..4eb58b22 100644
--- a/packages/flutter_mozilla_components/lib/flutter_mozilla_components.dart
+++ b/packages/flutter_mozilla_components/lib/flutter_mozilla_components.dart
@@ -17,6 +17,7 @@ export 'src/domain/services/gecko_downloads.dart';
export 'src/domain/services/gecko_engine_settings.dart';
export 'src/domain/services/gecko_event.dart';
export 'src/domain/services/gecko_find_in_page.dart';
+export 'src/domain/services/gecko_history.dart';
export 'src/domain/services/gecko_icon.dart';
export 'src/domain/services/gecko_logging.dart';
export 'src/domain/services/gecko_ml.dart';
@@ -59,6 +60,8 @@ export 'src/pigeons/gecko.g.dart'
TrackingProtectionPolicy,
UnknownHitResult,
VideoHitResult,
+ VisitInfo,
+ VisitType,
WebContentIsolationStrategy,
WebExtensionActionType,
WebExtensionData;
diff --git a/packages/flutter_mozilla_components/lib/src/domain/services/gecko_history.dart b/packages/flutter_mozilla_components/lib/src/domain/services/gecko_history.dart
new file mode 100644
index 00000000..01f1a383
--- /dev/null
+++ b/packages/flutter_mozilla_components/lib/src/domain/services/gecko_history.dart
@@ -0,0 +1,27 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart';
+
+final _apiInstance = GeckoHistoryApi();
+
+class GeckoHistoryService {
+ final GeckoHistoryApi _api;
+
+ GeckoHistoryService({GeckoHistoryApi? api}) : _api = api ?? _apiInstance;
+
+ Future> getDetailedVisits(
+ DateTime start,
+ DateTime end,
+ Set types,
+ ) {
+ return _api.getDetailedVisits(
+ start.millisecondsSinceEpoch,
+ end.millisecondsSinceEpoch,
+ VisitType.values.toSet().difference(types).toList(),
+ );
+ }
+}
diff --git a/packages/flutter_mozilla_components/lib/src/pigeons/gecko.g.dart b/packages/flutter_mozilla_components/lib/src/pigeons/gecko.g.dart
index a4a2ff0f..e734c3d9 100644
--- a/packages/flutter_mozilla_components/lib/src/pigeons/gecko.g.dart
+++ b/packages/flutter_mozilla_components/lib/src/pigeons/gecko.g.dart
@@ -92,6 +92,18 @@ enum CookieSameSiteStatus {
unspecified,
}
+enum VisitType {
+ link,
+ typed,
+ bookmark,
+ embed,
+ redirectPermanent,
+ redirectTemporary,
+ download,
+ framedLink,
+ reload,
+}
+
enum SelectionPattern {
phone,
email,
@@ -1222,6 +1234,72 @@ class Cookie {
;
}
+class VisitInfo {
+ VisitInfo({
+ required this.url,
+ this.title,
+ required this.visitTime,
+ required this.visitType,
+ this.previewImageUrl,
+ required this.isRemote,
+ });
+
+ String url;
+
+ String? title;
+
+ int visitTime;
+
+ VisitType visitType;
+
+ String? previewImageUrl;
+
+ bool isRemote;
+
+ List