mainly refactoring & addons

This commit is contained in:
Fabian Freund
2024-10-29 10:03:24 +01:00
parent 91a4319b28
commit 0710116feb
127 changed files with 4234 additions and 1815 deletions
@@ -0,0 +1,44 @@
import 'dart:ui';
import 'package:copy_with_extension/copy_with_extension.dart';
import 'package:fast_equatable/fast_equatable.dart';
import 'package:lensai/domain/entities/equatable_image.dart';
part 'web_extension_state.g.dart';
@CopyWith()
class WebExtensionState with FastEquatable {
String extensionId;
String? title;
bool enabled;
String? badgeText;
Color? badgeTextColor;
Color? badgeBackgroundColor;
final EquatableImage? icon;
WebExtensionState({
required this.extensionId,
required this.enabled,
this.title,
this.badgeText,
this.badgeTextColor,
this.badgeBackgroundColor,
this.icon,
});
@override
bool get cacheHash => true;
@override
List<Object?> get hashParameters => [
extensionId,
title,
enabled,
badgeText,
badgeTextColor,
badgeBackgroundColor,
icon,
];
}
@@ -0,0 +1,127 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'web_extension_state.dart';
// **************************************************************************
// CopyWithGenerator
// **************************************************************************
abstract class _$WebExtensionStateCWProxy {
WebExtensionState extensionId(String extensionId);
WebExtensionState enabled(bool enabled);
WebExtensionState title(String? title);
WebExtensionState badgeText(String? badgeText);
WebExtensionState badgeTextColor(Color? badgeTextColor);
WebExtensionState badgeBackgroundColor(Color? badgeBackgroundColor);
WebExtensionState icon(EquatableImage? icon);
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `WebExtensionState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
///
/// Usage
/// ```dart
/// WebExtensionState(...).copyWith(id: 12, name: "My name")
/// ````
WebExtensionState call({
String? extensionId,
bool? enabled,
String? title,
String? badgeText,
Color? badgeTextColor,
Color? badgeBackgroundColor,
EquatableImage? icon,
});
}
/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfWebExtensionState.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfWebExtensionState.copyWith.fieldName(...)`
class _$WebExtensionStateCWProxyImpl implements _$WebExtensionStateCWProxy {
const _$WebExtensionStateCWProxyImpl(this._value);
final WebExtensionState _value;
@override
WebExtensionState extensionId(String extensionId) =>
this(extensionId: extensionId);
@override
WebExtensionState enabled(bool enabled) => this(enabled: enabled);
@override
WebExtensionState title(String? title) => this(title: title);
@override
WebExtensionState badgeText(String? badgeText) => this(badgeText: badgeText);
@override
WebExtensionState badgeTextColor(Color? badgeTextColor) =>
this(badgeTextColor: badgeTextColor);
@override
WebExtensionState badgeBackgroundColor(Color? badgeBackgroundColor) =>
this(badgeBackgroundColor: badgeBackgroundColor);
@override
WebExtensionState icon(EquatableImage? icon) => this(icon: icon);
@override
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `WebExtensionState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
///
/// Usage
/// ```dart
/// WebExtensionState(...).copyWith(id: 12, name: "My name")
/// ````
WebExtensionState call({
Object? extensionId = const $CopyWithPlaceholder(),
Object? enabled = const $CopyWithPlaceholder(),
Object? title = const $CopyWithPlaceholder(),
Object? badgeText = const $CopyWithPlaceholder(),
Object? badgeTextColor = const $CopyWithPlaceholder(),
Object? badgeBackgroundColor = const $CopyWithPlaceholder(),
Object? icon = const $CopyWithPlaceholder(),
}) {
return WebExtensionState(
extensionId:
extensionId == const $CopyWithPlaceholder() || extensionId == null
? _value.extensionId
// ignore: cast_nullable_to_non_nullable
: extensionId as String,
enabled: enabled == const $CopyWithPlaceholder() || enabled == null
? _value.enabled
// ignore: cast_nullable_to_non_nullable
: enabled as bool,
title: title == const $CopyWithPlaceholder()
? _value.title
// ignore: cast_nullable_to_non_nullable
: title as String?,
badgeText: badgeText == const $CopyWithPlaceholder()
? _value.badgeText
// ignore: cast_nullable_to_non_nullable
: badgeText as String?,
badgeTextColor: badgeTextColor == const $CopyWithPlaceholder()
? _value.badgeTextColor
// ignore: cast_nullable_to_non_nullable
: badgeTextColor as Color?,
badgeBackgroundColor: badgeBackgroundColor == const $CopyWithPlaceholder()
? _value.badgeBackgroundColor
// ignore: cast_nullable_to_non_nullable
: badgeBackgroundColor as Color?,
icon: icon == const $CopyWithPlaceholder()
? _value.icon
// ignore: cast_nullable_to_non_nullable
: icon as EquatableImage?,
);
}
}
extension $WebExtensionStateCopyWith on WebExtensionState {
/// Returns a callable class that can be used as follows: `instanceOfWebExtensionState.copyWith(...)` or like so:`instanceOfWebExtensionState.copyWith.fieldName(...)`.
// ignore: library_private_types_in_public_api
_$WebExtensionStateCWProxy get copyWith =>
_$WebExtensionStateCWProxyImpl(this);
}
@@ -5,6 +5,7 @@ import 'package:lensai/core/logger.dart';
import 'package:lensai/features/bangs/domain/providers.dart';
import 'package:lensai/features/geckoview/domain/providers/tab_session.dart';
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:share_plus/share_plus.dart';
import 'package:url_launcher/url_launcher.dart';
@@ -13,7 +14,7 @@ part 'providers.g.dart';
@Riverpod(keepAlive: true)
GeckoSelectionActionService selectionActionService(
SelectionActionServiceRef ref,
Ref ref,
) {
final service = GeckoSelectionActionService.setUp();
@@ -74,7 +75,7 @@ GeckoSelectionActionService selectionActionService(
}
@Riverpod(keepAlive: true)
GeckoEventService eventService(EventServiceRef ref) {
GeckoEventService eventService(Ref ref) {
final service = GeckoEventService.setUp();
ref.onDispose(() {
@@ -84,6 +85,17 @@ GeckoEventService eventService(EventServiceRef ref) {
return service;
}
@Riverpod(keepAlive: true)
GeckoAddonService addonService(Ref ref) {
final service = GeckoAddonService.setUp();
ref.onDispose(() {
service.dispose();
});
return service;
}
@Riverpod(keepAlive: true)
class EngineReadyState extends _$EngineReadyState {
@override
@@ -120,6 +132,6 @@ class EngineReadyState extends _$EngineReadyState {
}
@Riverpod()
Raw<TabSession> selectedTabSessionNotifier(SelectedTabSessionNotifierRef ref) {
Raw<TabSession> selectedTabSessionNotifier(Ref ref) {
return ref.watch(tabSessionProvider(null).notifier);
}
@@ -7,7 +7,7 @@ part of 'providers.dart';
// **************************************************************************
String _$selectionActionServiceHash() =>
r'c150f6003dcea80b18fc063dd998ab45ce27d1a1';
r'b5bc6b2bc5496ae84d61a74cc6ff052b55d2a3d3';
/// See also [selectionActionService].
@ProviderFor(selectionActionService)
@@ -22,8 +22,10 @@ final selectionActionServiceProvider =
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef SelectionActionServiceRef = ProviderRef<GeckoSelectionActionService>;
String _$eventServiceHash() => r'5aa357fdf0d217677a9a66ecb50417ac18929cad';
String _$eventServiceHash() => r'166b01f636fbdd4355dbc55a18ca4f83e0006de8';
/// See also [eventService].
@ProviderFor(eventService)
@@ -36,9 +38,27 @@ final eventServiceProvider = Provider<GeckoEventService>.internal(
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef EventServiceRef = ProviderRef<GeckoEventService>;
String _$addonServiceHash() => r'c7aca09b99c3810908176f3464f5f90a185aa5e7';
/// See also [addonService].
@ProviderFor(addonService)
final addonServiceProvider = Provider<GeckoAddonService>.internal(
addonService,
name: r'addonServiceProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$addonServiceHash,
dependencies: null,
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef AddonServiceRef = ProviderRef<GeckoAddonService>;
String _$selectedTabSessionNotifierHash() =>
r'ea9959e871dd0c3a8b80152eafe726c925094106';
r'62fcd98a915566d55b5bcb297d87d675fe12786d';
/// See also [selectedTabSessionNotifier].
@ProviderFor(selectedTabSessionNotifier)
@@ -53,6 +73,8 @@ final selectedTabSessionNotifierProvider =
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef SelectedTabSessionNotifierRef = AutoDisposeProviderRef<Raw<TabSession>>;
String _$engineReadyStateHash() => r'c682333e2e07cf0635aa7ae793a2088ca648c950';
@@ -71,4 +93,4 @@ final engineReadyStateProvider =
typedef _$EngineReadyState = Notifier<bool>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
// 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
@@ -21,4 +21,4 @@ final selectedTabProvider = NotifierProvider<SelectedTab, String?>.internal(
typedef _$SelectedTab = Notifier<String?>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
// 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
@@ -13,6 +13,7 @@ part 'tab_list.g.dart';
class TabList extends _$TabList {
late TabDatabase _db;
@override
List<String> build() {
final eventService = ref.watch(eventServiceProvider);
@@ -6,7 +6,7 @@ part of 'tab_list.dart';
// RiverpodGenerator
// **************************************************************************
String _$tabListHash() => r'fd97d4692b1c74e91c5ebd4a75e6ff45ceb82ef9';
String _$tabListHash() => r'3c17372cc467736ce1cfba937999acf4de7345ef';
/// See also [TabList].
@ProviderFor(TabList)
@@ -21,4 +21,4 @@ final tabListProvider = NotifierProvider<TabList, List<String>>.internal(
typedef _$TabList = Notifier<List<String>>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
// 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
@@ -37,8 +37,8 @@ class TabSession extends _$TabSession {
return _sessionService.exitFullscreen();
}
Future<Uint8List?> requestScreenshot() {
return _sessionService.requestScreenshot();
Future<Uint8List?> requestScreenshot({bool requireImageResult = true}) {
return _sessionService.requestScreenshot(requireImageResult);
}
@override
@@ -6,7 +6,7 @@ part of 'tab_session.dart';
// RiverpodGenerator
// **************************************************************************
String _$tabSessionHash() => r'29b20f40af01e599ef80e198aec5f093d74efc6a';
String _$tabSessionHash() => r'42b44a4d47b9a551d002fdbc6337c14b2c327dde';
/// Copied from Dart SDK
class _SystemHash {
@@ -155,6 +155,8 @@ class TabSessionProvider
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
mixin TabSessionRef on AutoDisposeNotifierProviderRef<void> {
/// The parameter `tabId` of this provider.
String? get tabId;
@@ -169,4 +171,4 @@ class _TabSessionProviderElement
String? get tabId => (origin as TabSessionProvider).tabId;
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
// 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
@@ -10,6 +10,7 @@ import 'package:lensai/features/geckoview/domain/entities/tab_state.dart';
import 'package:lensai/features/geckoview/domain/providers.dart';
import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart';
import 'package:lensai/features/geckoview/utils/image_helper.dart';
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:synchronized/synchronized.dart';
@@ -190,7 +191,7 @@ class TabStates extends _$TabStates {
}
@Riverpod()
TabState? tabState(TabStateRef ref, String? tabId) {
TabState? tabState(Ref ref, String? tabId) {
if (tabId == null) {
return null;
}
@@ -201,7 +202,7 @@ TabState? tabState(TabStateRef ref, String? tabId) {
}
@Riverpod()
TabState? selectedTabState(SelectedTabStateRef ref) {
TabState? selectedTabState(Ref ref) {
final tabId = ref.watch(selectedTabProvider);
return ref.watch(tabStateProvider(tabId));
}
@@ -6,7 +6,7 @@ part of 'tab_state.dart';
// RiverpodGenerator
// **************************************************************************
String _$tabStateHash() => r'9fd7990804643fac180dd4fd50803bc7c9fa2827';
String _$tabStateHash() => r'f57b2353acc99ca73670d504b45ea5ff19df38c7';
/// Copied from Dart SDK
class _SystemHash {
@@ -141,6 +141,8 @@ class TabStateProvider extends AutoDisposeProvider<TabState?> {
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
mixin TabStateRef on AutoDisposeProviderRef<TabState?> {
/// The parameter `tabId` of this provider.
String? get tabId;
@@ -154,7 +156,7 @@ class _TabStateProviderElement extends AutoDisposeProviderElement<TabState?>
String? get tabId => (origin as TabStateProvider).tabId;
}
String _$selectedTabStateHash() => r'22172913554e14e67f692eff0777ea015175906e';
String _$selectedTabStateHash() => r'dbd36af7af286bd9d079f30e8e11bbda23bf7728';
/// See also [selectedTabState].
@ProviderFor(selectedTabState)
@@ -168,6 +170,8 @@ final selectedTabStateProvider = AutoDisposeProvider<TabState?>.internal(
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef SelectedTabStateRef = AutoDisposeProviderRef<TabState?>;
String _$tabStatesHash() => r'dcd293279a901eeaab7728979e39e5ca3bee8c66';
@@ -185,4 +189,4 @@ final tabStatesProvider =
typedef _$TabStates = Notifier<Map<String, TabState>>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
// 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
@@ -0,0 +1,107 @@
import 'dart:async';
import 'dart:ui';
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
import 'package:lensai/domain/entities/equatable_image.dart';
import 'package:lensai/extensions/image.dart';
import 'package:lensai/features/geckoview/domain/entities/web_extension_state.dart';
import 'package:lensai/features/geckoview/domain/providers.dart';
import 'package:lensai/features/geckoview/utils/image_helper.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:synchronized/synchronized.dart';
part 'web_extensions_state.g.dart';
@Riverpod(keepAlive: true)
class WebExtensionsState extends _$WebExtensionsState {
final _imageCache = <String, EquatableImage>{};
final _lock = Lock();
void _onExtensionUpdate(ExtensionDataEvent event) {
final ExtensionDataEvent(:extensionId, :data) = event;
if (data != null) {
final current = state[extensionId] ??
WebExtensionState(
extensionId: extensionId,
icon: _imageCache[extensionId],
enabled: false,
);
state = {...state}..[extensionId] = current.copyWith(
title: data.title,
enabled: data.enabled,
badgeText: data.badgeText,
badgeTextColor: (data.badgeTextColor != null)
? Color(data.badgeTextColor!)
: null,
badgeBackgroundColor: (data.badgeBackgroundColor != null)
? Color(data.badgeBackgroundColor!)
: null,
);
} else {
if (state.containsKey(extensionId)) {
state = {...state}..remove(extensionId);
}
}
}
Future<void> _onIconChange(ExtensionIconEvent event) async {
final ExtensionIconEvent(:extensionId, :bytes) = event;
final image =
await tryDecodeImage(bytes).then((image) async => image?.toEquatable());
if (image != null) {
if (_imageCache[extensionId] != image) {
_imageCache[extensionId] = image;
if (state.containsKey(extensionId)) {
state = {...state}..[extensionId] =
state[extensionId]!.copyWith.icon(image);
}
}
}
}
@override
Map<String, WebExtensionState> build(WebExtensionActionType actionType) {
final addonService = ref.watch(addonServiceProvider);
final subscriptions = switch (actionType) {
WebExtensionActionType.browser => [
addonService.browserExtensionStream.listen(
(event) async {
await _lock.synchronized(() => _onExtensionUpdate(event));
},
),
addonService.browserIconStream.listen(
(event) async {
await _lock.synchronized(() => _onIconChange(event));
},
),
],
WebExtensionActionType.page => [
addonService.pageExtensionStream.listen(
(event) async {
await _lock.synchronized(() => _onExtensionUpdate(event));
},
),
addonService.pageIconStream.listen(
(event) async {
await _lock.synchronized(() => _onIconChange(event));
},
),
],
};
ref.onDispose(() {
for (final sub in subscriptions) {
unawaited(sub.cancel());
}
});
return {};
}
}
@@ -0,0 +1,180 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'web_extensions_state.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$webExtensionsStateHash() =>
r'9ac102b1d1740d69f9b0de590f08ff0774064845';
/// 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));
}
}
abstract class _$WebExtensionsState
extends BuildlessNotifier<Map<String, WebExtensionState>> {
late final WebExtensionActionType actionType;
Map<String, WebExtensionState> build(
WebExtensionActionType actionType,
);
}
/// See also [WebExtensionsState].
@ProviderFor(WebExtensionsState)
const webExtensionsStateProvider = WebExtensionsStateFamily();
/// See also [WebExtensionsState].
class WebExtensionsStateFamily extends Family<Map<String, WebExtensionState>> {
/// See also [WebExtensionsState].
const WebExtensionsStateFamily();
/// See also [WebExtensionsState].
WebExtensionsStateProvider call(
WebExtensionActionType actionType,
) {
return WebExtensionsStateProvider(
actionType,
);
}
@override
WebExtensionsStateProvider getProviderOverride(
covariant WebExtensionsStateProvider provider,
) {
return call(
provider.actionType,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'webExtensionsStateProvider';
}
/// See also [WebExtensionsState].
class WebExtensionsStateProvider extends NotifierProviderImpl<
WebExtensionsState, Map<String, WebExtensionState>> {
/// See also [WebExtensionsState].
WebExtensionsStateProvider(
WebExtensionActionType actionType,
) : this._internal(
() => WebExtensionsState()..actionType = actionType,
from: webExtensionsStateProvider,
name: r'webExtensionsStateProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$webExtensionsStateHash,
dependencies: WebExtensionsStateFamily._dependencies,
allTransitiveDependencies:
WebExtensionsStateFamily._allTransitiveDependencies,
actionType: actionType,
);
WebExtensionsStateProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.actionType,
}) : super.internal();
final WebExtensionActionType actionType;
@override
Map<String, WebExtensionState> runNotifierBuild(
covariant WebExtensionsState notifier,
) {
return notifier.build(
actionType,
);
}
@override
Override overrideWith(WebExtensionsState Function() create) {
return ProviderOverride(
origin: this,
override: WebExtensionsStateProvider._internal(
() => create()..actionType = actionType,
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
actionType: actionType,
),
);
}
@override
NotifierProviderElement<WebExtensionsState, Map<String, WebExtensionState>>
createElement() {
return _WebExtensionsStateProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is WebExtensionsStateProvider &&
other.actionType == actionType;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, actionType.hashCode);
return _SystemHash.finish(hash);
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
mixin WebExtensionsStateRef
on NotifierProviderRef<Map<String, WebExtensionState>> {
/// The parameter `actionType` of this provider.
WebExtensionActionType get actionType;
}
class _WebExtensionsStateProviderElement extends NotifierProviderElement<
WebExtensionsState,
Map<String, WebExtensionState>> with WebExtensionsStateRef {
_WebExtensionsStateProviderElement(super.provider);
@override
WebExtensionActionType get actionType =>
(origin as WebExtensionsStateProvider).actionType;
}
// 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
@@ -22,4 +22,4 @@ final tabRepositoryProvider = NotifierProvider<TabRepository, void>.internal(
typedef _$TabRepository = Notifier<void>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
// 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