migrate mozilla components into project
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
export 'src/geckoview_widget.dart';
|
||||
//export 'src/domain/services/gecko_browser.dart';
|
||||
export 'src/domain/services/gecko_session.dart';
|
||||
export 'src/domain/services/gecko_tabs.dart';
|
||||
@@ -0,0 +1,46 @@
|
||||
// ignore_for_file: constant_identifier_names, non_constant_identifier_names
|
||||
|
||||
import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart';
|
||||
|
||||
/// Describes a combination of flags provided to the engine when loading a URL.
|
||||
class LoadUrlFlags {
|
||||
final int value;
|
||||
|
||||
const LoadUrlFlags._(this.value);
|
||||
|
||||
LoadUrlFlagsValue toValue() {
|
||||
return LoadUrlFlagsValue(value: value);
|
||||
}
|
||||
|
||||
static const LoadUrlFlags NONE = LoadUrlFlags._(0);
|
||||
static const LoadUrlFlags BYPASS_CACHE = LoadUrlFlags._(1 << 0);
|
||||
static const LoadUrlFlags BYPASS_PROXY = LoadUrlFlags._(1 << 1);
|
||||
static const LoadUrlFlags EXTERNAL = LoadUrlFlags._(1 << 2);
|
||||
static const LoadUrlFlags ALLOW_POPUPS = LoadUrlFlags._(1 << 3);
|
||||
static const LoadUrlFlags BYPASS_CLASSIFIER = LoadUrlFlags._(1 << 4);
|
||||
static const LoadUrlFlags LOAD_FLAGS_FORCE_ALLOW_DATA_URI =
|
||||
LoadUrlFlags._(1 << 5);
|
||||
static const LoadUrlFlags LOAD_FLAGS_REPLACE_HISTORY = LoadUrlFlags._(1 << 6);
|
||||
static const LoadUrlFlags LOAD_FLAGS_BYPASS_LOAD_URI_DELEGATE =
|
||||
LoadUrlFlags._(1 << 7);
|
||||
static const LoadUrlFlags ALLOW_ADDITIONAL_HEADERS = LoadUrlFlags._(1 << 15);
|
||||
static const LoadUrlFlags ALLOW_JAVASCRIPT_URL = LoadUrlFlags._(1 << 16);
|
||||
|
||||
static LoadUrlFlags ALL = LoadUrlFlags._(
|
||||
BYPASS_CACHE.value |
|
||||
BYPASS_PROXY.value |
|
||||
EXTERNAL.value |
|
||||
ALLOW_POPUPS.value |
|
||||
BYPASS_CLASSIFIER.value |
|
||||
LOAD_FLAGS_FORCE_ALLOW_DATA_URI.value |
|
||||
LOAD_FLAGS_REPLACE_HISTORY.value |
|
||||
LOAD_FLAGS_BYPASS_LOAD_URI_DELEGATE.value |
|
||||
ALLOW_ADDITIONAL_HEADERS.value |
|
||||
ALLOW_JAVASCRIPT_URL.value,
|
||||
);
|
||||
|
||||
static LoadUrlFlags select(List<LoadUrlFlags> flags) {
|
||||
int combinedValue = flags.fold(0, (sum, flag) => sum | flag.value);
|
||||
return LoadUrlFlags._(combinedValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
import 'package:flutter_mozilla_components/src/helper/helper.dart';
|
||||
import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart';
|
||||
|
||||
/// Describes a category of an external package.
|
||||
enum PackageCategory {
|
||||
unknown(-1),
|
||||
game(0),
|
||||
audio(1),
|
||||
video(2),
|
||||
image(3),
|
||||
social(4),
|
||||
news(5),
|
||||
maps(6),
|
||||
productivity(7);
|
||||
|
||||
final int id;
|
||||
const PackageCategory(this.id);
|
||||
|
||||
PackageCategoryValue toValue() {
|
||||
return PackageCategoryValue(value: id);
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the origin of a session to describe how and why it was created.
|
||||
abstract class Source {
|
||||
final int id;
|
||||
|
||||
const Source(this.id);
|
||||
|
||||
SourceValue toValue();
|
||||
|
||||
/// Initializes a [Source] of a correct type from its component properties.
|
||||
/// Intended use is for restoring persisted state.
|
||||
static Source restore(
|
||||
int? sourceId, String? packageId, int? packageCategory) {
|
||||
final caller = packageId != null
|
||||
? ExternalPackage(
|
||||
packageId: packageId,
|
||||
category: packageCategoryfromInt(packageCategory).toValue())
|
||||
: null;
|
||||
|
||||
switch (sourceId) {
|
||||
case 1:
|
||||
return External.actionSend(caller);
|
||||
case 2:
|
||||
return External.actionView(caller);
|
||||
case 3:
|
||||
return External.actionSearch(caller);
|
||||
case 4:
|
||||
return External.customTab(caller);
|
||||
case 5:
|
||||
return Internal.homeScreen;
|
||||
case 6:
|
||||
return Internal.menu;
|
||||
case 7:
|
||||
return Internal.newTab;
|
||||
case 8:
|
||||
return Internal.none;
|
||||
case 9:
|
||||
return Internal.textSelection;
|
||||
case 10:
|
||||
return Internal.userEntered;
|
||||
case 11:
|
||||
return Internal.customTab;
|
||||
default:
|
||||
return Internal.none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes sessions of external origins, i.e. from outside of the application.
|
||||
abstract class External extends Source {
|
||||
final ExternalPackage? caller;
|
||||
|
||||
const External(super.id, this.caller);
|
||||
|
||||
@override
|
||||
SourceValue toValue() {
|
||||
return SourceValue(id: id, caller: caller);
|
||||
}
|
||||
|
||||
/// Created to handle an ACTION_SEND (share) intent.
|
||||
factory External.actionSend(ExternalPackage? caller) = ActionSend;
|
||||
|
||||
/// Created to handle an ACTION_VIEW intent.
|
||||
factory External.actionView(ExternalPackage? caller) = ActionView;
|
||||
|
||||
/// Created to handle an ACTION_SEARCH and ACTION_WEB_SEARCH intent.
|
||||
factory External.actionSearch(ExternalPackage? caller) = ActionSearch;
|
||||
|
||||
/// Created to handle a CustomTabs intent of external origin.
|
||||
factory External.customTab(ExternalPackage? caller) = CustomTab;
|
||||
}
|
||||
|
||||
class ActionSend extends External {
|
||||
const ActionSend(ExternalPackage? caller) : super(1, caller);
|
||||
}
|
||||
|
||||
class ActionView extends External {
|
||||
const ActionView(ExternalPackage? caller) : super(2, caller);
|
||||
}
|
||||
|
||||
class ActionSearch extends External {
|
||||
const ActionSearch(ExternalPackage? caller) : super(3, caller);
|
||||
}
|
||||
|
||||
class CustomTab extends External {
|
||||
const CustomTab(ExternalPackage? caller) : super(4, caller);
|
||||
}
|
||||
|
||||
/// Describes sessions of internal origin, i.e. from within of the application.
|
||||
abstract class Internal extends Source {
|
||||
const Internal(super.id);
|
||||
|
||||
@override
|
||||
SourceValue toValue() {
|
||||
return SourceValue(id: id);
|
||||
}
|
||||
|
||||
/// User interacted with the home screen.
|
||||
static const homeScreen = _HomeScreen();
|
||||
|
||||
/// User interacted with a menu.
|
||||
static const menu = _Menu();
|
||||
|
||||
/// User opened a new tab.
|
||||
static const newTab = _NewTab();
|
||||
|
||||
/// Default value and for testing purposes.
|
||||
static const none = _None();
|
||||
|
||||
/// User selected text.
|
||||
static const textSelection = _TextSelection();
|
||||
|
||||
/// User entered a URL or search term.
|
||||
static const userEntered = _UserEntered();
|
||||
|
||||
/// Created to handle a CustomTabs intent of internal origin.
|
||||
static const customTab = _CustomTab();
|
||||
}
|
||||
|
||||
class _HomeScreen extends Internal {
|
||||
const _HomeScreen() : super(5);
|
||||
}
|
||||
|
||||
class _Menu extends Internal {
|
||||
const _Menu() : super(6);
|
||||
}
|
||||
|
||||
class _NewTab extends Internal {
|
||||
const _NewTab() : super(7);
|
||||
}
|
||||
|
||||
class _None extends Internal {
|
||||
const _None() : super(8);
|
||||
}
|
||||
|
||||
class _TextSelection extends Internal {
|
||||
const _TextSelection() : super(9);
|
||||
}
|
||||
|
||||
class _UserEntered extends Internal {
|
||||
const _UserEntered() : super(10);
|
||||
}
|
||||
|
||||
class _CustomTab extends Internal {
|
||||
const _CustomTab() : super(11);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart';
|
||||
|
||||
class GeckoBrowserService {
|
||||
final GeckoBrowserApi _api;
|
||||
|
||||
GeckoBrowserService({GeckoBrowserApi? api}) : _api = api ?? GeckoBrowserApi();
|
||||
|
||||
Future<void> showNativeFragment() {
|
||||
return _api.showNativeFragment();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
import 'package:flutter_mozilla_components/src/data/models/load_url_flags.dart';
|
||||
import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart';
|
||||
|
||||
class GeckoSessionService {
|
||||
final String? tabId;
|
||||
final GeckoSessionApi _api;
|
||||
|
||||
GeckoSessionService.forCurrentTab({GeckoSessionApi? api})
|
||||
: _api = api ?? GeckoSessionApi(),
|
||||
tabId = null;
|
||||
|
||||
GeckoSessionService({required String this.tabId, GeckoSessionApi? api})
|
||||
: _api = api ?? GeckoSessionApi();
|
||||
|
||||
Future<void> loadUrl({
|
||||
required Uri url,
|
||||
LoadUrlFlags flags = LoadUrlFlags.NONE,
|
||||
Map<String, String>? additionalHeaders,
|
||||
}) {
|
||||
return _api.loadUrl(
|
||||
tabId: tabId,
|
||||
url: url.toString(),
|
||||
flags: flags.toValue(),
|
||||
additionalHeaders: additionalHeaders,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> loadData({
|
||||
required String data,
|
||||
required String mimeType,
|
||||
String encoding = "UTF-8",
|
||||
}) {
|
||||
return _api.loadData(
|
||||
tabId: tabId,
|
||||
data: data,
|
||||
mimeType: mimeType,
|
||||
encoding: encoding,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> reload({LoadUrlFlags flags = LoadUrlFlags.NONE}) {
|
||||
return _api.reload(
|
||||
tabId: tabId,
|
||||
flags: flags.toValue(),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> stopLoading() {
|
||||
return _api.stopLoading(tabId: tabId);
|
||||
}
|
||||
|
||||
Future<void> goBack({bool userInteraction = true}) {
|
||||
return _api.goBack(
|
||||
tabId: tabId,
|
||||
userInteraction: userInteraction,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> goForward({bool userInteraction = true}) {
|
||||
return _api.goForward(
|
||||
tabId: tabId,
|
||||
userInteraction: userInteraction,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> goToHistoryIndex({required int index}) {
|
||||
return _api.goToHistoryIndex(
|
||||
index: index,
|
||||
tabId: tabId,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> requestDesktopSite({required bool enable}) {
|
||||
return _api.requestDesktopSite(
|
||||
enable: enable,
|
||||
tabId: tabId,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> exitFullscreen() {
|
||||
return _api.exitFullscreen(tabId: tabId);
|
||||
}
|
||||
|
||||
Future<void> saveToPdf() {
|
||||
return _api.saveToPdf(tabId: tabId);
|
||||
}
|
||||
|
||||
Future<void> printContent() {
|
||||
return _api.printContent(tabId: tabId);
|
||||
}
|
||||
|
||||
Future<void> translate({
|
||||
required String fromLanguage,
|
||||
required String toLanguage,
|
||||
TranslationOptions? options,
|
||||
}) {
|
||||
return _api.translate(
|
||||
tabId: tabId,
|
||||
fromLanguage: fromLanguage,
|
||||
toLanguage: toLanguage,
|
||||
options: options,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> translateRestore() {
|
||||
return _api.translateRestore(tabId: tabId);
|
||||
}
|
||||
|
||||
Future<void> crashRecovery({
|
||||
List<String>? tabIds,
|
||||
}) {
|
||||
return _api.crashRecovery(tabIds: tabIds);
|
||||
}
|
||||
|
||||
Future<void> purgeHistory() {
|
||||
return _api.purgeHistory();
|
||||
}
|
||||
|
||||
Future<void> updateLastAccess({
|
||||
String? tabId, //If null = current tab
|
||||
DateTime? lastAccess, //If null datetime.now
|
||||
}) {
|
||||
return _api.updateLastAccess(
|
||||
tabId: tabId,
|
||||
lastAccess: (lastAccess ?? DateTime.now()).millisecondsSinceEpoch,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
import 'package:flutter_mozilla_components/src/data/models/load_url_flags.dart';
|
||||
import 'package:flutter_mozilla_components/src/data/models/source.dart';
|
||||
import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart';
|
||||
|
||||
class GeckoTabsService {
|
||||
final GeckoTabsApi _api;
|
||||
|
||||
GeckoTabsService({GeckoTabsApi? api}) : _api = api ?? GeckoTabsApi();
|
||||
|
||||
Future<void> selectTab({required String tabId}) {
|
||||
return _api.selectTab(tabId: tabId);
|
||||
}
|
||||
|
||||
Future<void> removeTab({required String tabId}) {
|
||||
return _api.removeTab(tabId: tabId);
|
||||
}
|
||||
|
||||
Future<String> addTab({
|
||||
Uri? url,
|
||||
bool selectTab = true,
|
||||
bool startLoading = true,
|
||||
String? parentId,
|
||||
LoadUrlFlags flags = LoadUrlFlags.NONE,
|
||||
String? contextId,
|
||||
Source source = Internal.newTab,
|
||||
bool private = false,
|
||||
HistoryMetadataKey? historyMetadata,
|
||||
Map<String, String>? additionalHeaders,
|
||||
}) {
|
||||
return _api.addTab(
|
||||
url: (url ?? Uri.parse('about:blank')).toString(),
|
||||
selectTab: selectTab,
|
||||
startLoading: startLoading,
|
||||
parentId: parentId,
|
||||
flags: flags.toValue(),
|
||||
contextId: contextId,
|
||||
source: source.toValue(),
|
||||
private: private,
|
||||
historyMetadata: historyMetadata,
|
||||
additionalHeaders: additionalHeaders,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> removeAllTabs({required bool recoverable}) {
|
||||
return _api.removeAllTabs(recoverable: recoverable);
|
||||
}
|
||||
|
||||
Future<void> removeTabs({required List<String> ids}) {
|
||||
return _api.removeTabs(ids: ids);
|
||||
}
|
||||
|
||||
Future<void> removeNormalTabs() {
|
||||
return _api.removeNormalTabs();
|
||||
}
|
||||
|
||||
Future<void> removePrivateTabs() {
|
||||
return _api.removePrivateTabs();
|
||||
}
|
||||
|
||||
Future<void> undo() {
|
||||
return _api.undo();
|
||||
}
|
||||
|
||||
//restoreTabs invokes splitted
|
||||
Future<void> restoreTabsByList({
|
||||
required List<RecoverableTab> tabs,
|
||||
String? selectTabId,
|
||||
RestoreLocation restoreLocation = RestoreLocation.end,
|
||||
}) {
|
||||
return _api.restoreTabsByList(
|
||||
tabs: tabs, selectTabId: selectTabId, restoreLocation: restoreLocation);
|
||||
}
|
||||
|
||||
Future<void> restoreTabsByBrowserState({
|
||||
required RecoverableBrowserState state,
|
||||
RestoreLocation restoreLocation = RestoreLocation.end,
|
||||
}) {
|
||||
return _api.restoreTabsByBrowserState(
|
||||
state: state, restoreLocation: restoreLocation);
|
||||
}
|
||||
//The calls with engin storage for restore are not supported at the moment
|
||||
|
||||
//selectOrAddTab invokes splitted
|
||||
/// Selects an already existing tab with the matching [HistoryMetadataKey] or otherwise
|
||||
/// creates a new tab with the given [url].
|
||||
Future<String> selectOrAddTabByHistory({
|
||||
required Uri url,
|
||||
required HistoryMetadataKey historyMetadata,
|
||||
}) {
|
||||
return _api.selectOrAddTabByHistory(
|
||||
url: url.toString(), historyMetadata: historyMetadata);
|
||||
}
|
||||
|
||||
/// Selects an already existing tab displaying [url] or otherwise creates a new tab.
|
||||
Future<String> selectOrAddTabByUrl({
|
||||
required Uri url,
|
||||
bool private = false,
|
||||
Source source = Internal.newTab,
|
||||
LoadUrlFlags flags = LoadUrlFlags.NONE,
|
||||
bool ignoreFragment = false,
|
||||
}) {
|
||||
return _api.selectOrAddTabByUrl(
|
||||
url: url.toString(),
|
||||
private: private,
|
||||
source: source.toValue(),
|
||||
flags: flags.toValue(),
|
||||
ignoreFragment: ignoreFragment,
|
||||
);
|
||||
}
|
||||
|
||||
Future<String> duplicateTab({
|
||||
String? selectTabId,
|
||||
bool selectNewTab = true,
|
||||
}) {
|
||||
return _api.duplicateTab(
|
||||
selectTabId: selectTabId, selectNewTab: selectNewTab);
|
||||
}
|
||||
|
||||
Future<void> moveTabs({
|
||||
required List<String> tabIds,
|
||||
required String targetTabId,
|
||||
required bool placeAfter,
|
||||
}) {
|
||||
return _api.moveTabs(
|
||||
tabIds: tabIds, targetTabId: targetTabId, placeAfter: placeAfter);
|
||||
}
|
||||
|
||||
Future<String> migratePrivateTabUseCase({
|
||||
required String tabId,
|
||||
Uri? alternativeUrl,
|
||||
}) {
|
||||
return _api.migratePrivateTabUseCase(
|
||||
tabId: tabId, alternativeUrl: alternativeUrl?.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mozilla_components/src/domain/services/gecko_browser.dart';
|
||||
|
||||
class GeckoView extends StatelessWidget {
|
||||
const GeckoView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PlatformViewLink(
|
||||
viewType: 'eu.lensai/gecko',
|
||||
surfaceFactory: (
|
||||
context,
|
||||
controller,
|
||||
) {
|
||||
return AndroidViewSurface(
|
||||
controller: controller as AndroidViewController,
|
||||
gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{},
|
||||
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
||||
);
|
||||
},
|
||||
onCreatePlatformView: (PlatformViewCreationParams params) {
|
||||
return PlatformViewsService.initExpensiveAndroidView(
|
||||
id: params.id,
|
||||
viewType: 'eu.lensai/gecko',
|
||||
layoutDirection: TextDirection.ltr,
|
||||
creationParams: {},
|
||||
creationParamsCodec: const StandardMessageCodec(),
|
||||
)
|
||||
..addOnPlatformViewCreatedListener((value) async {
|
||||
params.onPlatformViewCreated(value);
|
||||
|
||||
SchedulerBinding.instance.addPostFrameCallback((_) async {
|
||||
await GeckoBrowserService().showNativeFragment();
|
||||
});
|
||||
})
|
||||
..create();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:flutter_mozilla_components/src/data/models/source.dart';
|
||||
|
||||
/// Maps an int category (as it can be obtained from a package manager) to our internal representation.
|
||||
PackageCategory packageCategoryfromInt(int? id) {
|
||||
return PackageCategory.values.firstWhere(
|
||||
(category) => category.id == id,
|
||||
orElse: () => PackageCategory.unknown,
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user