getting there
This commit is contained in:
Vendored
+23
@@ -26,6 +26,29 @@
|
||||
"type": "dart",
|
||||
"flutterMode": "release",
|
||||
"args": ["--device-user", "0"]
|
||||
},
|
||||
{
|
||||
"name": "example",
|
||||
"cwd": "packages/flutter_mozilla_components/example",
|
||||
"request": "launch",
|
||||
"type": "dart",
|
||||
"args": ["--device-user", "0"]
|
||||
},
|
||||
{
|
||||
"name": "example (profile mode)",
|
||||
"cwd": "packages/flutter_mozilla_components/example",
|
||||
"request": "launch",
|
||||
"type": "dart",
|
||||
"flutterMode": "profile",
|
||||
"args": ["--device-user", "0"]
|
||||
},
|
||||
{
|
||||
"name": "example (release mode)",
|
||||
"cwd": "packages/flutter_mozilla_components/example",
|
||||
"request": "launch",
|
||||
"type": "dart",
|
||||
"flutterMode": "release",
|
||||
"args": ["--device-user", "0"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,10 +1,47 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<!-- This is needed because the android.permission.CAMERA above automatically
|
||||
adds a requirements for camera hardware and we don't want add those restrictions -->
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera.autofocus"
|
||||
android:required="false" />
|
||||
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="28" />
|
||||
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
|
||||
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<!-- Needed for uploading media files on devices with Android 13 and later. -->
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
|
||||
|
||||
<application
|
||||
android:label="Lensai"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/launcher_icon"
|
||||
android:usesCleartextTraffic="true">
|
||||
<activity android:name="eu.lensai.flutter_mozilla_components.NotificationActivity" android:theme="@style/Theme.AppCompat.Translucent" />
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
@@ -46,6 +83,7 @@
|
||||
<data android:mimeType="application/pdf" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<receiver android:name="FullWidgetProvider" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
@@ -54,6 +92,7 @@
|
||||
<meta-data android:name="android.appwidget.provider"
|
||||
android:resource="@xml/full_widget_info"/>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name="CompactWidgetProvider" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
@@ -62,6 +101,7 @@
|
||||
<meta-data android:name="android.appwidget.provider"
|
||||
android:resource="@xml/compact_widget_info"/>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name="SearchBarWidgetProvider" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
@@ -70,6 +110,15 @@
|
||||
<meta-data android:name="android.appwidget.provider"
|
||||
android:resource="@xml/search_bar_widget_info"/>
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name="eu.lensai.flutter_mozilla_components.DownloadService"
|
||||
android:foregroundServiceType="dataSync" />
|
||||
|
||||
<service android:name="eu.lensai.flutter_mozilla_components.MediaSessionService"
|
||||
android:foregroundServiceType="mediaPlayback"
|
||||
android:exported="false" />
|
||||
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package me.movenext.bang_navigator
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||
|
||||
class MainActivity: FlutterActivity()
|
||||
class MainActivity: FlutterFragmentActivity()
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import 'package:fast_equatable/fast_equatable.dart';
|
||||
|
||||
class EquatableCollection<T> with FastEquatable {
|
||||
final T collection;
|
||||
final bool immutable;
|
||||
|
||||
EquatableCollection(this.collection, {required this.immutable})
|
||||
: assert(
|
||||
collection is Map || collection is Iterable,
|
||||
'Collection type not supported',
|
||||
);
|
||||
|
||||
@override
|
||||
bool get cacheHash => immutable;
|
||||
|
||||
@override
|
||||
List<Object?> get hashParameters => [
|
||||
collection,
|
||||
immutable,
|
||||
];
|
||||
}
|
||||
@@ -4,9 +4,6 @@ import 'package:exceptions/exceptions.dart';
|
||||
import 'package:lensai/features/about/data/repositories/package_info_repository.dart';
|
||||
import 'package:lensai/features/bangs/data/models/bang.dart';
|
||||
import 'package:lensai/features/bangs/domain/repositories/sync.dart';
|
||||
import 'package:lensai/features/kagi/data/services/session.dart';
|
||||
import 'package:lensai/features/settings/data/models/settings.dart';
|
||||
import 'package:lensai/features/settings/data/repositories/settings_repository.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'app_initialization.g.dart';
|
||||
@@ -46,27 +43,8 @@ class AppInitializationService extends _$AppInitializationService {
|
||||
.syncBangGroups(syncInterval: const Duration(days: 7));
|
||||
}
|
||||
|
||||
Future<void> _initIncognito(Settings settings) async {
|
||||
state = Result.success(
|
||||
(
|
||||
initialized: false,
|
||||
stage: 'Enforcing Privacy...',
|
||||
errors: List.empty(),
|
||||
),
|
||||
);
|
||||
|
||||
if (settings.kagiSession case final String session) {
|
||||
if (session.isNotEmpty) {
|
||||
await ref
|
||||
.read(kagiSessionServiceProvider.notifier)
|
||||
.setKagiSession(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> initialize() async {
|
||||
state = await Result.fromAsync(() async {
|
||||
final settings = await ref.read(settingsRepositoryProvider.future);
|
||||
final errors = <ErrorMessage>[];
|
||||
|
||||
await _initPackageInfo();
|
||||
@@ -76,8 +54,6 @@ class AppInitializationService extends _$AppInitializationService {
|
||||
result.onFailure(errors.add);
|
||||
}
|
||||
|
||||
await _initIncognito(settings);
|
||||
|
||||
return (initialized: true, stage: null, errors: errors);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ part of 'app_initialization.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$appInitializationServiceHash() =>
|
||||
r'0d7dc3eb3ed2e17643f4c34e4e172734ed8d09e2';
|
||||
r'fa383398929c8f3c8b430986304775e044b9af7a';
|
||||
|
||||
/// See also [AppInitializationService].
|
||||
@ProviderFor(AppInitializationService)
|
||||
|
||||
@@ -1246,122 +1246,191 @@ final class $BangTableReferences
|
||||
}
|
||||
}
|
||||
|
||||
class $BangTableFilterComposer
|
||||
extends FilterComposer<_$BangDatabase, BangTable> {
|
||||
$BangTableFilterComposer(super.$state);
|
||||
ColumnFilters<String> get trigger => $state.composableBuilder(
|
||||
column: $state.table.trigger,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
class $BangTableFilterComposer extends Composer<_$BangDatabase, BangTable> {
|
||||
$BangTableFilterComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnFilters<String> get trigger => $composableBuilder(
|
||||
column: $table.trigger, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnWithTypeConverterFilters<BangGroup, BangGroup, int> get group =>
|
||||
$state.composableBuilder(
|
||||
column: $state.table.group,
|
||||
builder: (column, joinBuilders) => ColumnWithTypeConverterFilters(
|
||||
column,
|
||||
joinBuilders: joinBuilders));
|
||||
$composableBuilder(
|
||||
column: $table.group,
|
||||
builder: (column) => ColumnWithTypeConverterFilters(column));
|
||||
|
||||
ColumnFilters<String> get websiteName => $state.composableBuilder(
|
||||
column: $state.table.websiteName,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
ColumnFilters<String> get websiteName => $composableBuilder(
|
||||
column: $table.websiteName, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<String> get domain => $state.composableBuilder(
|
||||
column: $state.table.domain,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
ColumnFilters<String> get domain => $composableBuilder(
|
||||
column: $table.domain, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<String> get urlTemplate => $state.composableBuilder(
|
||||
column: $state.table.urlTemplate,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
ColumnFilters<String> get urlTemplate => $composableBuilder(
|
||||
column: $table.urlTemplate, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<String> get category => $state.composableBuilder(
|
||||
column: $state.table.category,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
ColumnFilters<String> get category => $composableBuilder(
|
||||
column: $table.category, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<String> get subCategory => $state.composableBuilder(
|
||||
column: $state.table.subCategory,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
ColumnFilters<String> get subCategory => $composableBuilder(
|
||||
column: $table.subCategory, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnWithTypeConverterFilters<Set<BangFormat>?, Set<BangFormat>, String>
|
||||
get format => $state.composableBuilder(
|
||||
column: $state.table.format,
|
||||
builder: (column, joinBuilders) => ColumnWithTypeConverterFilters(
|
||||
column,
|
||||
joinBuilders: joinBuilders));
|
||||
get format => $composableBuilder(
|
||||
column: $table.format,
|
||||
builder: (column) => ColumnWithTypeConverterFilters(column));
|
||||
|
||||
ComposableFilter bangFrequencyRefs(
|
||||
ComposableFilter Function($BangFrequencyFilterComposer f) f) {
|
||||
final $BangFrequencyFilterComposer composer = $state.composerBuilder(
|
||||
Expression<bool> bangFrequencyRefs(
|
||||
Expression<bool> Function($BangFrequencyFilterComposer f) f) {
|
||||
final $BangFrequencyFilterComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.trigger,
|
||||
referencedTable: $state.db.bangFrequency,
|
||||
referencedTable: $db.bangFrequency,
|
||||
getReferencedColumn: (t) => t.trigger,
|
||||
builder: (joinBuilder, parentComposers) => $BangFrequencyFilterComposer(
|
||||
ComposerState($state.db, $state.db.bangFrequency, joinBuilder,
|
||||
parentComposers)));
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$BangFrequencyFilterComposer(
|
||||
$db: $db,
|
||||
$table: $db.bangFrequency,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return f(composer);
|
||||
}
|
||||
|
||||
ComposableFilter bangIconRefs(
|
||||
ComposableFilter Function($BangIconFilterComposer f) f) {
|
||||
final $BangIconFilterComposer composer = $state.composerBuilder(
|
||||
Expression<bool> bangIconRefs(
|
||||
Expression<bool> Function($BangIconFilterComposer f) f) {
|
||||
final $BangIconFilterComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.trigger,
|
||||
referencedTable: $state.db.bangIcon,
|
||||
referencedTable: $db.bangIcon,
|
||||
getReferencedColumn: (t) => t.trigger,
|
||||
builder: (joinBuilder, parentComposers) => $BangIconFilterComposer(
|
||||
ComposerState(
|
||||
$state.db, $state.db.bangIcon, joinBuilder, parentComposers)));
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$BangIconFilterComposer(
|
||||
$db: $db,
|
||||
$table: $db.bangIcon,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return f(composer);
|
||||
}
|
||||
}
|
||||
|
||||
class $BangTableOrderingComposer
|
||||
extends OrderingComposer<_$BangDatabase, BangTable> {
|
||||
$BangTableOrderingComposer(super.$state);
|
||||
ColumnOrderings<String> get trigger => $state.composableBuilder(
|
||||
column: $state.table.trigger,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
class $BangTableOrderingComposer extends Composer<_$BangDatabase, BangTable> {
|
||||
$BangTableOrderingComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnOrderings<String> get trigger => $composableBuilder(
|
||||
column: $table.trigger, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<int> get group => $state.composableBuilder(
|
||||
column: $state.table.group,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<int> get group => $composableBuilder(
|
||||
column: $table.group, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> get websiteName => $state.composableBuilder(
|
||||
column: $state.table.websiteName,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<String> get websiteName => $composableBuilder(
|
||||
column: $table.websiteName, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> get domain => $state.composableBuilder(
|
||||
column: $state.table.domain,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<String> get domain => $composableBuilder(
|
||||
column: $table.domain, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> get urlTemplate => $state.composableBuilder(
|
||||
column: $state.table.urlTemplate,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<String> get urlTemplate => $composableBuilder(
|
||||
column: $table.urlTemplate, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> get category => $state.composableBuilder(
|
||||
column: $state.table.category,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<String> get category => $composableBuilder(
|
||||
column: $table.category, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> get subCategory => $state.composableBuilder(
|
||||
column: $state.table.subCategory,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<String> get subCategory => $composableBuilder(
|
||||
column: $table.subCategory, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> get format => $state.composableBuilder(
|
||||
column: $state.table.format,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<String> get format => $composableBuilder(
|
||||
column: $table.format, builder: (column) => ColumnOrderings(column));
|
||||
}
|
||||
|
||||
class $BangTableAnnotationComposer extends Composer<_$BangDatabase, BangTable> {
|
||||
$BangTableAnnotationComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
GeneratedColumn<String> get trigger =>
|
||||
$composableBuilder(column: $table.trigger, builder: (column) => column);
|
||||
|
||||
GeneratedColumnWithTypeConverter<BangGroup, int> get group =>
|
||||
$composableBuilder(column: $table.group, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> get websiteName => $composableBuilder(
|
||||
column: $table.websiteName, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> get domain =>
|
||||
$composableBuilder(column: $table.domain, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> get urlTemplate => $composableBuilder(
|
||||
column: $table.urlTemplate, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> get category =>
|
||||
$composableBuilder(column: $table.category, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> get subCategory => $composableBuilder(
|
||||
column: $table.subCategory, builder: (column) => column);
|
||||
|
||||
GeneratedColumnWithTypeConverter<Set<BangFormat>?, String> get format =>
|
||||
$composableBuilder(column: $table.format, builder: (column) => column);
|
||||
|
||||
Expression<T> bangFrequencyRefs<T extends Object>(
|
||||
Expression<T> Function($BangFrequencyAnnotationComposer a) f) {
|
||||
final $BangFrequencyAnnotationComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.trigger,
|
||||
referencedTable: $db.bangFrequency,
|
||||
getReferencedColumn: (t) => t.trigger,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$BangFrequencyAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: $db.bangFrequency,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return f(composer);
|
||||
}
|
||||
|
||||
Expression<T> bangIconRefs<T extends Object>(
|
||||
Expression<T> Function($BangIconAnnotationComposer a) f) {
|
||||
final $BangIconAnnotationComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.trigger,
|
||||
referencedTable: $db.bangIcon,
|
||||
getReferencedColumn: (t) => t.trigger,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$BangIconAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: $db.bangIcon,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return f(composer);
|
||||
}
|
||||
}
|
||||
|
||||
class $BangTableTableManager extends RootTableManager<
|
||||
@@ -1370,6 +1439,7 @@ class $BangTableTableManager extends RootTableManager<
|
||||
Bang,
|
||||
$BangTableFilterComposer,
|
||||
$BangTableOrderingComposer,
|
||||
$BangTableAnnotationComposer,
|
||||
$BangTableCreateCompanionBuilder,
|
||||
$BangTableUpdateCompanionBuilder,
|
||||
(Bang, $BangTableReferences),
|
||||
@@ -1379,9 +1449,12 @@ class $BangTableTableManager extends RootTableManager<
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $BangTableFilterComposer(ComposerState(db, table)),
|
||||
orderingComposer:
|
||||
$BangTableOrderingComposer(ComposerState(db, table)),
|
||||
createFilteringComposer: () =>
|
||||
$BangTableFilterComposer($db: db, $table: table),
|
||||
createOrderingComposer: () =>
|
||||
$BangTableOrderingComposer($db: db, $table: table),
|
||||
createComputedFieldComposer: () =>
|
||||
$BangTableAnnotationComposer($db: db, $table: table),
|
||||
updateCompanionCallback: ({
|
||||
Value<String> trigger = const Value.absent(),
|
||||
Value<BangGroup> group = const Value.absent(),
|
||||
@@ -1477,6 +1550,7 @@ typedef $BangTableProcessedTableManager = ProcessedTableManager<
|
||||
Bang,
|
||||
$BangTableFilterComposer,
|
||||
$BangTableOrderingComposer,
|
||||
$BangTableAnnotationComposer,
|
||||
$BangTableCreateCompanionBuilder,
|
||||
$BangTableUpdateCompanionBuilder,
|
||||
(Bang, $BangTableReferences),
|
||||
@@ -1491,33 +1565,51 @@ typedef $BangSyncUpdateCompanionBuilder = BangSyncCompanion Function({
|
||||
Value<DateTime> lastSync,
|
||||
});
|
||||
|
||||
class $BangSyncFilterComposer extends FilterComposer<_$BangDatabase, BangSync> {
|
||||
$BangSyncFilterComposer(super.$state);
|
||||
class $BangSyncFilterComposer extends Composer<_$BangDatabase, BangSync> {
|
||||
$BangSyncFilterComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnWithTypeConverterFilters<BangGroup, BangGroup, int> get group =>
|
||||
$state.composableBuilder(
|
||||
column: $state.table.group,
|
||||
builder: (column, joinBuilders) => ColumnWithTypeConverterFilters(
|
||||
column,
|
||||
joinBuilders: joinBuilders));
|
||||
$composableBuilder(
|
||||
column: $table.group,
|
||||
builder: (column) => ColumnWithTypeConverterFilters(column));
|
||||
|
||||
ColumnFilters<DateTime> get lastSync => $state.composableBuilder(
|
||||
column: $state.table.lastSync,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
ColumnFilters<DateTime> get lastSync => $composableBuilder(
|
||||
column: $table.lastSync, builder: (column) => ColumnFilters(column));
|
||||
}
|
||||
|
||||
class $BangSyncOrderingComposer
|
||||
extends OrderingComposer<_$BangDatabase, BangSync> {
|
||||
$BangSyncOrderingComposer(super.$state);
|
||||
ColumnOrderings<int> get group => $state.composableBuilder(
|
||||
column: $state.table.group,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
class $BangSyncOrderingComposer extends Composer<_$BangDatabase, BangSync> {
|
||||
$BangSyncOrderingComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnOrderings<int> get group => $composableBuilder(
|
||||
column: $table.group, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<DateTime> get lastSync => $state.composableBuilder(
|
||||
column: $state.table.lastSync,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<DateTime> get lastSync => $composableBuilder(
|
||||
column: $table.lastSync, builder: (column) => ColumnOrderings(column));
|
||||
}
|
||||
|
||||
class $BangSyncAnnotationComposer extends Composer<_$BangDatabase, BangSync> {
|
||||
$BangSyncAnnotationComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
GeneratedColumnWithTypeConverter<BangGroup, int> get group =>
|
||||
$composableBuilder(column: $table.group, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<DateTime> get lastSync =>
|
||||
$composableBuilder(column: $table.lastSync, builder: (column) => column);
|
||||
}
|
||||
|
||||
class $BangSyncTableManager extends RootTableManager<
|
||||
@@ -1526,6 +1618,7 @@ class $BangSyncTableManager extends RootTableManager<
|
||||
BangSyncData,
|
||||
$BangSyncFilterComposer,
|
||||
$BangSyncOrderingComposer,
|
||||
$BangSyncAnnotationComposer,
|
||||
$BangSyncCreateCompanionBuilder,
|
||||
$BangSyncUpdateCompanionBuilder,
|
||||
(BangSyncData, BaseReferences<_$BangDatabase, BangSync, BangSyncData>),
|
||||
@@ -1535,8 +1628,12 @@ class $BangSyncTableManager extends RootTableManager<
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $BangSyncFilterComposer(ComposerState(db, table)),
|
||||
orderingComposer: $BangSyncOrderingComposer(ComposerState(db, table)),
|
||||
createFilteringComposer: () =>
|
||||
$BangSyncFilterComposer($db: db, $table: table),
|
||||
createOrderingComposer: () =>
|
||||
$BangSyncOrderingComposer($db: db, $table: table),
|
||||
createComputedFieldComposer: () =>
|
||||
$BangSyncAnnotationComposer($db: db, $table: table),
|
||||
updateCompanionCallback: ({
|
||||
Value<BangGroup> group = const Value.absent(),
|
||||
Value<DateTime> lastSync = const Value.absent(),
|
||||
@@ -1566,6 +1663,7 @@ typedef $BangSyncProcessedTableManager = ProcessedTableManager<
|
||||
BangSyncData,
|
||||
$BangSyncFilterComposer,
|
||||
$BangSyncOrderingComposer,
|
||||
$BangSyncAnnotationComposer,
|
||||
$BangSyncCreateCompanionBuilder,
|
||||
$BangSyncUpdateCompanionBuilder,
|
||||
(BangSyncData, BaseReferences<_$BangDatabase, BangSync, BangSyncData>),
|
||||
@@ -1603,53 +1701,109 @@ final class $BangFrequencyReferences
|
||||
}
|
||||
|
||||
class $BangFrequencyFilterComposer
|
||||
extends FilterComposer<_$BangDatabase, BangFrequency> {
|
||||
$BangFrequencyFilterComposer(super.$state);
|
||||
ColumnFilters<int> get frequency => $state.composableBuilder(
|
||||
column: $state.table.frequency,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
extends Composer<_$BangDatabase, BangFrequency> {
|
||||
$BangFrequencyFilterComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnFilters<int> get frequency => $composableBuilder(
|
||||
column: $table.frequency, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<DateTime> get lastUsed => $state.composableBuilder(
|
||||
column: $state.table.lastUsed,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
ColumnFilters<DateTime> get lastUsed => $composableBuilder(
|
||||
column: $table.lastUsed, builder: (column) => ColumnFilters(column));
|
||||
|
||||
$BangTableFilterComposer get trigger {
|
||||
final $BangTableFilterComposer composer = $state.composerBuilder(
|
||||
final $BangTableFilterComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.trigger,
|
||||
referencedTable: $state.db.bang,
|
||||
referencedTable: $db.bang,
|
||||
getReferencedColumn: (t) => t.trigger,
|
||||
builder: (joinBuilder, parentComposers) => $BangTableFilterComposer(
|
||||
ComposerState(
|
||||
$state.db, $state.db.bang, joinBuilder, parentComposers)));
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$BangTableFilterComposer(
|
||||
$db: $db,
|
||||
$table: $db.bang,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $BangFrequencyOrderingComposer
|
||||
extends OrderingComposer<_$BangDatabase, BangFrequency> {
|
||||
$BangFrequencyOrderingComposer(super.$state);
|
||||
ColumnOrderings<int> get frequency => $state.composableBuilder(
|
||||
column: $state.table.frequency,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
extends Composer<_$BangDatabase, BangFrequency> {
|
||||
$BangFrequencyOrderingComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnOrderings<int> get frequency => $composableBuilder(
|
||||
column: $table.frequency, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<DateTime> get lastUsed => $state.composableBuilder(
|
||||
column: $state.table.lastUsed,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<DateTime> get lastUsed => $composableBuilder(
|
||||
column: $table.lastUsed, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
$BangTableOrderingComposer get trigger {
|
||||
final $BangTableOrderingComposer composer = $state.composerBuilder(
|
||||
final $BangTableOrderingComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.trigger,
|
||||
referencedTable: $state.db.bang,
|
||||
referencedTable: $db.bang,
|
||||
getReferencedColumn: (t) => t.trigger,
|
||||
builder: (joinBuilder, parentComposers) => $BangTableOrderingComposer(
|
||||
ComposerState(
|
||||
$state.db, $state.db.bang, joinBuilder, parentComposers)));
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$BangTableOrderingComposer(
|
||||
$db: $db,
|
||||
$table: $db.bang,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $BangFrequencyAnnotationComposer
|
||||
extends Composer<_$BangDatabase, BangFrequency> {
|
||||
$BangFrequencyAnnotationComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
GeneratedColumn<int> get frequency =>
|
||||
$composableBuilder(column: $table.frequency, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<DateTime> get lastUsed =>
|
||||
$composableBuilder(column: $table.lastUsed, builder: (column) => column);
|
||||
|
||||
$BangTableAnnotationComposer get trigger {
|
||||
final $BangTableAnnotationComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.trigger,
|
||||
referencedTable: $db.bang,
|
||||
getReferencedColumn: (t) => t.trigger,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$BangTableAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: $db.bang,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
@@ -1660,6 +1814,7 @@ class $BangFrequencyTableManager extends RootTableManager<
|
||||
BangFrequencyData,
|
||||
$BangFrequencyFilterComposer,
|
||||
$BangFrequencyOrderingComposer,
|
||||
$BangFrequencyAnnotationComposer,
|
||||
$BangFrequencyCreateCompanionBuilder,
|
||||
$BangFrequencyUpdateCompanionBuilder,
|
||||
(BangFrequencyData, $BangFrequencyReferences),
|
||||
@@ -1669,10 +1824,12 @@ class $BangFrequencyTableManager extends RootTableManager<
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer:
|
||||
$BangFrequencyFilterComposer(ComposerState(db, table)),
|
||||
orderingComposer:
|
||||
$BangFrequencyOrderingComposer(ComposerState(db, table)),
|
||||
createFilteringComposer: () =>
|
||||
$BangFrequencyFilterComposer($db: db, $table: table),
|
||||
createOrderingComposer: () =>
|
||||
$BangFrequencyOrderingComposer($db: db, $table: table),
|
||||
createComputedFieldComposer: () =>
|
||||
$BangFrequencyAnnotationComposer($db: db, $table: table),
|
||||
updateCompanionCallback: ({
|
||||
Value<String> trigger = const Value.absent(),
|
||||
Value<int> frequency = const Value.absent(),
|
||||
@@ -1716,6 +1873,7 @@ class $BangFrequencyTableManager extends RootTableManager<
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic>>(state) {
|
||||
if (trigger) {
|
||||
state = state.withJoin(
|
||||
@@ -1743,6 +1901,7 @@ typedef $BangFrequencyProcessedTableManager = ProcessedTableManager<
|
||||
BangFrequencyData,
|
||||
$BangFrequencyFilterComposer,
|
||||
$BangFrequencyOrderingComposer,
|
||||
$BangFrequencyAnnotationComposer,
|
||||
$BangFrequencyCreateCompanionBuilder,
|
||||
$BangFrequencyUpdateCompanionBuilder,
|
||||
(BangFrequencyData, $BangFrequencyReferences),
|
||||
@@ -1779,53 +1938,107 @@ final class $BangIconReferences
|
||||
}
|
||||
}
|
||||
|
||||
class $BangIconFilterComposer extends FilterComposer<_$BangDatabase, BangIcon> {
|
||||
$BangIconFilterComposer(super.$state);
|
||||
ColumnFilters<Uint8List> get iconData => $state.composableBuilder(
|
||||
column: $state.table.iconData,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
class $BangIconFilterComposer extends Composer<_$BangDatabase, BangIcon> {
|
||||
$BangIconFilterComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnFilters<Uint8List> get iconData => $composableBuilder(
|
||||
column: $table.iconData, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<DateTime> get fetchDate => $state.composableBuilder(
|
||||
column: $state.table.fetchDate,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
ColumnFilters<DateTime> get fetchDate => $composableBuilder(
|
||||
column: $table.fetchDate, builder: (column) => ColumnFilters(column));
|
||||
|
||||
$BangTableFilterComposer get trigger {
|
||||
final $BangTableFilterComposer composer = $state.composerBuilder(
|
||||
final $BangTableFilterComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.trigger,
|
||||
referencedTable: $state.db.bang,
|
||||
referencedTable: $db.bang,
|
||||
getReferencedColumn: (t) => t.trigger,
|
||||
builder: (joinBuilder, parentComposers) => $BangTableFilterComposer(
|
||||
ComposerState(
|
||||
$state.db, $state.db.bang, joinBuilder, parentComposers)));
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$BangTableFilterComposer(
|
||||
$db: $db,
|
||||
$table: $db.bang,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $BangIconOrderingComposer
|
||||
extends OrderingComposer<_$BangDatabase, BangIcon> {
|
||||
$BangIconOrderingComposer(super.$state);
|
||||
ColumnOrderings<Uint8List> get iconData => $state.composableBuilder(
|
||||
column: $state.table.iconData,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
class $BangIconOrderingComposer extends Composer<_$BangDatabase, BangIcon> {
|
||||
$BangIconOrderingComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnOrderings<Uint8List> get iconData => $composableBuilder(
|
||||
column: $table.iconData, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<DateTime> get fetchDate => $state.composableBuilder(
|
||||
column: $state.table.fetchDate,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<DateTime> get fetchDate => $composableBuilder(
|
||||
column: $table.fetchDate, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
$BangTableOrderingComposer get trigger {
|
||||
final $BangTableOrderingComposer composer = $state.composerBuilder(
|
||||
final $BangTableOrderingComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.trigger,
|
||||
referencedTable: $state.db.bang,
|
||||
referencedTable: $db.bang,
|
||||
getReferencedColumn: (t) => t.trigger,
|
||||
builder: (joinBuilder, parentComposers) => $BangTableOrderingComposer(
|
||||
ComposerState(
|
||||
$state.db, $state.db.bang, joinBuilder, parentComposers)));
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$BangTableOrderingComposer(
|
||||
$db: $db,
|
||||
$table: $db.bang,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $BangIconAnnotationComposer extends Composer<_$BangDatabase, BangIcon> {
|
||||
$BangIconAnnotationComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
GeneratedColumn<Uint8List> get iconData =>
|
||||
$composableBuilder(column: $table.iconData, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<DateTime> get fetchDate =>
|
||||
$composableBuilder(column: $table.fetchDate, builder: (column) => column);
|
||||
|
||||
$BangTableAnnotationComposer get trigger {
|
||||
final $BangTableAnnotationComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.trigger,
|
||||
referencedTable: $db.bang,
|
||||
getReferencedColumn: (t) => t.trigger,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$BangTableAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: $db.bang,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
@@ -1836,6 +2049,7 @@ class $BangIconTableManager extends RootTableManager<
|
||||
BangIconData,
|
||||
$BangIconFilterComposer,
|
||||
$BangIconOrderingComposer,
|
||||
$BangIconAnnotationComposer,
|
||||
$BangIconCreateCompanionBuilder,
|
||||
$BangIconUpdateCompanionBuilder,
|
||||
(BangIconData, $BangIconReferences),
|
||||
@@ -1845,8 +2059,12 @@ class $BangIconTableManager extends RootTableManager<
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $BangIconFilterComposer(ComposerState(db, table)),
|
||||
orderingComposer: $BangIconOrderingComposer(ComposerState(db, table)),
|
||||
createFilteringComposer: () =>
|
||||
$BangIconFilterComposer($db: db, $table: table),
|
||||
createOrderingComposer: () =>
|
||||
$BangIconOrderingComposer($db: db, $table: table),
|
||||
createComputedFieldComposer: () =>
|
||||
$BangIconAnnotationComposer($db: db, $table: table),
|
||||
updateCompanionCallback: ({
|
||||
Value<String> trigger = const Value.absent(),
|
||||
Value<Uint8List> iconData = const Value.absent(),
|
||||
@@ -1890,6 +2108,7 @@ class $BangIconTableManager extends RootTableManager<
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic>>(state) {
|
||||
if (trigger) {
|
||||
state = state.withJoin(
|
||||
@@ -1917,6 +2136,7 @@ typedef $BangIconProcessedTableManager = ProcessedTableManager<
|
||||
BangIconData,
|
||||
$BangIconFilterComposer,
|
||||
$BangIconOrderingComposer,
|
||||
$BangIconAnnotationComposer,
|
||||
$BangIconCreateCompanionBuilder,
|
||||
$BangIconUpdateCompanionBuilder,
|
||||
(BangIconData, $BangIconReferences),
|
||||
@@ -1933,31 +2153,49 @@ typedef $BangFtsUpdateCompanionBuilder = BangFtsCompanion Function({
|
||||
Value<int> rowid,
|
||||
});
|
||||
|
||||
class $BangFtsFilterComposer extends FilterComposer<_$BangDatabase, BangFts> {
|
||||
$BangFtsFilterComposer(super.$state);
|
||||
ColumnFilters<String> get trigger => $state.composableBuilder(
|
||||
column: $state.table.trigger,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
class $BangFtsFilterComposer extends Composer<_$BangDatabase, BangFts> {
|
||||
$BangFtsFilterComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnFilters<String> get trigger => $composableBuilder(
|
||||
column: $table.trigger, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<String> get websiteName => $state.composableBuilder(
|
||||
column: $state.table.websiteName,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
ColumnFilters<String> get websiteName => $composableBuilder(
|
||||
column: $table.websiteName, builder: (column) => ColumnFilters(column));
|
||||
}
|
||||
|
||||
class $BangFtsOrderingComposer
|
||||
extends OrderingComposer<_$BangDatabase, BangFts> {
|
||||
$BangFtsOrderingComposer(super.$state);
|
||||
ColumnOrderings<String> get trigger => $state.composableBuilder(
|
||||
column: $state.table.trigger,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
class $BangFtsOrderingComposer extends Composer<_$BangDatabase, BangFts> {
|
||||
$BangFtsOrderingComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnOrderings<String> get trigger => $composableBuilder(
|
||||
column: $table.trigger, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> get websiteName => $state.composableBuilder(
|
||||
column: $state.table.websiteName,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<String> get websiteName => $composableBuilder(
|
||||
column: $table.websiteName, builder: (column) => ColumnOrderings(column));
|
||||
}
|
||||
|
||||
class $BangFtsAnnotationComposer extends Composer<_$BangDatabase, BangFts> {
|
||||
$BangFtsAnnotationComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
GeneratedColumn<String> get trigger =>
|
||||
$composableBuilder(column: $table.trigger, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> get websiteName => $composableBuilder(
|
||||
column: $table.websiteName, builder: (column) => column);
|
||||
}
|
||||
|
||||
class $BangFtsTableManager extends RootTableManager<
|
||||
@@ -1966,6 +2204,7 @@ class $BangFtsTableManager extends RootTableManager<
|
||||
BangFt,
|
||||
$BangFtsFilterComposer,
|
||||
$BangFtsOrderingComposer,
|
||||
$BangFtsAnnotationComposer,
|
||||
$BangFtsCreateCompanionBuilder,
|
||||
$BangFtsUpdateCompanionBuilder,
|
||||
(BangFt, BaseReferences<_$BangDatabase, BangFts, BangFt>),
|
||||
@@ -1975,8 +2214,12 @@ class $BangFtsTableManager extends RootTableManager<
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $BangFtsFilterComposer(ComposerState(db, table)),
|
||||
orderingComposer: $BangFtsOrderingComposer(ComposerState(db, table)),
|
||||
createFilteringComposer: () =>
|
||||
$BangFtsFilterComposer($db: db, $table: table),
|
||||
createOrderingComposer: () =>
|
||||
$BangFtsOrderingComposer($db: db, $table: table),
|
||||
createComputedFieldComposer: () =>
|
||||
$BangFtsAnnotationComposer($db: db, $table: table),
|
||||
updateCompanionCallback: ({
|
||||
Value<String> trigger = const Value.absent(),
|
||||
Value<String> websiteName = const Value.absent(),
|
||||
@@ -2010,6 +2253,7 @@ typedef $BangFtsProcessedTableManager = ProcessedTableManager<
|
||||
BangFt,
|
||||
$BangFtsFilterComposer,
|
||||
$BangFtsOrderingComposer,
|
||||
$BangFtsAnnotationComposer,
|
||||
$BangFtsCreateCompanionBuilder,
|
||||
$BangFtsUpdateCompanionBuilder,
|
||||
(BangFt, BaseReferences<_$BangDatabase, BangFts, BangFt>),
|
||||
|
||||
@@ -455,41 +455,58 @@ typedef $ChatUpdateCompanionBuilder = ChatCompanion Function({
|
||||
Value<int> rowid,
|
||||
});
|
||||
|
||||
class $ChatFilterComposer extends FilterComposer<_$ChatSearchDatabase, Chat> {
|
||||
$ChatFilterComposer(super.$state);
|
||||
ColumnFilters<String> get fileName => $state.composableBuilder(
|
||||
column: $state.table.fileName,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
class $ChatFilterComposer extends Composer<_$ChatSearchDatabase, Chat> {
|
||||
$ChatFilterComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnFilters<String> get fileName => $composableBuilder(
|
||||
column: $table.fileName, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<String> get title => $state.composableBuilder(
|
||||
column: $state.table.title,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
ColumnFilters<String> get title => $composableBuilder(
|
||||
column: $table.title, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<String> get content => $state.composableBuilder(
|
||||
column: $state.table.content,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
ColumnFilters<String> get content => $composableBuilder(
|
||||
column: $table.content, builder: (column) => ColumnFilters(column));
|
||||
}
|
||||
|
||||
class $ChatOrderingComposer
|
||||
extends OrderingComposer<_$ChatSearchDatabase, Chat> {
|
||||
$ChatOrderingComposer(super.$state);
|
||||
ColumnOrderings<String> get fileName => $state.composableBuilder(
|
||||
column: $state.table.fileName,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
class $ChatOrderingComposer extends Composer<_$ChatSearchDatabase, Chat> {
|
||||
$ChatOrderingComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnOrderings<String> get fileName => $composableBuilder(
|
||||
column: $table.fileName, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> get title => $state.composableBuilder(
|
||||
column: $state.table.title,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<String> get title => $composableBuilder(
|
||||
column: $table.title, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> get content => $state.composableBuilder(
|
||||
column: $state.table.content,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<String> get content => $composableBuilder(
|
||||
column: $table.content, builder: (column) => ColumnOrderings(column));
|
||||
}
|
||||
|
||||
class $ChatAnnotationComposer extends Composer<_$ChatSearchDatabase, Chat> {
|
||||
$ChatAnnotationComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
GeneratedColumn<String> get fileName =>
|
||||
$composableBuilder(column: $table.fileName, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> get title =>
|
||||
$composableBuilder(column: $table.title, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> get content =>
|
||||
$composableBuilder(column: $table.content, builder: (column) => column);
|
||||
}
|
||||
|
||||
class $ChatTableManager extends RootTableManager<
|
||||
@@ -498,6 +515,7 @@ class $ChatTableManager extends RootTableManager<
|
||||
ChatData,
|
||||
$ChatFilterComposer,
|
||||
$ChatOrderingComposer,
|
||||
$ChatAnnotationComposer,
|
||||
$ChatCreateCompanionBuilder,
|
||||
$ChatUpdateCompanionBuilder,
|
||||
(ChatData, BaseReferences<_$ChatSearchDatabase, Chat, ChatData>),
|
||||
@@ -507,8 +525,12 @@ class $ChatTableManager extends RootTableManager<
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $ChatFilterComposer(ComposerState(db, table)),
|
||||
orderingComposer: $ChatOrderingComposer(ComposerState(db, table)),
|
||||
createFilteringComposer: () =>
|
||||
$ChatFilterComposer($db: db, $table: table),
|
||||
createOrderingComposer: () =>
|
||||
$ChatOrderingComposer($db: db, $table: table),
|
||||
createComputedFieldComposer: () =>
|
||||
$ChatAnnotationComposer($db: db, $table: table),
|
||||
updateCompanionCallback: ({
|
||||
Value<String> fileName = const Value.absent(),
|
||||
Value<String> title = const Value.absent(),
|
||||
@@ -546,6 +568,7 @@ typedef $ChatProcessedTableManager = ProcessedTableManager<
|
||||
ChatData,
|
||||
$ChatFilterComposer,
|
||||
$ChatOrderingComposer,
|
||||
$ChatAnnotationComposer,
|
||||
$ChatCreateCompanionBuilder,
|
||||
$ChatUpdateCompanionBuilder,
|
||||
(ChatData, BaseReferences<_$ChatSearchDatabase, Chat, ChatData>),
|
||||
@@ -562,32 +585,50 @@ typedef $ChatFtsUpdateCompanionBuilder = ChatFtsCompanion Function({
|
||||
Value<int> rowid,
|
||||
});
|
||||
|
||||
class $ChatFtsFilterComposer
|
||||
extends FilterComposer<_$ChatSearchDatabase, ChatFts> {
|
||||
$ChatFtsFilterComposer(super.$state);
|
||||
ColumnFilters<String> get title => $state.composableBuilder(
|
||||
column: $state.table.title,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
class $ChatFtsFilterComposer extends Composer<_$ChatSearchDatabase, ChatFts> {
|
||||
$ChatFtsFilterComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnFilters<String> get title => $composableBuilder(
|
||||
column: $table.title, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<String> get content => $state.composableBuilder(
|
||||
column: $state.table.content,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
ColumnFilters<String> get content => $composableBuilder(
|
||||
column: $table.content, builder: (column) => ColumnFilters(column));
|
||||
}
|
||||
|
||||
class $ChatFtsOrderingComposer
|
||||
extends OrderingComposer<_$ChatSearchDatabase, ChatFts> {
|
||||
$ChatFtsOrderingComposer(super.$state);
|
||||
ColumnOrderings<String> get title => $state.composableBuilder(
|
||||
column: $state.table.title,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
class $ChatFtsOrderingComposer extends Composer<_$ChatSearchDatabase, ChatFts> {
|
||||
$ChatFtsOrderingComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnOrderings<String> get title => $composableBuilder(
|
||||
column: $table.title, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> get content => $state.composableBuilder(
|
||||
column: $state.table.content,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<String> get content => $composableBuilder(
|
||||
column: $table.content, builder: (column) => ColumnOrderings(column));
|
||||
}
|
||||
|
||||
class $ChatFtsAnnotationComposer
|
||||
extends Composer<_$ChatSearchDatabase, ChatFts> {
|
||||
$ChatFtsAnnotationComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
GeneratedColumn<String> get title =>
|
||||
$composableBuilder(column: $table.title, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> get content =>
|
||||
$composableBuilder(column: $table.content, builder: (column) => column);
|
||||
}
|
||||
|
||||
class $ChatFtsTableManager extends RootTableManager<
|
||||
@@ -596,6 +637,7 @@ class $ChatFtsTableManager extends RootTableManager<
|
||||
ChatFt,
|
||||
$ChatFtsFilterComposer,
|
||||
$ChatFtsOrderingComposer,
|
||||
$ChatFtsAnnotationComposer,
|
||||
$ChatFtsCreateCompanionBuilder,
|
||||
$ChatFtsUpdateCompanionBuilder,
|
||||
(ChatFt, BaseReferences<_$ChatSearchDatabase, ChatFts, ChatFt>),
|
||||
@@ -605,8 +647,12 @@ class $ChatFtsTableManager extends RootTableManager<
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $ChatFtsFilterComposer(ComposerState(db, table)),
|
||||
orderingComposer: $ChatFtsOrderingComposer(ComposerState(db, table)),
|
||||
createFilteringComposer: () =>
|
||||
$ChatFtsFilterComposer($db: db, $table: table),
|
||||
createOrderingComposer: () =>
|
||||
$ChatFtsOrderingComposer($db: db, $table: table),
|
||||
createComputedFieldComposer: () =>
|
||||
$ChatFtsAnnotationComposer($db: db, $table: table),
|
||||
updateCompanionCallback: ({
|
||||
Value<String> title = const Value.absent(),
|
||||
Value<String> content = const Value.absent(),
|
||||
@@ -640,6 +686,7 @@ typedef $ChatFtsProcessedTableManager = ProcessedTableManager<
|
||||
ChatFt,
|
||||
$ChatFtsFilterComposer,
|
||||
$ChatFtsOrderingComposer,
|
||||
$ChatFtsAnnotationComposer,
|
||||
$ChatFtsCreateCompanionBuilder,
|
||||
$ChatFtsUpdateCompanionBuilder,
|
||||
(ChatFt, BaseReferences<_$ChatSearchDatabase, ChatFts, ChatFt>),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_session.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
@@ -8,6 +10,8 @@ part 'providers.g.dart';
|
||||
GeckoEventService eventService(EventServiceRef ref) {
|
||||
final service = GeckoEventService.setUp();
|
||||
|
||||
unawaited(GeckoTabService().syncEvents());
|
||||
|
||||
ref.onDispose(() {
|
||||
service.dispose();
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'providers.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$eventServiceHash() => r'5aa357fdf0d217677a9a66ecb50417ac18929cad';
|
||||
String _$eventServiceHash() => r'c36c6d895629002945c7b4eafba8389771e2eb2d';
|
||||
|
||||
/// See also [eventService].
|
||||
@ProviderFor(eventService)
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:lensai/features/geckoview/domain/providers.dart';
|
||||
import 'package:lensai/features/geckoview/features/topics/data/database/database.dart';
|
||||
import 'package:lensai/features/geckoview/features/topics/data/providers.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'selected_tab.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class SelectedTab extends _$SelectedTab {
|
||||
late TabDatabase _db;
|
||||
|
||||
@override
|
||||
String? build() {
|
||||
_db = ref.watch(tabDatabaseProvider);
|
||||
|
||||
final eventSerivce = ref.watch(eventServiceProvider);
|
||||
|
||||
final selectedTabSub = eventSerivce.selectedTabEvents.listen(
|
||||
@@ -17,6 +23,12 @@ class SelectedTab extends _$SelectedTab {
|
||||
},
|
||||
);
|
||||
|
||||
ref.listenSelf((previous, next) async {
|
||||
if (next != null) {
|
||||
await _db.tabLinkDao.touchTabLink(next, timestamp: DateTime.now());
|
||||
}
|
||||
});
|
||||
|
||||
ref.onDispose(() {
|
||||
unawaited(selectedTabSub.cancel());
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'selected_tab.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$selectedTabHash() => r'd30f0490c7924b7de30e23f3d4d132311bf336d0';
|
||||
String _$selectedTabHash() => r'd57003aa20d8a6f711918821ae355e5537a55685';
|
||||
|
||||
/// See also [SelectedTab].
|
||||
@ProviderFor(SelectedTab)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
@@ -31,6 +33,10 @@ class TabSession extends _$TabSession {
|
||||
return _sessionService.goForward();
|
||||
}
|
||||
|
||||
Future<Uint8List?> requestScreenshot() {
|
||||
return _sessionService.requestScreenshot();
|
||||
}
|
||||
|
||||
@override
|
||||
void build(String? tabId) {
|
||||
_sessionService = (tabId != null)
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'tab_session.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$tabSessionHash() => r'cdde9c7426178f50dc430284939e215f158e8535';
|
||||
String _$tabSessionHash() => r'25afbead5c1110ca865e48a5009da70eb20d3a28';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:lensai/extensions/image.dart';
|
||||
import 'package:lensai/features/geckoview/domain/entities/find_result_state.dart';
|
||||
@@ -9,6 +10,8 @@ import 'package:lensai/features/geckoview/domain/entities/security_state.dart';
|
||||
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/features/topics/data/database/database.dart';
|
||||
import 'package:lensai/features/geckoview/features/topics/data/providers.dart';
|
||||
import 'package:lensai/features/geckoview/utils/image_helper.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
@@ -18,6 +21,8 @@ part 'tab_state.g.dart';
|
||||
class TabStates extends _$TabStates {
|
||||
final _tabsService = GeckoTabService();
|
||||
|
||||
late TabDatabase _db;
|
||||
|
||||
void _onTabListChange(List<String> tabs) {
|
||||
state = {
|
||||
for (final tabId in tabs) tabId: state[tabId] ?? TabState.$default(tabId),
|
||||
@@ -166,6 +171,7 @@ class TabStates extends _$TabStates {
|
||||
@override
|
||||
Map<String, TabState> build() {
|
||||
final eventService = ref.watch(eventServiceProvider);
|
||||
_db = ref.watch(tabDatabaseProvider);
|
||||
|
||||
final subscriptions = [
|
||||
eventService.tabListEvents.listen(_onTabListChange),
|
||||
@@ -178,6 +184,18 @@ class TabStates extends _$TabStates {
|
||||
eventService.findResultsEvent.listen(_onFindResults),
|
||||
];
|
||||
|
||||
ref.listenSelf(
|
||||
(previous, next) async {
|
||||
if (!const DeepCollectionEquality()
|
||||
.equals(previous?.keys.toSet(), next.keys.toSet())) {
|
||||
final ids = next.keys.toList();
|
||||
if (ids.isNotEmpty) {
|
||||
await _db.tabLinkDao.syncTabLinks(retainTabIds: ids);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
ref.onDispose(() {
|
||||
for (final sub in subscriptions) {
|
||||
unawaited(sub.cancel());
|
||||
|
||||
@@ -169,7 +169,7 @@ final selectedTabStateProvider = AutoDisposeProvider<TabState?>.internal(
|
||||
);
|
||||
|
||||
typedef SelectedTabStateRef = AutoDisposeProviderRef<TabState?>;
|
||||
String _$tabStatesHash() => r'22fd36fe2e443fd2dfb703dc3be72716fbccef6d';
|
||||
String _$tabStatesHash() => r'f3ae09e49150955dcb29ec89f0f3fe63155a1d6e';
|
||||
|
||||
/// See also [TabStates].
|
||||
@ProviderFor(TabStates)
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:lensai/data/models/equatable_iterable.dart';
|
||||
import 'package:lensai/features/bangs/data/models/bang_data.dart';
|
||||
import 'package:lensai/features/bangs/domain/repositories/data.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:lensai/features/geckoview/features/topics/data/providers.dart';
|
||||
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
@@ -80,3 +83,29 @@ class ShowFindInPage extends _$ShowFindInPage {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Riverpod()
|
||||
Stream<List<String>> availableTabIds(AvailableTabIdsRef ref, String? topicId) {
|
||||
final db = ref.watch(tabDatabaseProvider);
|
||||
final openTabs = ref
|
||||
.watch(
|
||||
tabStatesProvider.select(
|
||||
(states) =>
|
||||
EquatableCollection(states.keys.toSet(), immutable: false),
|
||||
),
|
||||
)
|
||||
.collection;
|
||||
|
||||
if (topicId != null) {
|
||||
return db.tabLinkDao.topicTabIds(topicId).watch().map(
|
||||
(tabIds) =>
|
||||
tabIds.where((tabId) => openTabs.contains(tabId)).toList(),
|
||||
);
|
||||
} else {
|
||||
return db.tabLinkDao.allTabIds().watch().map(
|
||||
(assignedTabIds) => openTabs
|
||||
.where((tabId) => !assignedTabIds.contains(tabId))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +156,135 @@ class _SelectedBangDataProviderElement
|
||||
String? get domain => (origin as SelectedBangDataProvider).domain;
|
||||
}
|
||||
|
||||
String _$availableTabIdsHash() => r'bea231cdf6211fc876b8031b5d72999eae5d7b15';
|
||||
|
||||
/// See also [availableTabIds].
|
||||
@ProviderFor(availableTabIds)
|
||||
const availableTabIdsProvider = AvailableTabIdsFamily();
|
||||
|
||||
/// See also [availableTabIds].
|
||||
class AvailableTabIdsFamily extends Family<AsyncValue<List<String>>> {
|
||||
/// See also [availableTabIds].
|
||||
const AvailableTabIdsFamily();
|
||||
|
||||
/// See also [availableTabIds].
|
||||
AvailableTabIdsProvider call(
|
||||
String? topicId,
|
||||
) {
|
||||
return AvailableTabIdsProvider(
|
||||
topicId,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AvailableTabIdsProvider getProviderOverride(
|
||||
covariant AvailableTabIdsProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.topicId,
|
||||
);
|
||||
}
|
||||
|
||||
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'availableTabIdsProvider';
|
||||
}
|
||||
|
||||
/// See also [availableTabIds].
|
||||
class AvailableTabIdsProvider extends AutoDisposeStreamProvider<List<String>> {
|
||||
/// See also [availableTabIds].
|
||||
AvailableTabIdsProvider(
|
||||
String? topicId,
|
||||
) : this._internal(
|
||||
(ref) => availableTabIds(
|
||||
ref as AvailableTabIdsRef,
|
||||
topicId,
|
||||
),
|
||||
from: availableTabIdsProvider,
|
||||
name: r'availableTabIdsProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$availableTabIdsHash,
|
||||
dependencies: AvailableTabIdsFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
AvailableTabIdsFamily._allTransitiveDependencies,
|
||||
topicId: topicId,
|
||||
);
|
||||
|
||||
AvailableTabIdsProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.topicId,
|
||||
}) : super.internal();
|
||||
|
||||
final String? topicId;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
Stream<List<String>> Function(AvailableTabIdsRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: AvailableTabIdsProvider._internal(
|
||||
(ref) => create(ref as AvailableTabIdsRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
topicId: topicId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeStreamProviderElement<List<String>> createElement() {
|
||||
return _AvailableTabIdsProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is AvailableTabIdsProvider && other.topicId == topicId;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, topicId.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
mixin AvailableTabIdsRef on AutoDisposeStreamProviderRef<List<String>> {
|
||||
/// The parameter `topicId` of this provider.
|
||||
String? get topicId;
|
||||
}
|
||||
|
||||
class _AvailableTabIdsProviderElement
|
||||
extends AutoDisposeStreamProviderElement<List<String>>
|
||||
with AvailableTabIdsRef {
|
||||
_AvailableTabIdsProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String? get topicId => (origin as AvailableTabIdsProvider).topicId;
|
||||
}
|
||||
|
||||
String _$selectedBangTriggerHash() =>
|
||||
r'b0e12bc95e93d50d04f1c658230cea9f15ff0385';
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/data/models/equatable_iterable.dart';
|
||||
import 'package:lensai/features/geckoview/domain/entities/tab_state.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:lensai/features/geckoview/features/topics/domain/providers.dart';
|
||||
@@ -25,8 +26,14 @@ class TabActionDialog extends HookConsumerWidget {
|
||||
tabTopicIdProvider(initialTab.id).select((value) => value.valueOrNull),
|
||||
);
|
||||
|
||||
final topics =
|
||||
ref.watch(topicsWithCountProvider.select((value) => value.valueOrNull));
|
||||
final topics = ref
|
||||
.watch(
|
||||
topicsWithCountProvider.select(
|
||||
(value) => EquatableCollection(value.valueOrNull, immutable: true),
|
||||
),
|
||||
)
|
||||
.collection;
|
||||
|
||||
final selectedTopic =
|
||||
topics?.firstWhereOrNull((topic) => topic.id == tabTopicId);
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
@@ -7,6 +9,7 @@ import 'package:lensai/data/models/web_page_info.dart';
|
||||
import 'package:lensai/features/bangs/data/models/bang_data.dart';
|
||||
import 'package:lensai/features/bangs/domain/providers.dart';
|
||||
import 'package:lensai/features/bangs/presentation/widgets/site_search.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_session.dart';
|
||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
||||
@@ -55,6 +58,7 @@ class WebPageDialog extends HookConsumerWidget {
|
||||
|
||||
final formKey = useMemoized(() => GlobalKey<FormState>());
|
||||
final urlTextController = useTextEditingController(text: url.toString());
|
||||
final urlTextFocusNode = useFocusNode();
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
@@ -80,6 +84,7 @@ class WebPageDialog extends HookConsumerWidget {
|
||||
key: formKey,
|
||||
child: TextFormField(
|
||||
controller: urlTextController,
|
||||
focusNode: urlTextFocusNode,
|
||||
enableIMEPersonalizedLearning: !incognitoEnabled,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'URL',
|
||||
@@ -109,6 +114,15 @@ class WebPageDialog extends HookConsumerWidget {
|
||||
|
||||
return 'Invalid URL';
|
||||
},
|
||||
onTap: () {
|
||||
if (!urlTextFocusNode.hasFocus) {
|
||||
// Select all text when the field is tapped
|
||||
urlTextController.selection = TextSelection(
|
||||
baseOffset: 0,
|
||||
extentOffset: urlTextController.text.length,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -183,6 +197,40 @@ class WebPageDialog extends HookConsumerWidget {
|
||||
onDismiss?.call();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.mobile_screen_share),
|
||||
title: const Text('Share screenshot'),
|
||||
onTap: () async {
|
||||
final screenshot = await ref
|
||||
.read(selectedTabSessionNotifierProvider)
|
||||
.requestScreenshot();
|
||||
|
||||
if (screenshot != null) {
|
||||
ui.decodeImageFromList(
|
||||
screenshot,
|
||||
(result) async {
|
||||
final png = await result.toByteData(
|
||||
format: ui.ImageByteFormat.png,
|
||||
);
|
||||
|
||||
if (png != null) {
|
||||
final file = XFile.fromData(
|
||||
png.buffer.asUint8List(),
|
||||
mimeType: 'image/png',
|
||||
);
|
||||
|
||||
await Share.shareXFiles(
|
||||
[file],
|
||||
subject: precachedInfo?.title,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
onDismiss?.call();
|
||||
},
|
||||
),
|
||||
const Divider(),
|
||||
ListTile(
|
||||
leading: Icon(KagiTool.summarizer.icon),
|
||||
|
||||
+11
-4
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart' show rootBundle;
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/data/models/equatable_iterable.dart';
|
||||
import 'package:lensai/domain/services/app_initialization.dart';
|
||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/error_container.dart';
|
||||
@@ -51,10 +52,16 @@ class LandingContent extends HookConsumerWidget {
|
||||
const LandingAction(),
|
||||
Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final errors = ref.watch(
|
||||
appInitializationServiceProvider
|
||||
.select((result) => result.valueOrNull?.errors),
|
||||
);
|
||||
final errors = ref
|
||||
.watch(
|
||||
appInitializationServiceProvider.select(
|
||||
(result) => EquatableCollection(
|
||||
result.valueOrNull?.errors,
|
||||
immutable: false,
|
||||
),
|
||||
),
|
||||
)
|
||||
.collection;
|
||||
|
||||
if (errors == null || errors.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
|
||||
+121
-123
@@ -1,16 +1,16 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fading_scroll/fading_scroll.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/data/models/equatable_iterable.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||
import 'package:lensai/features/geckoview/features/browser/domain/providers.dart';
|
||||
import 'package:lensai/features/geckoview/features/browser/presentation/dialogs/tab_action.dart';
|
||||
import 'package:lensai/features/geckoview/features/browser/presentation/widgets/tab_preview.dart';
|
||||
import 'package:lensai/features/geckoview/features/controllers/overlay_dialog.dart';
|
||||
import 'package:lensai/features/geckoview/features/topics/domain/providers.dart';
|
||||
import 'package:lensai/features/geckoview/features/topics/domain/providers/selected_topic.dart';
|
||||
import 'package:lensai/features/geckoview/features/topics/domain/repositories/tab_link.dart';
|
||||
import 'package:lensai/features/geckoview/features/topics/presentation/widgets/topic_chips.dart';
|
||||
@@ -116,135 +116,133 @@ class ViewTabsSheetWidget extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return FadingScroll(
|
||||
fadingSize: 25,
|
||||
shaderPadding:
|
||||
const EdgeInsets.only(top: _SliverHeaderDelagate._headerSize),
|
||||
return CustomScrollView(
|
||||
controller: sheetScrollController,
|
||||
builder: (context, controller) {
|
||||
return CustomScrollView(
|
||||
controller: controller,
|
||||
slivers: [
|
||||
SliverPersistentHeader(
|
||||
pinned: true,
|
||||
delegate: _SliverHeaderDelagate(onClose: onClose),
|
||||
),
|
||||
HookConsumer(
|
||||
builder: (context, ref, child) {
|
||||
final topic = ref.watch(selectedTopicProvider);
|
||||
final availableTabs = ref.watch(
|
||||
topicTabIdsProvider(topic)
|
||||
.select((value) => value.valueOrNull ?? []),
|
||||
);
|
||||
final activeTab = ref.watch(selectedTabProvider);
|
||||
|
||||
final itemHeight = useMemoized(
|
||||
() => _calculateItemHeight(
|
||||
screenWidth: MediaQuery.of(context).size.width,
|
||||
childAspectRatio: 0.75,
|
||||
horizontalPadding: 4.0,
|
||||
mainAxisSpacing: 8.0,
|
||||
crossAxisSpacing: 8.0,
|
||||
crossAxisCount: 2,
|
||||
slivers: [
|
||||
SliverPersistentHeader(
|
||||
pinned: true,
|
||||
delegate: _SliverHeaderDelagate(onClose: onClose),
|
||||
),
|
||||
HookConsumer(
|
||||
builder: (context, ref, child) {
|
||||
final topic = ref.watch(selectedTopicProvider);
|
||||
final availableTabs = ref
|
||||
.watch(
|
||||
availableTabIdsProvider(topic).select(
|
||||
(value) => EquatableCollection(
|
||||
value.valueOrNull ?? [],
|
||||
immutable: true,
|
||||
),
|
||||
),
|
||||
[MediaQuery.of(context).size.width],
|
||||
);
|
||||
)
|
||||
.collection;
|
||||
final activeTab = ref.watch(selectedTabProvider);
|
||||
|
||||
useEffect(
|
||||
() {
|
||||
final index = availableTabs
|
||||
.indexWhere((webView) => webView == activeTab);
|
||||
final itemHeight = useMemoized(
|
||||
() => _calculateItemHeight(
|
||||
screenWidth: MediaQuery.of(context).size.width,
|
||||
childAspectRatio: 0.75,
|
||||
horizontalPadding: 4.0,
|
||||
mainAxisSpacing: 8.0,
|
||||
crossAxisSpacing: 8.0,
|
||||
crossAxisCount: 2,
|
||||
),
|
||||
[MediaQuery.of(context).size.width],
|
||||
);
|
||||
|
||||
if (index > -1) {
|
||||
final reversedIndex = availableTabs.length - 1 - index;
|
||||
final offset = (reversedIndex ~/ 2) * itemHeight;
|
||||
useEffect(
|
||||
() {
|
||||
final index =
|
||||
availableTabs.indexWhere((webView) => webView == activeTab);
|
||||
|
||||
if (offset != controller.offset) {
|
||||
unawaited(
|
||||
controller.animateTo(
|
||||
offset,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
curve: Curves.easeInOut,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
if (index > -1) {
|
||||
final reversedIndex = availableTabs.length - 1 - index;
|
||||
final offset = (reversedIndex ~/ 2) * itemHeight;
|
||||
|
||||
return null;
|
||||
},
|
||||
[],
|
||||
);
|
||||
if (offset != sheetScrollController.offset) {
|
||||
unawaited(
|
||||
sheetScrollController.animateTo(
|
||||
offset,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
curve: Curves.easeInOut,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return SliverPadding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||
sliver: SliverGrid.count(
|
||||
//Sync values for itemHeight calculation _calculateItemHeight
|
||||
childAspectRatio: 0.75,
|
||||
mainAxisSpacing: 8.0,
|
||||
crossAxisSpacing: 8.0,
|
||||
crossAxisCount: 2,
|
||||
children: availableTabs.reversed
|
||||
.map(
|
||||
(tabId) => Consumer(
|
||||
key: ValueKey(tabId),
|
||||
builder: (context, ref, child) {
|
||||
final tab = ref.watch(tabStateProvider(tabId));
|
||||
|
||||
return (tab != null)
|
||||
? TabPreview(
|
||||
tab: tab,
|
||||
isActive: tabId == activeTab,
|
||||
onTap: () async {
|
||||
if (tabId != activeTab) {
|
||||
//Close first to avoid rebuilds
|
||||
onClose();
|
||||
await ref
|
||||
.read(
|
||||
tabRepositoryProvider.notifier,
|
||||
)
|
||||
.selectTab(tab.id);
|
||||
} else {
|
||||
onClose();
|
||||
}
|
||||
},
|
||||
onLongPress: () {
|
||||
ref
|
||||
.read(
|
||||
overlayDialogControllerProvider
|
||||
.notifier,
|
||||
)
|
||||
.show(
|
||||
TabActionDialog(
|
||||
initialTab: tab,
|
||||
onDismiss: ref
|
||||
.read(
|
||||
overlayDialogControllerProvider
|
||||
.notifier,
|
||||
)
|
||||
.dismiss,
|
||||
),
|
||||
);
|
||||
},
|
||||
onDelete: () async {
|
||||
await ref
|
||||
.read(
|
||||
tabRepositoryProvider.notifier,
|
||||
)
|
||||
.closeTab(tab.id);
|
||||
},
|
||||
)
|
||||
: const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
return null;
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
[availableTabs, activeTab],
|
||||
);
|
||||
|
||||
return SliverPadding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||
sliver: SliverGrid.count(
|
||||
//Sync values for itemHeight calculation _calculateItemHeight
|
||||
childAspectRatio: 0.75,
|
||||
mainAxisSpacing: 8.0,
|
||||
crossAxisSpacing: 8.0,
|
||||
crossAxisCount: 2,
|
||||
children: availableTabs.reversed
|
||||
.map(
|
||||
(tabId) => Consumer(
|
||||
key: ValueKey(tabId),
|
||||
builder: (context, ref, child) {
|
||||
final tab = ref.watch(tabStateProvider(tabId));
|
||||
|
||||
return (tab != null)
|
||||
? TabPreview(
|
||||
tab: tab,
|
||||
isActive: tabId == activeTab,
|
||||
onTap: () async {
|
||||
if (tabId != activeTab) {
|
||||
//Close first to avoid rebuilds
|
||||
onClose();
|
||||
await ref
|
||||
.read(
|
||||
tabRepositoryProvider.notifier,
|
||||
)
|
||||
.selectTab(tab.id);
|
||||
} else {
|
||||
onClose();
|
||||
}
|
||||
},
|
||||
onLongPress: () {
|
||||
ref
|
||||
.read(
|
||||
overlayDialogControllerProvider
|
||||
.notifier,
|
||||
)
|
||||
.show(
|
||||
TabActionDialog(
|
||||
initialTab: tab,
|
||||
onDismiss: ref
|
||||
.read(
|
||||
overlayDialogControllerProvider
|
||||
.notifier,
|
||||
)
|
||||
.dismiss,
|
||||
),
|
||||
);
|
||||
},
|
||||
onDelete: () async {
|
||||
await ref
|
||||
.read(
|
||||
tabRepositoryProvider.notifier,
|
||||
)
|
||||
.closeTab(tab.id);
|
||||
},
|
||||
)
|
||||
: const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@ import 'package:flutter_material_design_icons/flutter_material_design_icons.dart
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/core/logger.dart';
|
||||
import 'package:lensai/core/routing/routes.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_session.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||
@@ -22,6 +24,7 @@ import 'package:lensai/features/geckoview/features/controllers/bottom_sheet.dart
|
||||
import 'package:lensai/features/geckoview/features/controllers/overlay_dialog.dart';
|
||||
import 'package:lensai/features/geckoview/features/find_in_page/presentation/controllers/find_in_page_visibility.dart';
|
||||
import 'package:lensai/features/geckoview/features/find_in_page/presentation/widgets/find_in_page.dart';
|
||||
import 'package:lensai/features/geckoview/features/readerview/presentation/widgets/reader_appearance_button.dart';
|
||||
import 'package:lensai/features/geckoview/features/readerview/presentation/widgets/reader_button.dart';
|
||||
import 'package:lensai/features/kagi/data/entities/modes.dart';
|
||||
import 'package:lensai/features/kagi/data/services/session.dart';
|
||||
@@ -546,7 +549,23 @@ class BrowserScreen extends HookConsumerWidget {
|
||||
SafeArea(
|
||||
child: Stack(
|
||||
children: [
|
||||
const GeckoView(),
|
||||
GeckoView(
|
||||
preInitializationStep: () async {
|
||||
await ref
|
||||
.read(eventServiceProvider)
|
||||
.fragmentReadyStateEvents
|
||||
.firstWhere((state) => state == true)
|
||||
.timeout(
|
||||
const Duration(seconds: 3),
|
||||
onTimeout: () {
|
||||
logger.e(
|
||||
'Browser fragement not reported ready, trying to intitialize anyways',
|
||||
);
|
||||
return true;
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
@@ -604,6 +623,7 @@ class BrowserScreen extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
floatingActionButton: ReaderAppearanceButton(),
|
||||
bottomSheet: (displayedSheet != null)
|
||||
? NotificationListener<DraggableScrollableNotification>(
|
||||
onNotification: (notification) {
|
||||
|
||||
@@ -19,9 +19,3 @@ Stream<bool> appearanceButtonVisibility(AppearanceButtonVisibilityRef ref) {
|
||||
final service = ref.watch(readerableServiceProvider);
|
||||
return service.appearanceVisibility;
|
||||
}
|
||||
|
||||
@Riverpod()
|
||||
Stream<bool> readerButtonVisibility(ReaderButtonVisibilityRef ref) {
|
||||
final service = ref.watch(readerableServiceProvider);
|
||||
return service.readerVisibility;
|
||||
}
|
||||
|
||||
@@ -38,21 +38,5 @@ final appearanceButtonVisibilityProvider =
|
||||
);
|
||||
|
||||
typedef AppearanceButtonVisibilityRef = AutoDisposeStreamProviderRef<bool>;
|
||||
String _$readerButtonVisibilityHash() =>
|
||||
r'd58132aa4e9a5ba311a0b5d99b9f8416e952b1ab';
|
||||
|
||||
/// See also [readerButtonVisibility].
|
||||
@ProviderFor(readerButtonVisibility)
|
||||
final readerButtonVisibilityProvider = AutoDisposeStreamProvider<bool>.internal(
|
||||
readerButtonVisibility,
|
||||
name: r'readerButtonVisibilityProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$readerButtonVisibilityHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef ReaderButtonVisibilityRef = AutoDisposeStreamProviderRef<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
|
||||
|
||||
+16
-7
@@ -1,6 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/features/geckoview/domain/entities/readerable_state.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:lensai/features/geckoview/features/readerview/domain/providers/readerable.dart';
|
||||
|
||||
class ReaderAppearanceButton extends HookConsumerWidget {
|
||||
@@ -11,13 +13,20 @@ class ReaderAppearanceButton extends HookConsumerWidget {
|
||||
.select((value) => value.valueOrNull ?? false),
|
||||
);
|
||||
|
||||
return FloatingActionButton(
|
||||
onPressed: buttonVisible
|
||||
? () async {
|
||||
await ref.read(readerableServiceProvider).onAppearanceButtonTap();
|
||||
}
|
||||
: null,
|
||||
child: const Icon(MdiIcons.formatFont),
|
||||
final readerabilityState = ref.watch(
|
||||
selectedTabStateProvider.select(
|
||||
(state) => state?.readerableState ?? ReaderableState.$default(),
|
||||
),
|
||||
);
|
||||
|
||||
return Visibility(
|
||||
visible: readerabilityState.active && buttonVisible,
|
||||
child: FloatingActionButton(
|
||||
onPressed: () async {
|
||||
await ref.read(readerableServiceProvider).onAppearanceButtonTap();
|
||||
},
|
||||
child: const Icon(MdiIcons.formatFont),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-8
@@ -4,7 +4,6 @@ import 'package:flutter_material_design_icons/flutter_material_design_icons.dart
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/features/geckoview/domain/entities/readerable_state.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:lensai/features/geckoview/features/readerview/domain/providers/readerable.dart';
|
||||
import 'package:lensai/features/geckoview/features/readerview/presentation/controllers/readerable.dart';
|
||||
import 'package:lensai/presentation/widgets/animate_gradient_shader.dart';
|
||||
|
||||
@@ -21,11 +20,6 @@ class ReaderButton extends HookConsumerWidget {
|
||||
),
|
||||
);
|
||||
|
||||
final readerButtonVisible = ref.watch(
|
||||
readerButtonVisibilityProvider
|
||||
.select((value) => value.valueOrNull ?? false),
|
||||
);
|
||||
|
||||
final icon = useMemoized(
|
||||
() => readerabilityState.active
|
||||
? Icon(
|
||||
@@ -40,7 +34,7 @@ class ReaderButton extends HookConsumerWidget {
|
||||
);
|
||||
|
||||
return Visibility(
|
||||
visible: readerButtonVisible,
|
||||
visible: readerabilityState.readerable,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 15.0,
|
||||
@@ -48,7 +42,7 @@ class ReaderButton extends HookConsumerWidget {
|
||||
),
|
||||
child: readerChanging.when(
|
||||
data: (_) => Visibility(
|
||||
visible: readerButtonVisible,
|
||||
visible: readerabilityState.readerable,
|
||||
child: InkWell(
|
||||
onTap: readerChanging.isLoading
|
||||
? null
|
||||
|
||||
@@ -7,14 +7,18 @@ part 'tab.g.dart';
|
||||
class TabLinkDao extends DatabaseAccessor<TabDatabase> with _$TabLinkDaoMixin {
|
||||
TabLinkDao(super.db);
|
||||
|
||||
Selectable<String> topicTabIds(String? topicId) {
|
||||
Selectable<String> topicTabIds(String topicId) {
|
||||
final query = selectOnly(db.tabLink)
|
||||
..addColumns([db.tabLink.id])
|
||||
..where(db.tabLink.topicId.equals(topicId))
|
||||
..orderBy([OrderingTerm.asc(db.tabLink.id)]);
|
||||
|
||||
return query.map((row) => row.read(db.tabLink.id)!);
|
||||
}
|
||||
|
||||
Selectable<String> allTabIds() {
|
||||
final query = selectOnly(db.tabLink)
|
||||
..addColumns([db.tabLink.id])
|
||||
..where(
|
||||
(topicId == null)
|
||||
? db.tabLink.topicId.isNull()
|
||||
: db.tabLink.topicId.equals(topicId),
|
||||
)
|
||||
..orderBy([OrderingTerm.asc(db.tabLink.id)]);
|
||||
|
||||
return query.map((row) => row.read(db.tabLink.id)!);
|
||||
@@ -25,13 +29,13 @@ class TabLinkDao extends DatabaseAccessor<TabDatabase> with _$TabLinkDaoMixin {
|
||||
..addColumns([db.tabLink.topicId])
|
||||
..where(db.tabLink.id.equals(tabId));
|
||||
|
||||
return query.map((row) => row.read(db.tabLink.id)!);
|
||||
return query.map((row) => row.read(db.tabLink.topicId)!);
|
||||
}
|
||||
|
||||
Future<void> upsertTabLink(
|
||||
String tabId, {
|
||||
required DateTime timestamp,
|
||||
Value<String?> topicId = const Value.absent(),
|
||||
required String topicId,
|
||||
}) {
|
||||
return db.tabLink.insertOne(
|
||||
TabLinkCompanion.insert(
|
||||
|
||||
@@ -30,6 +30,8 @@ class TabDatabase extends _$TabDatabase {
|
||||
await m.dropColumn(tabLink, 'url');
|
||||
await m.dropColumn(tabLink, 'title');
|
||||
await m.dropColumn(tabLink, 'screenshot');
|
||||
|
||||
await m.alterTable(TableMigration(tabLink));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ CREATE TABLE topic (
|
||||
|
||||
CREATE TABLE tab_link (
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
topic_id TEXT REFERENCES topic (id) ON DELETE CASCADE,
|
||||
topic_id TEXT NOT NULL REFERENCES topic (id) ON DELETE CASCADE,
|
||||
timestamp DATETIME NOT NULL
|
||||
);
|
||||
|
||||
|
||||
@@ -142,10 +142,10 @@ class TabLink extends Table with TableInfo<TabLink, TabLinkData> {
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'PRIMARY KEY NOT NULL');
|
||||
late final GeneratedColumn<String> topicId = GeneratedColumn<String>(
|
||||
'topic_id', aliasedName, true,
|
||||
'topic_id', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'REFERENCES topic(id)ON DELETE CASCADE');
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL REFERENCES topic(id)ON DELETE CASCADE');
|
||||
late final GeneratedColumn<DateTime> timestamp = GeneratedColumn<DateTime>(
|
||||
'timestamp', aliasedName, false,
|
||||
type: DriftSqlType.dateTime,
|
||||
@@ -167,7 +167,7 @@ class TabLink extends Table with TableInfo<TabLink, TabLinkData> {
|
||||
id: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.string, data['${effectivePrefix}id'])!,
|
||||
topicId: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.string, data['${effectivePrefix}topic_id']),
|
||||
.read(DriftSqlType.string, data['${effectivePrefix}topic_id'])!,
|
||||
timestamp: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.dateTime, data['${effectivePrefix}timestamp'])!,
|
||||
);
|
||||
@@ -184,16 +184,15 @@ class TabLink extends Table with TableInfo<TabLink, TabLinkData> {
|
||||
|
||||
class TabLinkData extends DataClass implements Insertable<TabLinkData> {
|
||||
final String id;
|
||||
final String? topicId;
|
||||
final String topicId;
|
||||
final DateTime timestamp;
|
||||
const TabLinkData({required this.id, this.topicId, required this.timestamp});
|
||||
const TabLinkData(
|
||||
{required this.id, required this.topicId, required this.timestamp});
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
map['id'] = Variable<String>(id);
|
||||
if (!nullToAbsent || topicId != null) {
|
||||
map['topic_id'] = Variable<String>(topicId);
|
||||
}
|
||||
map['topic_id'] = Variable<String>(topicId);
|
||||
map['timestamp'] = Variable<DateTime>(timestamp);
|
||||
return map;
|
||||
}
|
||||
@@ -203,7 +202,7 @@ class TabLinkData extends DataClass implements Insertable<TabLinkData> {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return TabLinkData(
|
||||
id: serializer.fromJson<String>(json['id']),
|
||||
topicId: serializer.fromJson<String?>(json['topic_id']),
|
||||
topicId: serializer.fromJson<String>(json['topic_id']),
|
||||
timestamp: serializer.fromJson<DateTime>(json['timestamp']),
|
||||
);
|
||||
}
|
||||
@@ -212,18 +211,15 @@ class TabLinkData extends DataClass implements Insertable<TabLinkData> {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'id': serializer.toJson<String>(id),
|
||||
'topic_id': serializer.toJson<String?>(topicId),
|
||||
'topic_id': serializer.toJson<String>(topicId),
|
||||
'timestamp': serializer.toJson<DateTime>(timestamp),
|
||||
};
|
||||
}
|
||||
|
||||
TabLinkData copyWith(
|
||||
{String? id,
|
||||
Value<String?> topicId = const Value.absent(),
|
||||
DateTime? timestamp}) =>
|
||||
TabLinkData copyWith({String? id, String? topicId, DateTime? timestamp}) =>
|
||||
TabLinkData(
|
||||
id: id ?? this.id,
|
||||
topicId: topicId.present ? topicId.value : this.topicId,
|
||||
topicId: topicId ?? this.topicId,
|
||||
timestamp: timestamp ?? this.timestamp,
|
||||
);
|
||||
TabLinkData copyWithCompanion(TabLinkCompanion data) {
|
||||
@@ -257,7 +253,7 @@ class TabLinkData extends DataClass implements Insertable<TabLinkData> {
|
||||
|
||||
class TabLinkCompanion extends UpdateCompanion<TabLinkData> {
|
||||
final Value<String> id;
|
||||
final Value<String?> topicId;
|
||||
final Value<String> topicId;
|
||||
final Value<DateTime> timestamp;
|
||||
final Value<int> rowid;
|
||||
const TabLinkCompanion({
|
||||
@@ -268,10 +264,11 @@ class TabLinkCompanion extends UpdateCompanion<TabLinkData> {
|
||||
});
|
||||
TabLinkCompanion.insert({
|
||||
required String id,
|
||||
this.topicId = const Value.absent(),
|
||||
required String topicId,
|
||||
required DateTime timestamp,
|
||||
this.rowid = const Value.absent(),
|
||||
}) : id = Value(id),
|
||||
topicId = Value(topicId),
|
||||
timestamp = Value(timestamp);
|
||||
static Insertable<TabLinkData> custom({
|
||||
Expression<String>? id,
|
||||
@@ -289,7 +286,7 @@ class TabLinkCompanion extends UpdateCompanion<TabLinkData> {
|
||||
|
||||
TabLinkCompanion copyWith(
|
||||
{Value<String>? id,
|
||||
Value<String?>? topicId,
|
||||
Value<String>? topicId,
|
||||
Value<DateTime>? timestamp,
|
||||
Value<int>? rowid}) {
|
||||
return TabLinkCompanion(
|
||||
@@ -403,55 +400,102 @@ final class $TopicReferences
|
||||
}
|
||||
}
|
||||
|
||||
class $TopicFilterComposer extends FilterComposer<_$TabDatabase, Topic> {
|
||||
$TopicFilterComposer(super.$state);
|
||||
ColumnFilters<String> get id => $state.composableBuilder(
|
||||
column: $state.table.id,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
class $TopicFilterComposer extends Composer<_$TabDatabase, Topic> {
|
||||
$TopicFilterComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnFilters<String> get id => $composableBuilder(
|
||||
column: $table.id, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<String> get name => $state.composableBuilder(
|
||||
column: $state.table.name,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
ColumnFilters<String> get name => $composableBuilder(
|
||||
column: $table.name, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnWithTypeConverterFilters<Color, Color, int> get color =>
|
||||
$state.composableBuilder(
|
||||
column: $state.table.color,
|
||||
builder: (column, joinBuilders) => ColumnWithTypeConverterFilters(
|
||||
column,
|
||||
joinBuilders: joinBuilders));
|
||||
$composableBuilder(
|
||||
column: $table.color,
|
||||
builder: (column) => ColumnWithTypeConverterFilters(column));
|
||||
|
||||
ComposableFilter tabLinkRefs(
|
||||
ComposableFilter Function($TabLinkFilterComposer f) f) {
|
||||
final $TabLinkFilterComposer composer = $state.composerBuilder(
|
||||
Expression<bool> tabLinkRefs(
|
||||
Expression<bool> Function($TabLinkFilterComposer f) f) {
|
||||
final $TabLinkFilterComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.id,
|
||||
referencedTable: $state.db.tabLink,
|
||||
referencedTable: $db.tabLink,
|
||||
getReferencedColumn: (t) => t.topicId,
|
||||
builder: (joinBuilder, parentComposers) => $TabLinkFilterComposer(
|
||||
ComposerState(
|
||||
$state.db, $state.db.tabLink, joinBuilder, parentComposers)));
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$TabLinkFilterComposer(
|
||||
$db: $db,
|
||||
$table: $db.tabLink,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return f(composer);
|
||||
}
|
||||
}
|
||||
|
||||
class $TopicOrderingComposer extends OrderingComposer<_$TabDatabase, Topic> {
|
||||
$TopicOrderingComposer(super.$state);
|
||||
ColumnOrderings<String> get id => $state.composableBuilder(
|
||||
column: $state.table.id,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
class $TopicOrderingComposer extends Composer<_$TabDatabase, Topic> {
|
||||
$TopicOrderingComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnOrderings<String> get id => $composableBuilder(
|
||||
column: $table.id, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> get name => $state.composableBuilder(
|
||||
column: $state.table.name,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<String> get name => $composableBuilder(
|
||||
column: $table.name, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<int> get color => $state.composableBuilder(
|
||||
column: $state.table.color,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<int> get color => $composableBuilder(
|
||||
column: $table.color, builder: (column) => ColumnOrderings(column));
|
||||
}
|
||||
|
||||
class $TopicAnnotationComposer extends Composer<_$TabDatabase, Topic> {
|
||||
$TopicAnnotationComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
GeneratedColumn<String> get id =>
|
||||
$composableBuilder(column: $table.id, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> get name =>
|
||||
$composableBuilder(column: $table.name, builder: (column) => column);
|
||||
|
||||
GeneratedColumnWithTypeConverter<Color, int> get color =>
|
||||
$composableBuilder(column: $table.color, builder: (column) => column);
|
||||
|
||||
Expression<T> tabLinkRefs<T extends Object>(
|
||||
Expression<T> Function($TabLinkAnnotationComposer a) f) {
|
||||
final $TabLinkAnnotationComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.id,
|
||||
referencedTable: $db.tabLink,
|
||||
getReferencedColumn: (t) => t.topicId,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$TabLinkAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: $db.tabLink,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return f(composer);
|
||||
}
|
||||
}
|
||||
|
||||
class $TopicTableManager extends RootTableManager<
|
||||
@@ -460,6 +504,7 @@ class $TopicTableManager extends RootTableManager<
|
||||
TopicData,
|
||||
$TopicFilterComposer,
|
||||
$TopicOrderingComposer,
|
||||
$TopicAnnotationComposer,
|
||||
$TopicCreateCompanionBuilder,
|
||||
$TopicUpdateCompanionBuilder,
|
||||
(TopicData, $TopicReferences),
|
||||
@@ -469,8 +514,12 @@ class $TopicTableManager extends RootTableManager<
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $TopicFilterComposer(ComposerState(db, table)),
|
||||
orderingComposer: $TopicOrderingComposer(ComposerState(db, table)),
|
||||
createFilteringComposer: () =>
|
||||
$TopicFilterComposer($db: db, $table: table),
|
||||
createOrderingComposer: () =>
|
||||
$TopicOrderingComposer($db: db, $table: table),
|
||||
createComputedFieldComposer: () =>
|
||||
$TopicAnnotationComposer($db: db, $table: table),
|
||||
updateCompanionCallback: ({
|
||||
Value<String> id = const Value.absent(),
|
||||
Value<String?> name = const Value.absent(),
|
||||
@@ -528,6 +577,7 @@ typedef $TopicProcessedTableManager = ProcessedTableManager<
|
||||
TopicData,
|
||||
$TopicFilterComposer,
|
||||
$TopicOrderingComposer,
|
||||
$TopicAnnotationComposer,
|
||||
$TopicCreateCompanionBuilder,
|
||||
$TopicUpdateCompanionBuilder,
|
||||
(TopicData, $TopicReferences),
|
||||
@@ -535,13 +585,13 @@ typedef $TopicProcessedTableManager = ProcessedTableManager<
|
||||
PrefetchHooks Function({bool tabLinkRefs})>;
|
||||
typedef $TabLinkCreateCompanionBuilder = TabLinkCompanion Function({
|
||||
required String id,
|
||||
Value<String?> topicId,
|
||||
required String topicId,
|
||||
required DateTime timestamp,
|
||||
Value<int> rowid,
|
||||
});
|
||||
typedef $TabLinkUpdateCompanionBuilder = TabLinkCompanion Function({
|
||||
Value<String> id,
|
||||
Value<String?> topicId,
|
||||
Value<String> topicId,
|
||||
Value<DateTime> timestamp,
|
||||
Value<int> rowid,
|
||||
});
|
||||
@@ -564,53 +614,107 @@ final class $TabLinkReferences
|
||||
}
|
||||
}
|
||||
|
||||
class $TabLinkFilterComposer extends FilterComposer<_$TabDatabase, TabLink> {
|
||||
$TabLinkFilterComposer(super.$state);
|
||||
ColumnFilters<String> get id => $state.composableBuilder(
|
||||
column: $state.table.id,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
class $TabLinkFilterComposer extends Composer<_$TabDatabase, TabLink> {
|
||||
$TabLinkFilterComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnFilters<String> get id => $composableBuilder(
|
||||
column: $table.id, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<DateTime> get timestamp => $state.composableBuilder(
|
||||
column: $state.table.timestamp,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnFilters(column, joinBuilders: joinBuilders));
|
||||
ColumnFilters<DateTime> get timestamp => $composableBuilder(
|
||||
column: $table.timestamp, builder: (column) => ColumnFilters(column));
|
||||
|
||||
$TopicFilterComposer get topicId {
|
||||
final $TopicFilterComposer composer = $state.composerBuilder(
|
||||
final $TopicFilterComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.topicId,
|
||||
referencedTable: $state.db.topic,
|
||||
referencedTable: $db.topic,
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder, parentComposers) => $TopicFilterComposer(
|
||||
ComposerState(
|
||||
$state.db, $state.db.topic, joinBuilder, parentComposers)));
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$TopicFilterComposer(
|
||||
$db: $db,
|
||||
$table: $db.topic,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $TabLinkOrderingComposer
|
||||
extends OrderingComposer<_$TabDatabase, TabLink> {
|
||||
$TabLinkOrderingComposer(super.$state);
|
||||
ColumnOrderings<String> get id => $state.composableBuilder(
|
||||
column: $state.table.id,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
class $TabLinkOrderingComposer extends Composer<_$TabDatabase, TabLink> {
|
||||
$TabLinkOrderingComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnOrderings<String> get id => $composableBuilder(
|
||||
column: $table.id, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<DateTime> get timestamp => $state.composableBuilder(
|
||||
column: $state.table.timestamp,
|
||||
builder: (column, joinBuilders) =>
|
||||
ColumnOrderings(column, joinBuilders: joinBuilders));
|
||||
ColumnOrderings<DateTime> get timestamp => $composableBuilder(
|
||||
column: $table.timestamp, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
$TopicOrderingComposer get topicId {
|
||||
final $TopicOrderingComposer composer = $state.composerBuilder(
|
||||
final $TopicOrderingComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.topicId,
|
||||
referencedTable: $state.db.topic,
|
||||
referencedTable: $db.topic,
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder, parentComposers) => $TopicOrderingComposer(
|
||||
ComposerState(
|
||||
$state.db, $state.db.topic, joinBuilder, parentComposers)));
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$TopicOrderingComposer(
|
||||
$db: $db,
|
||||
$table: $db.topic,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $TabLinkAnnotationComposer extends Composer<_$TabDatabase, TabLink> {
|
||||
$TabLinkAnnotationComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
GeneratedColumn<String> get id =>
|
||||
$composableBuilder(column: $table.id, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<DateTime> get timestamp =>
|
||||
$composableBuilder(column: $table.timestamp, builder: (column) => column);
|
||||
|
||||
$TopicAnnotationComposer get topicId {
|
||||
final $TopicAnnotationComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.topicId,
|
||||
referencedTable: $db.topic,
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$TopicAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: $db.topic,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
@@ -621,6 +725,7 @@ class $TabLinkTableManager extends RootTableManager<
|
||||
TabLinkData,
|
||||
$TabLinkFilterComposer,
|
||||
$TabLinkOrderingComposer,
|
||||
$TabLinkAnnotationComposer,
|
||||
$TabLinkCreateCompanionBuilder,
|
||||
$TabLinkUpdateCompanionBuilder,
|
||||
(TabLinkData, $TabLinkReferences),
|
||||
@@ -630,11 +735,15 @@ class $TabLinkTableManager extends RootTableManager<
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $TabLinkFilterComposer(ComposerState(db, table)),
|
||||
orderingComposer: $TabLinkOrderingComposer(ComposerState(db, table)),
|
||||
createFilteringComposer: () =>
|
||||
$TabLinkFilterComposer($db: db, $table: table),
|
||||
createOrderingComposer: () =>
|
||||
$TabLinkOrderingComposer($db: db, $table: table),
|
||||
createComputedFieldComposer: () =>
|
||||
$TabLinkAnnotationComposer($db: db, $table: table),
|
||||
updateCompanionCallback: ({
|
||||
Value<String> id = const Value.absent(),
|
||||
Value<String?> topicId = const Value.absent(),
|
||||
Value<String> topicId = const Value.absent(),
|
||||
Value<DateTime> timestamp = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
@@ -646,7 +755,7 @@ class $TabLinkTableManager extends RootTableManager<
|
||||
),
|
||||
createCompanionCallback: ({
|
||||
required String id,
|
||||
Value<String?> topicId = const Value.absent(),
|
||||
required String topicId,
|
||||
required DateTime timestamp,
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
@@ -675,6 +784,7 @@ class $TabLinkTableManager extends RootTableManager<
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic>>(state) {
|
||||
if (topicId) {
|
||||
state = state.withJoin(
|
||||
@@ -701,6 +811,7 @@ typedef $TabLinkProcessedTableManager = ProcessedTableManager<
|
||||
TabLinkData,
|
||||
$TabLinkFilterComposer,
|
||||
$TabLinkOrderingComposer,
|
||||
$TabLinkAnnotationComposer,
|
||||
$TabLinkCreateCompanionBuilder,
|
||||
$TabLinkUpdateCompanionBuilder,
|
||||
(TabLinkData, $TabLinkReferences),
|
||||
|
||||
@@ -31,7 +31,7 @@ Stream<List<TopicDataWithCount>> topicsWithCount(TopicsWithCountRef ref) {
|
||||
}
|
||||
|
||||
@Riverpod()
|
||||
Stream<List<String>> topicTabIds(TopicTabIdsRef ref, String? topicId) {
|
||||
Stream<List<String>> topicTabIds(TopicTabIdsRef ref, String topicId) {
|
||||
final db = ref.watch(tabDatabaseProvider);
|
||||
return db.tabLinkDao.topicTabIds(topicId).watch();
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ final topicsWithCountProvider =
|
||||
|
||||
typedef TopicsWithCountRef
|
||||
= AutoDisposeStreamProviderRef<List<TopicDataWithCount>>;
|
||||
String _$topicTabIdsHash() => r'f7ce2633804421a22df1efc42eb4d19d440d9fd3';
|
||||
String _$topicTabIdsHash() => r'43719c70e01cf9e030d75171405ab9650936ddf8';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
@@ -74,7 +74,7 @@ class TopicTabIdsFamily extends Family<AsyncValue<List<String>>> {
|
||||
|
||||
/// See also [topicTabIds].
|
||||
TopicTabIdsProvider call(
|
||||
String? topicId,
|
||||
String topicId,
|
||||
) {
|
||||
return TopicTabIdsProvider(
|
||||
topicId,
|
||||
@@ -109,7 +109,7 @@ class TopicTabIdsFamily extends Family<AsyncValue<List<String>>> {
|
||||
class TopicTabIdsProvider extends AutoDisposeStreamProvider<List<String>> {
|
||||
/// See also [topicTabIds].
|
||||
TopicTabIdsProvider(
|
||||
String? topicId,
|
||||
String topicId,
|
||||
) : this._internal(
|
||||
(ref) => topicTabIds(
|
||||
ref as TopicTabIdsRef,
|
||||
@@ -137,7 +137,7 @@ class TopicTabIdsProvider extends AutoDisposeStreamProvider<List<String>> {
|
||||
required this.topicId,
|
||||
}) : super.internal();
|
||||
|
||||
final String? topicId;
|
||||
final String topicId;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
@@ -178,7 +178,7 @@ class TopicTabIdsProvider extends AutoDisposeStreamProvider<List<String>> {
|
||||
|
||||
mixin TopicTabIdsRef on AutoDisposeStreamProviderRef<List<String>> {
|
||||
/// The parameter `topicId` of this provider.
|
||||
String? get topicId;
|
||||
String get topicId;
|
||||
}
|
||||
|
||||
class _TopicTabIdsProviderElement
|
||||
@@ -186,7 +186,7 @@ class _TopicTabIdsProviderElement
|
||||
_TopicTabIdsProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String? get topicId => (origin as TopicTabIdsProvider).topicId;
|
||||
String get topicId => (origin as TopicTabIdsProvider).topicId;
|
||||
}
|
||||
|
||||
String _$tabTopicIdHash() => r'284164ac3acd9be3ba4e15eba99fc8d97602ee84';
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||
import 'package:lensai/features/geckoview/features/topics/data/database/database.dart';
|
||||
@@ -15,38 +13,28 @@ class TabLinkRepository extends _$TabLinkRepository {
|
||||
@override
|
||||
void build() {
|
||||
_db = ref.watch(tabDatabaseProvider);
|
||||
|
||||
//Sync existing tabs
|
||||
ref.listen(
|
||||
tabStatesProvider.select((tabs) => tabs.keys.toList()),
|
||||
(previous, next) async {
|
||||
//No empty list to avoid data loss
|
||||
if (next.isNotEmpty) {
|
||||
await _db.tabLinkDao.syncTabLinks(retainTabIds: next);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
ref.listen(
|
||||
selectedTabProvider,
|
||||
(previous, next) async {
|
||||
if (next != null) {
|
||||
await _db.tabLinkDao.touchTabLink(next, timestamp: DateTime.now());
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> assignTab(String tabId, String? topicId) {
|
||||
Future<void> assignTab(String tabId, String topicId) {
|
||||
return _db.tabLinkDao.upsertTabLink(
|
||||
tabId,
|
||||
timestamp: DateTime.now(),
|
||||
topicId: Value(topicId),
|
||||
topicId: topicId,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> closeAllTabs(String? topicId) async {
|
||||
final tabIds = await _db.tabLinkDao.topicTabIds(topicId).get();
|
||||
final List<String> tabIds;
|
||||
if (topicId != null) {
|
||||
tabIds = await _db.tabLinkDao.topicTabIds(topicId).get();
|
||||
} else {
|
||||
final openTabs = ref.read(tabStatesProvider).keys.toSet();
|
||||
final assignedTabIds = await _db.tabLinkDao.allTabIds().get();
|
||||
|
||||
tabIds =
|
||||
openTabs.where((tabId) => !assignedTabIds.contains(tabId)).toList();
|
||||
}
|
||||
|
||||
if (tabIds.isNotEmpty) {
|
||||
await ref.read(tabRepositoryProvider.notifier).closeTabs(tabIds);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'tab_link.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$tabLinkRepositoryHash() => r'c4944c1f6792bd725f889b1d6e12946b1439be11';
|
||||
String _$tabLinkRepositoryHash() => r'cdc23ca6ea215925f39842b16f9abcc289b0efbb';
|
||||
|
||||
/// See also [TabLinkRepository].
|
||||
@ProviderFor(TabLinkRepository)
|
||||
|
||||
@@ -17,12 +17,8 @@ abstract class _$SettingsCWProxy {
|
||||
|
||||
Settings launchUrlExternal(bool launchUrlExternal);
|
||||
|
||||
Settings enableContentBlocking(bool enableContentBlocking);
|
||||
|
||||
Settings blockHttpProtocol(bool blockHttpProtocol);
|
||||
|
||||
Settings enableHostList(Set<HostSource> enableHostList);
|
||||
|
||||
Settings themeMode(ThemeMode themeMode);
|
||||
|
||||
Settings quickAction(KagiTool? quickAction);
|
||||
@@ -43,9 +39,7 @@ abstract class _$SettingsCWProxy {
|
||||
bool? incognitoMode,
|
||||
bool? enableJavascript,
|
||||
bool? launchUrlExternal,
|
||||
bool? enableContentBlocking,
|
||||
bool? blockHttpProtocol,
|
||||
Set<HostSource>? enableHostList,
|
||||
ThemeMode? themeMode,
|
||||
KagiTool? quickAction,
|
||||
bool? quickActionVoiceInput,
|
||||
@@ -78,18 +72,10 @@ class _$SettingsCWProxyImpl implements _$SettingsCWProxy {
|
||||
Settings launchUrlExternal(bool launchUrlExternal) =>
|
||||
this(launchUrlExternal: launchUrlExternal);
|
||||
|
||||
@override
|
||||
Settings enableContentBlocking(bool enableContentBlocking) =>
|
||||
this(enableContentBlocking: enableContentBlocking);
|
||||
|
||||
@override
|
||||
Settings blockHttpProtocol(bool blockHttpProtocol) =>
|
||||
this(blockHttpProtocol: blockHttpProtocol);
|
||||
|
||||
@override
|
||||
Settings enableHostList(Set<HostSource> enableHostList) =>
|
||||
this(enableHostList: enableHostList);
|
||||
|
||||
@override
|
||||
Settings themeMode(ThemeMode themeMode) => this(themeMode: themeMode);
|
||||
|
||||
@@ -118,9 +104,7 @@ class _$SettingsCWProxyImpl implements _$SettingsCWProxy {
|
||||
Object? incognitoMode = const $CopyWithPlaceholder(),
|
||||
Object? enableJavascript = const $CopyWithPlaceholder(),
|
||||
Object? launchUrlExternal = const $CopyWithPlaceholder(),
|
||||
Object? enableContentBlocking = const $CopyWithPlaceholder(),
|
||||
Object? blockHttpProtocol = const $CopyWithPlaceholder(),
|
||||
Object? enableHostList = const $CopyWithPlaceholder(),
|
||||
Object? themeMode = const $CopyWithPlaceholder(),
|
||||
Object? quickAction = const $CopyWithPlaceholder(),
|
||||
Object? quickActionVoiceInput = const $CopyWithPlaceholder(),
|
||||
@@ -152,22 +136,11 @@ class _$SettingsCWProxyImpl implements _$SettingsCWProxy {
|
||||
? _value.launchUrlExternal
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: launchUrlExternal as bool,
|
||||
enableContentBlocking:
|
||||
enableContentBlocking == const $CopyWithPlaceholder() ||
|
||||
enableContentBlocking == null
|
||||
? _value.enableContentBlocking
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: enableContentBlocking as bool,
|
||||
blockHttpProtocol: blockHttpProtocol == const $CopyWithPlaceholder() ||
|
||||
blockHttpProtocol == null
|
||||
? _value.blockHttpProtocol
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: blockHttpProtocol as bool,
|
||||
enableHostList: enableHostList == const $CopyWithPlaceholder() ||
|
||||
enableHostList == null
|
||||
? _value.enableHostList
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: enableHostList as Set<HostSource>,
|
||||
themeMode: themeMode == const $CopyWithPlaceholder() || themeMode == null
|
||||
? _value.themeMode
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
|
||||
@@ -7,7 +7,7 @@ part of 'settings_repository.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$settingsRepositoryHash() =>
|
||||
r'f7c42efda64f0fb647e5daf0a92c2d118596cc52';
|
||||
r'b0a498899546b6a0c8566458ed8848fef410c537';
|
||||
|
||||
/// See also [SettingsRepository].
|
||||
@ProviderFor(SettingsRepository)
|
||||
|
||||
+25
-24
@@ -50,10 +50,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
|
||||
sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.0"
|
||||
version: "2.6.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -290,18 +290,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: drift
|
||||
sha256: d6ff1ec6a0f3fa097dda6b776cf601f1f3d88b53b287288e09c1306f394fb1b3
|
||||
sha256: df027d168a2985a2e9da900adeba2ab0136f0d84436592cf3cd5135f82c8579c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.20.3"
|
||||
version: "2.21.0"
|
||||
drift_dev:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: drift_dev
|
||||
sha256: "3ee987578ca2281b5ff91eadd757cd6dd36001458d6e33784f990d67ff38f756"
|
||||
sha256: "27bab15e7869b69259663590381180117873b9b273a1ea9ebb21bb73133d1233"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.20.3"
|
||||
version: "2.21.0"
|
||||
dynamic_color:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -479,10 +479,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_markdown
|
||||
sha256: e17575ca576a34b46c58c91f9948891117a1bd97815d2e661813c7f90c647a78
|
||||
sha256: bd9c475d9aae256369edacafc29d1e74c81f78a10cdcdacbbbc9e3c43d009e4a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.3+2"
|
||||
version: "0.7.4"
|
||||
flutter_material_design_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -501,10 +501,11 @@ packages:
|
||||
flutter_pdf_text:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "/home/fafre/Repos/flutter-pdf-text"
|
||||
relative: false
|
||||
source: path
|
||||
version: "0.6.0"
|
||||
name: flutter_pdf_text
|
||||
sha256: "456fcc92ee6297f87e2e5bd46c35f1951a9cd716b8a00ab557d9d087c37a3b9c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.0"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -517,10 +518,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_riverpod
|
||||
sha256: "0f1974eff5bbe774bf1d870e406fc6f29e3d6f1c46bd9c58e7172ff68a785d7d"
|
||||
sha256: "711d916456563f715bde1e139d7cfdca009f8264befab3ac9f8ded8b6ec26405"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.1"
|
||||
version: "2.5.3"
|
||||
flutter_secure_storage:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -655,10 +656,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: hooks_riverpod
|
||||
sha256: "97266a91c994951a06ef0ff3a1c7fb261e52ec7f74e87f0614ea0b7411b859b2"
|
||||
sha256: "534ca8af331235f700f3916a74e4579cdfdd708e2fbed342fc8aa969d41a7af0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.2"
|
||||
version: "2.5.4"
|
||||
hotreloader:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -983,10 +984,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: riverpod
|
||||
sha256: f21b32ffd26a36555e501b04f4a5dca43ed59e16343f1a30c13632b2351dfa4d
|
||||
sha256: c86fedfb45dd1da98ee6493dd9374325cdf494e7d523ebfb0c387eecc5f7b5c9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.1"
|
||||
version: "2.5.3"
|
||||
riverpod_analyzer_utils:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -999,10 +1000,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: riverpod_annotation
|
||||
sha256: e5e796c0eba4030c704e9dae1b834a6541814963292839dcf9638d53eba84f5c
|
||||
sha256: "77fdedb87d09344809e8b514ab864d0537b1cb580a93d09bf579b0403aa6203a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.5"
|
||||
version: "2.5.3"
|
||||
riverpod_generator:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@@ -1187,10 +1188,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlparser
|
||||
sha256: "852cf80f9e974ac8e1b613758a8aa640215f7701352b66a7f468e95711eb570b"
|
||||
sha256: c5f63dff8677407ddcddfa4744c176ea6dc44286c47ba9e69e76d8071398034d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.38.1"
|
||||
version: "0.39.1"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1418,10 +1419,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: "4d45dc9069dba4619dc0ebd93c7cec5e66d8482cb625a370ac806dcc8165f2ec"
|
||||
sha256: e5c39a90447e7c81cfec14b041cdbd0d0916bd9ebbc7fe02ab69568be703b9bd
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.5.5"
|
||||
version: "5.6.0"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
+7
-8
@@ -11,7 +11,7 @@ dependencies:
|
||||
collection: ^1.19.0
|
||||
copy_with_extension: ^5.0.4
|
||||
crypto: ^3.0.5
|
||||
drift: ^2.20.3
|
||||
drift: ^2.21.0
|
||||
dynamic_color: ^1.7.0
|
||||
exceptions: ^0.6.1
|
||||
expandable_page_view: ^1.0.17
|
||||
@@ -22,18 +22,17 @@ dependencies:
|
||||
sdk: flutter
|
||||
flutter_hooks: ^0.20.5
|
||||
flutter_inappwebview: ^6.1.5
|
||||
flutter_markdown: ^0.7.3+2
|
||||
flutter_markdown: ^0.7.4
|
||||
flutter_material_design_icons: ^1.1.7447
|
||||
flutter_mozilla_components:
|
||||
path: ../packages/flutter_mozilla_components
|
||||
flutter_pdf_text:
|
||||
path: ../../flutter-pdf-text
|
||||
flutter_pdf_text: ^0.7.0
|
||||
flutter_secure_storage: ^9.2.2
|
||||
flutter_sharing_intent: ^1.1.1
|
||||
go_router: ^14.3.0
|
||||
google_fonts: ^6.2.1
|
||||
home_widget: ^0.7.0
|
||||
hooks_riverpod: ^2.5.2
|
||||
hooks_riverpod: ^2.5.4
|
||||
html: ^0.15.4
|
||||
http: ^1.2.2
|
||||
json_annotation: ^4.9.0
|
||||
@@ -43,8 +42,8 @@ dependencies:
|
||||
package_info_plus: ^8.0.3
|
||||
path: ^1.9.0
|
||||
path_provider: ^2.1.4
|
||||
riverpod: ^2.5.1
|
||||
riverpod_annotation: ^2.3.5
|
||||
riverpod: ^2.5.3
|
||||
riverpod_annotation: ^2.5.3
|
||||
rxdart: ^0.28.0
|
||||
share_plus: ^10.0.3
|
||||
shared_preferences: ^2.3.2
|
||||
@@ -67,7 +66,7 @@ dev_dependencies:
|
||||
copy_with_extension_gen: ^5.0.4
|
||||
custom_lint: ^0.6.8
|
||||
dependency_validator: ^4.1.1
|
||||
drift_dev: ^2.20.3
|
||||
drift_dev: ^2.21.0
|
||||
fast_equatable_lint: ^0.3.0
|
||||
flutter_launcher_icons: ^0.14.1
|
||||
go_router_builder: ^2.7.1
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
name: lensai_project
|
||||
|
||||
command:
|
||||
clean:
|
||||
hooks:
|
||||
pre: melos exec -c 6 -- "flutter clean"
|
||||
|
||||
scripts:
|
||||
upgrade-major-tighten:
|
||||
run: |
|
||||
|
||||
+1
@@ -68,6 +68,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
|
||||
_components = GlobalComponents.components
|
||||
|
||||
_engineView = createEngine(components)
|
||||
_components?.engineView = _engineView
|
||||
|
||||
val engineNativeView = engineView.asView()
|
||||
// Set layout parameters
|
||||
|
||||
+25
-6
@@ -17,6 +17,8 @@ import eu.lensai.flutter_mozilla_components.pigeons.ReaderableState
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.SecurityInfoState
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.SelectionAction
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.TabContentState
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
@@ -31,10 +33,12 @@ import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
|
||||
import mozilla.components.concept.base.crash.Breadcrumb
|
||||
import mozilla.components.concept.engine.DefaultSettings
|
||||
import mozilla.components.concept.engine.Engine
|
||||
import mozilla.components.concept.engine.EngineView
|
||||
import mozilla.components.concept.engine.mediaquery.PreferredColorScheme
|
||||
import mozilla.components.concept.fetch.Client
|
||||
import mozilla.components.feature.addons.AddonManager
|
||||
import mozilla.components.feature.addons.amo.AMOAddonsProvider
|
||||
import mozilla.components.feature.addons.logger
|
||||
import mozilla.components.feature.addons.migration.DefaultSupportedAddonsChecker
|
||||
import mozilla.components.feature.addons.update.DefaultAddonUpdater
|
||||
import mozilla.components.feature.app.links.AppLinksInterceptor
|
||||
@@ -73,7 +77,7 @@ private const val DAY_IN_MINUTES = 24 * 60L
|
||||
@Suppress("LargeClass")
|
||||
open class DefaultComponents(
|
||||
private val applicationContext: Context,
|
||||
private val flutterEvents: GeckoStateEvents,
|
||||
val flutterEvents: GeckoStateEvents,
|
||||
val readerViewController: ReaderViewController,
|
||||
val selectionAction: SelectionAction,
|
||||
) {
|
||||
@@ -83,6 +87,8 @@ open class DefaultComponents(
|
||||
const val PREF_GLOBAL_PRIVACY_CONTROL = "sample_browser_global_privacy_control"
|
||||
}
|
||||
|
||||
var engineView: EngineView? = null
|
||||
|
||||
val preferences: SharedPreferences =
|
||||
applicationContext.getSharedPreferences(SAMPLE_BROWSER_PREFERENCES, Context.MODE_PRIVATE)
|
||||
|
||||
@@ -140,6 +146,7 @@ open class DefaultComponents(
|
||||
FileUploadsDirCleaner { applicationContext.cacheDir }
|
||||
}
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
val store by lazy {
|
||||
BrowserStore(
|
||||
middleware = listOf(
|
||||
@@ -156,6 +163,7 @@ open class DefaultComponents(
|
||||
).apply {
|
||||
this.flowScoped { flow ->
|
||||
flow.map { state -> state.selectedTabId }
|
||||
.distinctUntilChanged()
|
||||
.collect { tabId ->
|
||||
flutterEvents.onSelectedTabChange(
|
||||
tabId
|
||||
@@ -166,8 +174,10 @@ open class DefaultComponents(
|
||||
this.flowScoped { flow ->
|
||||
flow.mapNotNull { state -> state.tabs }
|
||||
.filterChanged {
|
||||
it.content.icon
|
||||
it.content
|
||||
}
|
||||
.ifAnyChanged { arrayOf (it.content.icon) }
|
||||
.debounce { 50 }
|
||||
.collect { tab ->
|
||||
val iconBytes = tab.content.icon?.toWebPBytes()
|
||||
flutterEvents.onIconChange(
|
||||
@@ -182,6 +192,7 @@ open class DefaultComponents(
|
||||
.filterChanged {
|
||||
it.content.securityInfo
|
||||
}
|
||||
.debounce { 50 }
|
||||
.collect { tab ->
|
||||
flutterEvents.onSecurityInfoStateChange(
|
||||
tab.id,
|
||||
@@ -200,10 +211,11 @@ open class DefaultComponents(
|
||||
it.readerState
|
||||
}
|
||||
.ifAnyChanged { arrayOf(
|
||||
it.readerState.readerable,
|
||||
it.readerState.active,
|
||||
)
|
||||
it.readerState.readerable,
|
||||
it.readerState.active,
|
||||
)
|
||||
}
|
||||
.debounce { 50 }
|
||||
.collect { tab ->
|
||||
flutterEvents.onReaderableStateChange(
|
||||
tab.id,
|
||||
@@ -226,6 +238,7 @@ open class DefaultComponents(
|
||||
it.content.canGoForward,
|
||||
)
|
||||
}
|
||||
.debounce { 50 }
|
||||
.collect { tab ->
|
||||
flutterEvents.onHistoryStateChange(
|
||||
tab.id,
|
||||
@@ -261,8 +274,11 @@ open class DefaultComponents(
|
||||
it.content.private,
|
||||
it.content.fullScreen,
|
||||
it.content.progress,
|
||||
it.content.loading) }
|
||||
it.content.loading)
|
||||
}
|
||||
.debounce { 50 }
|
||||
.collect { tab ->
|
||||
logger.info("title: ${tab.content.title} ${tab.content.url}")
|
||||
flutterEvents.onTabContentStateChange(
|
||||
TabContentState(
|
||||
id = tab.id,
|
||||
@@ -283,6 +299,7 @@ open class DefaultComponents(
|
||||
.filterChanged {
|
||||
it.content.findResults
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.collect { tab ->
|
||||
tab.content.findResults
|
||||
flutterEvents.onFindResults(
|
||||
@@ -296,6 +313,8 @@ open class DefaultComponents(
|
||||
}
|
||||
}
|
||||
|
||||
icons.install(engine, this)
|
||||
|
||||
WebNotificationFeature(
|
||||
applicationContext,
|
||||
engine,
|
||||
|
||||
+10
-4
@@ -87,6 +87,7 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
|
||||
private var activity: Activity? = null
|
||||
|
||||
private lateinit var _flutterPluginBinding: FlutterPlugin.FlutterPluginBinding;
|
||||
private lateinit var _flutterEvents : GeckoStateEvents
|
||||
|
||||
init {
|
||||
Log.addSink(AndroidLogSink())
|
||||
@@ -95,14 +96,15 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
|
||||
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
||||
_flutterPluginBinding = flutterPluginBinding
|
||||
|
||||
val flutterEvents = GeckoStateEvents(_flutterPluginBinding.binaryMessenger)
|
||||
_flutterEvents = GeckoStateEvents(_flutterPluginBinding.binaryMessenger)
|
||||
|
||||
val readerViewController =
|
||||
ReaderViewController(_flutterPluginBinding.binaryMessenger)
|
||||
val selectionActionDelegate = SelectionAction(_flutterPluginBinding.binaryMessenger)
|
||||
|
||||
GlobalComponents.setUp(
|
||||
flutterPluginBinding.applicationContext,
|
||||
flutterEvents,
|
||||
_flutterEvents,
|
||||
readerViewController,
|
||||
selectionActionDelegate
|
||||
)
|
||||
@@ -141,7 +143,6 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
|
||||
fm.beginTransaction()
|
||||
.replace(FRAGMENT_CONTAINER_ID, nativeFragment)
|
||||
.commitAllowingStateLoss()
|
||||
|
||||
}
|
||||
|
||||
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
||||
@@ -152,7 +153,12 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
|
||||
this.activity = binding.activity
|
||||
|
||||
_flutterPluginBinding.platformViewRegistry.registerViewFactory(
|
||||
"eu.lensai/gecko", GeckoViewFactory(binding.activity, FRAGMENT_CONTAINER_ID))
|
||||
"eu.lensai/gecko", GeckoViewFactory(
|
||||
binding.activity,
|
||||
FRAGMENT_CONTAINER_ID,
|
||||
_flutterEvents
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDetachedFromActivityForConfigChanges() {
|
||||
|
||||
+15
-4
@@ -5,20 +5,26 @@ import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents
|
||||
import io.flutter.plugin.common.StandardMessageCodec
|
||||
import io.flutter.plugin.platform.PlatformView
|
||||
import io.flutter.plugin.platform.PlatformViewFactory
|
||||
|
||||
class GeckoViewFactory(private val activity: Activity, private val containerId: Int) : PlatformViewFactory(
|
||||
class GeckoViewFactory(
|
||||
private val activity: Activity,
|
||||
private val containerId: Int,
|
||||
private val flutterEvents: GeckoStateEvents
|
||||
) : PlatformViewFactory(
|
||||
StandardMessageCodec.INSTANCE) {
|
||||
override fun create(context: Context?, id: Int, args: Any?): PlatformView {
|
||||
return NativeFragmentView(this.activity, this.containerId)
|
||||
return NativeFragmentView(this.activity, this.containerId, this.flutterEvents)
|
||||
}
|
||||
}
|
||||
|
||||
private class NativeFragmentView(
|
||||
private val activity: Activity?,
|
||||
private val containerId: Int
|
||||
activity: Activity?,
|
||||
containerId: Int,
|
||||
private val flutterEvents: GeckoStateEvents
|
||||
) : PlatformView {
|
||||
private val container: View
|
||||
|
||||
@@ -32,6 +38,11 @@ private class NativeFragmentView(
|
||||
container.id = containerId
|
||||
}
|
||||
|
||||
override fun onFlutterViewAttached(flutterView: View) {
|
||||
super.onFlutterViewAttached(flutterView)
|
||||
flutterEvents.onFragmentReadyStateChange(true) { _ -> }
|
||||
}
|
||||
|
||||
override fun getView(): View {
|
||||
return container
|
||||
}
|
||||
|
||||
+35
@@ -2,17 +2,35 @@ package eu.lensai.flutter_mozilla_components.api
|
||||
|
||||
import android.util.Log
|
||||
import eu.lensai.flutter_mozilla_components.GlobalComponents
|
||||
import eu.lensai.flutter_mozilla_components.ext.toWebPBytes
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoSessionApi
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.LoadUrlFlagsValue
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import mozilla.components.browser.state.action.ContentAction
|
||||
import mozilla.components.browser.state.selector.findTab
|
||||
import mozilla.components.browser.state.selector.selectedTab
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.TranslationOptions as PigeonTranslationOptions
|
||||
import mozilla.components.browser.state.state.BrowserState
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
|
||||
import mozilla.components.concept.base.images.ImageLoadRequest
|
||||
import mozilla.components.concept.engine.EngineSession
|
||||
import mozilla.components.concept.engine.EngineView
|
||||
import mozilla.components.concept.engine.translate.TranslationOptions
|
||||
import mozilla.components.feature.session.SessionUseCases
|
||||
import org.mozilla.gecko.util.ThreadUtils.runOnUiThread
|
||||
|
||||
class GeckoSessionApiImpl : GeckoSessionApi {
|
||||
private val sessionUseCases: SessionUseCases by lazy { GlobalComponents.components!!.sessionUseCases }
|
||||
private val store: BrowserStore by lazy { GlobalComponents.components!!.store }
|
||||
private val state: BrowserState by lazy { GlobalComponents.components!!.store.state }
|
||||
private val thumbnailStorage: ThumbnailStorage by lazy { GlobalComponents.components!!.thumbnailStorage }
|
||||
private val events: GeckoStateEvents by lazy { GlobalComponents.components!!.flutterEvents }
|
||||
private val engineView: EngineView? by lazy { GlobalComponents.components!!.engineView }
|
||||
|
||||
override fun loadUrl(
|
||||
tabId: String?,
|
||||
@@ -124,4 +142,21 @@ class GeckoSessionApiImpl : GeckoSessionApi {
|
||||
lastAccess = lastAccess ?: System.currentTimeMillis()
|
||||
)
|
||||
}
|
||||
|
||||
override fun requestScreenshot(callback: (Result<ByteArray?>) -> Unit) {
|
||||
val tab = state.selectedTab
|
||||
if (tab != null) {
|
||||
engineView?.captureThumbnail { bitmap ->
|
||||
if (bitmap != null) {
|
||||
store.dispatch(ContentAction.UpdateThumbnailAction(tab.id, bitmap))
|
||||
val compressed = bitmap.toWebPBytes()
|
||||
callback(Result.success(compressed))
|
||||
} else {
|
||||
callback(Result.success(null))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(Exception("No selected tab for screenshot")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+145
@@ -8,7 +8,18 @@ import eu.lensai.flutter_mozilla_components.pigeons.RestoreLocation as PigeonRes
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.RecoverableTab as PigeonRecoverableTab
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.SourceValue
|
||||
import eu.lensai.flutter_mozilla_components.GlobalComponents
|
||||
import eu.lensai.flutter_mozilla_components.ext.toWebPBytes
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.FindResultState
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.HistoryItem
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.HistoryState
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.ReaderableState
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.RestoreLocation
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.SecurityInfoState
|
||||
import eu.lensai.flutter_mozilla_components.pigeons.TabContentState
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.browser.session.storage.RecoverableBrowserState
|
||||
import mozilla.components.browser.state.action.TabListAction
|
||||
import mozilla.components.browser.state.selector.findTab
|
||||
@@ -18,16 +29,21 @@ import mozilla.components.browser.state.state.ReaderState
|
||||
import mozilla.components.browser.state.state.SessionState
|
||||
import mozilla.components.browser.state.state.recover.RecoverableTab
|
||||
import mozilla.components.browser.state.state.recover.TabState
|
||||
import mozilla.components.browser.thumbnails.storage.ThumbnailStorage
|
||||
import mozilla.components.concept.base.images.ImageLoadRequest
|
||||
import mozilla.components.concept.engine.Engine
|
||||
import mozilla.components.concept.engine.EngineSession
|
||||
import mozilla.components.concept.storage.HistoryMetadataKey
|
||||
import mozilla.components.feature.tabs.TabsUseCases
|
||||
import org.json.JSONObject
|
||||
import org.mozilla.gecko.util.ThreadUtils.runOnUiThread
|
||||
|
||||
class GeckoTabsApiImpl() : GeckoTabsApi {
|
||||
private val tabsUseCases: TabsUseCases by lazy { GlobalComponents.components!!.tabsUseCases }
|
||||
private val engine: Engine by lazy { GlobalComponents.components!!.engine }
|
||||
private val state: BrowserState by lazy { GlobalComponents.components!!.store.state }
|
||||
private val thumbnailStorage: ThumbnailStorage by lazy { GlobalComponents.components!!.thumbnailStorage }
|
||||
private val events: GeckoStateEvents by lazy { GlobalComponents.components!!.flutterEvents }
|
||||
|
||||
private fun restoreSource(source: SourceValue ) : SessionState.Source {
|
||||
return SessionState.Source.restore(
|
||||
@@ -88,6 +104,135 @@ class GeckoTabsApiImpl() : GeckoTabsApi {
|
||||
}
|
||||
}
|
||||
|
||||
override fun syncEvents(
|
||||
onSelectedTabChange: Boolean,
|
||||
onTabListChange: Boolean,
|
||||
onTabContentStateChange: Boolean,
|
||||
onIconChange: Boolean,
|
||||
onSecurityInfoStateChange: Boolean,
|
||||
onReaderableStateChange: Boolean,
|
||||
onHistoryStateChange: Boolean,
|
||||
onFindResults: Boolean,
|
||||
onThumbnailChange: Boolean,
|
||||
) {
|
||||
if(onSelectedTabChange) {
|
||||
events.onSelectedTabChange(
|
||||
state.selectedTabId
|
||||
) { _ -> }
|
||||
}
|
||||
|
||||
if(onTabListChange) {
|
||||
events.onTabListChange(state.tabs.map {tab -> tab.id}) { _ -> }
|
||||
}
|
||||
|
||||
if(onTabContentStateChange) {
|
||||
state.tabs.forEach { tab ->
|
||||
events.onTabContentStateChange(
|
||||
TabContentState(
|
||||
id = tab.id,
|
||||
contextId = tab.contextId,
|
||||
url = tab.content.url,
|
||||
title = tab.content.title,
|
||||
progress = tab.content.progress.toLong(),
|
||||
isPrivate = tab.content.private,
|
||||
isFullScreen = tab.content.fullScreen,
|
||||
isLoading = tab.content.loading
|
||||
)
|
||||
) { _ -> }
|
||||
}
|
||||
}
|
||||
|
||||
if(onIconChange) {
|
||||
state.tabs.forEach { tab ->
|
||||
if(tab.content.icon != null) {
|
||||
val iconBytes = tab.content.icon?.toWebPBytes()
|
||||
events.onIconChange(
|
||||
tab.id,
|
||||
iconBytes
|
||||
) { _ -> }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(onSecurityInfoStateChange) {
|
||||
state.tabs.forEach { tab ->
|
||||
val iconBytes = tab.content.icon?.toWebPBytes()
|
||||
events.onSecurityInfoStateChange(
|
||||
tab.id,
|
||||
SecurityInfoState(
|
||||
tab.content.securityInfo.secure,
|
||||
tab.content.securityInfo.host,
|
||||
tab.content.securityInfo.issuer,
|
||||
)
|
||||
) { _ -> }
|
||||
}
|
||||
}
|
||||
|
||||
if(onReaderableStateChange) {
|
||||
state.tabs.forEach { tab ->
|
||||
events.onReaderableStateChange(
|
||||
tab.id,
|
||||
ReaderableState(
|
||||
tab.readerState.readerable,
|
||||
tab.readerState.active,
|
||||
)
|
||||
) { _ -> }
|
||||
}
|
||||
}
|
||||
|
||||
if(onHistoryStateChange) {
|
||||
state.tabs.forEach { tab ->
|
||||
events.onHistoryStateChange(
|
||||
tab.id,
|
||||
HistoryState(
|
||||
items = tab.content.history.items.map { item -> HistoryItem(
|
||||
url = item.uri,
|
||||
title = item.title
|
||||
) },
|
||||
currentIndex = tab.content.history.currentIndex.toLong(),
|
||||
canGoBack = tab.content.canGoBack,
|
||||
canGoForward = tab.content.canGoForward,
|
||||
)
|
||||
) { _ -> }
|
||||
}
|
||||
}
|
||||
|
||||
if(onFindResults) {
|
||||
state.tabs.forEach { tab ->
|
||||
events.onFindResults(
|
||||
tab.id,
|
||||
tab.content.findResults.map { result -> FindResultState(
|
||||
activeMatchOrdinal = result.activeMatchOrdinal.toLong(),
|
||||
numberOfMatches = result.numberOfMatches.toLong(),
|
||||
isDoneCounting = result.isDoneCounting,
|
||||
) }
|
||||
) { _ -> }
|
||||
}
|
||||
}
|
||||
|
||||
if(onThumbnailChange) {
|
||||
state.tabs.forEach { tab ->
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
val bitmap = thumbnailStorage.loadThumbnail(
|
||||
ImageLoadRequest(
|
||||
id = tab.id,
|
||||
//TODO: make this configurable
|
||||
size = 600,
|
||||
isPrivate = tab.content.private
|
||||
)
|
||||
).await()
|
||||
|
||||
if(bitmap != null) {
|
||||
val bytes = bitmap.toWebPBytes()
|
||||
runOnUiThread {
|
||||
events.onThumbnailChange(tab.id, bytes) { _ -> }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun selectTab(tabId: String) {
|
||||
tabsUseCases.selectTab(tabId = tabId)
|
||||
}
|
||||
|
||||
+4
-1
@@ -12,6 +12,7 @@ import mozilla.components.browser.state.action.ContentAction
|
||||
import mozilla.components.browser.state.state.BrowserState
|
||||
import mozilla.components.lib.state.Middleware
|
||||
import mozilla.components.lib.state.MiddlewareContext
|
||||
import org.mozilla.gecko.util.ThreadUtils.runOnUiThread
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
|
||||
@@ -30,7 +31,9 @@ class FlutterEventMiddleware(private val flutterEvents: GeckoStateEvents) : Midd
|
||||
when (action) {
|
||||
is ContentAction.UpdateThumbnailAction -> {
|
||||
val bytes = action.thumbnail.toWebPBytes()
|
||||
flutterEvents.onThumbnailChange(action.sessionId, bytes) { _ -> }
|
||||
runOnUiThread {
|
||||
flutterEvents.onThumbnailChange(action.sessionId, bytes) { _ -> }
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
// no-op
|
||||
|
||||
+64
-18
@@ -1,4 +1,4 @@
|
||||
// Autogenerated from Pigeon (v22.4.2), do not edit directly.
|
||||
// Autogenerated from Pigeon (v22.5.0), do not edit directly.
|
||||
// See also: https://pub.dev/packages/pigeon
|
||||
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
|
||||
|
||||
@@ -1239,6 +1239,7 @@ interface GeckoSessionApi {
|
||||
fun crashRecovery(tabIds: List<String>?)
|
||||
fun purgeHistory()
|
||||
fun updateLastAccess(tabId: String?, lastAccess: Long?)
|
||||
fun requestScreenshot(callback: (Result<ByteArray?>) -> Unit)
|
||||
|
||||
companion object {
|
||||
/** The codec used by GeckoSessionApi. */
|
||||
@@ -1550,11 +1551,30 @@ interface GeckoSessionApi {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoSessionApi.requestScreenshot$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { _, reply ->
|
||||
api.requestScreenshot{ result: Result<ByteArray?> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
} else {
|
||||
val data = result.getOrNull()
|
||||
reply.reply(wrapResult(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 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 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
|
||||
@@ -1585,6 +1605,32 @@ interface GeckoTabsApi {
|
||||
@JvmOverloads
|
||||
fun setUp(binaryMessenger: BinaryMessenger, api: GeckoTabsApi?, messageChannelSuffix: String = "") {
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoTabsApi.syncEvents$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val onSelectedTabChangeArg = args[0] as Boolean
|
||||
val onTabListChangeArg = args[1] as Boolean
|
||||
val onTabContentStateChangeArg = args[2] as Boolean
|
||||
val onIconChangeArg = args[3] as Boolean
|
||||
val onSecurityInfoStateChangeArg = args[4] as Boolean
|
||||
val onReaderableStateChangeArg = args[5] as Boolean
|
||||
val onHistoryStateChangeArg = args[6] as Boolean
|
||||
val onFindResultsArg = args[7] as Boolean
|
||||
val onThumbnailChangeArg = args[8] as Boolean
|
||||
val wrapped: List<Any?> = try {
|
||||
api.syncEvents(onSelectedTabChangeArg, onTabListChangeArg, onTabContentStateChangeArg, onIconChangeArg, onSecurityInfoStateChangeArg, onReaderableStateChangeArg, onHistoryStateChangeArg, onFindResultsArg, onThumbnailChangeArg)
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoTabsApi.selectTab$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
@@ -2107,6 +2153,23 @@ class GeckoStateEvents(private val binaryMessenger: BinaryMessenger, private val
|
||||
GeckoPigeonCodec()
|
||||
}
|
||||
}
|
||||
fun onFragmentReadyStateChange(stateArg: Boolean, callback: (Result<Unit>) -> Unit)
|
||||
{
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
val channelName = "dev.flutter.pigeon.flutter_mozilla_components.GeckoStateEvents.onFragmentReadyStateChange$separatedMessageChannelSuffix"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(stateArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else {
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun onTabListChange(tabIdsArg: List<String>, callback: (Result<Unit>) -> Unit)
|
||||
{
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
@@ -2337,23 +2400,6 @@ class ReaderViewController(private val binaryMessenger: BinaryMessenger, private
|
||||
}
|
||||
}
|
||||
}
|
||||
fun readerViewButtonVisibility(visibleArg: Boolean, callback: (Result<Unit>) -> Unit)
|
||||
{
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
val channelName = "dev.flutter.pigeon.flutter_mozilla_components.ReaderViewController.readerViewButtonVisibility$separatedMessageChannelSuffix"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(visibleArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else {
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */
|
||||
class SelectionAction(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
|
||||
// Typedefs for record types
|
||||
typedef HistoryEvent = ({String tabId, HistoryState history});
|
||||
@@ -12,74 +13,79 @@ typedef FindResultsEvent = ({String tabId, List<FindResultState> results});
|
||||
|
||||
class GeckoEventService extends GeckoStateEvents {
|
||||
// Stream controllers
|
||||
final _tabListController = StreamController<List<String>>.broadcast();
|
||||
final _selectedTabController = StreamController<String?>.broadcast();
|
||||
final _tabContentController = StreamController<TabContentState>.broadcast();
|
||||
final _historyController = StreamController<HistoryEvent>.broadcast();
|
||||
final _readerableController = StreamController<ReaderableEvent>.broadcast();
|
||||
final _securityInfoController =
|
||||
StreamController<SecurityInfoEvent>.broadcast();
|
||||
final _iconController = StreamController<IconEvent>.broadcast();
|
||||
final _thumbnailController = StreamController<ThumbnailEvent>.broadcast();
|
||||
final _findResultsController = StreamController<FindResultsEvent>.broadcast();
|
||||
final _fragmentStateSubject = BehaviorSubject.seeded(false);
|
||||
final _tabListSubject = BehaviorSubject<List<String>>();
|
||||
final _selectedTabSubject = BehaviorSubject<String?>();
|
||||
final _tabContentSubject = BehaviorSubject<TabContentState>();
|
||||
final _historySubject = BehaviorSubject<HistoryEvent>();
|
||||
final _readerableSubject = BehaviorSubject<ReaderableEvent>();
|
||||
final _securityInfoSubject = BehaviorSubject<SecurityInfoEvent>();
|
||||
final _iconSubject = BehaviorSubject<IconEvent>();
|
||||
final _thumbnailSubject = BehaviorSubject<ThumbnailEvent>();
|
||||
final _findResultsSubject = BehaviorSubject<FindResultsEvent>();
|
||||
|
||||
// Event streams
|
||||
Stream<List<String>> get tabListEvents => _tabListController.stream;
|
||||
Stream<String?> get selectedTabEvents => _selectedTabController.stream;
|
||||
Stream<TabContentState> get tabContentEvents => _tabContentController.stream;
|
||||
Stream<HistoryEvent> get historyEvents => _historyController.stream;
|
||||
Stream<ReaderableEvent> get readerableEvents => _readerableController.stream;
|
||||
Stream<bool> get fragmentReadyStateEvents => _fragmentStateSubject.stream;
|
||||
Stream<List<String>> get tabListEvents => _tabListSubject.stream;
|
||||
Stream<String?> get selectedTabEvents => _selectedTabSubject.stream;
|
||||
Stream<TabContentState> get tabContentEvents => _tabContentSubject.stream;
|
||||
Stream<HistoryEvent> get historyEvents => _historySubject.stream;
|
||||
Stream<ReaderableEvent> get readerableEvents => _readerableSubject.stream;
|
||||
Stream<SecurityInfoEvent> get securityInfoEvents =>
|
||||
_securityInfoController.stream;
|
||||
Stream<IconEvent> get iconEvents => _iconController.stream;
|
||||
Stream<ThumbnailEvent> get thumbnailEvents => _thumbnailController.stream;
|
||||
Stream<FindResultsEvent> get findResultsEvent =>
|
||||
_findResultsController.stream;
|
||||
_securityInfoSubject.stream;
|
||||
Stream<IconEvent> get iconEvents => _iconSubject.stream;
|
||||
Stream<ThumbnailEvent> get thumbnailEvents => _thumbnailSubject.stream;
|
||||
Stream<FindResultsEvent> get findResultsEvent => _findResultsSubject.stream;
|
||||
|
||||
@override
|
||||
void onFragmentReadyStateChange(bool state) {
|
||||
_fragmentStateSubject.add(state);
|
||||
}
|
||||
|
||||
// Overridden methods
|
||||
@override
|
||||
void onTabListChange(List<String?> tabIds) {
|
||||
_tabListController.add(tabIds.nonNulls.toList());
|
||||
_tabListSubject.add(tabIds.nonNulls.toList());
|
||||
}
|
||||
|
||||
@override
|
||||
void onSelectedTabChange(String? id) {
|
||||
_selectedTabController.add(id);
|
||||
_selectedTabSubject.add(id);
|
||||
}
|
||||
|
||||
@override
|
||||
void onTabContentStateChange(TabContentState state) {
|
||||
_tabContentController.add(state);
|
||||
_tabContentSubject.add(state);
|
||||
}
|
||||
|
||||
@override
|
||||
void onHistoryStateChange(String id, HistoryState state) {
|
||||
_historyController.add((tabId: id, history: state));
|
||||
_historySubject.add((tabId: id, history: state));
|
||||
}
|
||||
|
||||
@override
|
||||
void onReaderableStateChange(String id, ReaderableState state) {
|
||||
_readerableController.add((tabId: id, readerable: state));
|
||||
_readerableSubject.add((tabId: id, readerable: state));
|
||||
}
|
||||
|
||||
@override
|
||||
void onSecurityInfoStateChange(String id, SecurityInfoState state) {
|
||||
_securityInfoController.add((tabId: id, securityInfo: state));
|
||||
_securityInfoSubject.add((tabId: id, securityInfo: state));
|
||||
}
|
||||
|
||||
@override
|
||||
void onIconChange(String id, Uint8List? bytes) {
|
||||
_iconController.add((tabId: id, bytes: bytes));
|
||||
_iconSubject.add((tabId: id, bytes: bytes));
|
||||
}
|
||||
|
||||
@override
|
||||
void onThumbnailChange(String id, Uint8List? bytes) {
|
||||
_thumbnailController.add((tabId: id, bytes: bytes));
|
||||
_thumbnailSubject.add((tabId: id, bytes: bytes));
|
||||
}
|
||||
|
||||
@override
|
||||
void onFindResults(String id, List<FindResultState?> results) {
|
||||
_findResultsController.add((tabId: id, results: results.nonNulls.toList()));
|
||||
_findResultsSubject.add((tabId: id, results: results.nonNulls.toList()));
|
||||
}
|
||||
|
||||
GeckoEventService.setUp({
|
||||
@@ -94,14 +100,14 @@ class GeckoEventService extends GeckoStateEvents {
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
unawaited(_tabListController.close());
|
||||
unawaited(_selectedTabController.close());
|
||||
unawaited(_tabContentController.close());
|
||||
unawaited(_historyController.close());
|
||||
unawaited(_readerableController.close());
|
||||
unawaited(_securityInfoController.close());
|
||||
unawaited(_iconController.close());
|
||||
unawaited(_thumbnailController.close());
|
||||
unawaited(_findResultsController.close());
|
||||
unawaited(_tabListSubject.close());
|
||||
unawaited(_selectedTabSubject.close());
|
||||
unawaited(_tabContentSubject.close());
|
||||
unawaited(_historySubject.close());
|
||||
unawaited(_readerableSubject.close());
|
||||
unawaited(_securityInfoSubject.close());
|
||||
unawaited(_iconSubject.close());
|
||||
unawaited(_thumbnailSubject.close());
|
||||
unawaited(_findResultsSubject.close());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@ import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
|
||||
class GeckoReaderableService extends ReaderViewController {
|
||||
final ReaderViewEvents _events;
|
||||
|
||||
final _appearanceVisibility = StreamController<bool>.broadcast();
|
||||
final _readerVisibility = StreamController<bool>.broadcast();
|
||||
final _appearanceVisibility = BehaviorSubject<bool>();
|
||||
final _readerVisibility = BehaviorSubject<bool>();
|
||||
|
||||
Stream<bool> get appearanceVisibility => _appearanceVisibility.stream;
|
||||
Stream<bool> get readerVisibility => _readerVisibility.stream;
|
||||
|
||||
Future<void> toggleReaderView(bool enable) {
|
||||
return _events.onToggleReaderView(enable);
|
||||
@@ -25,11 +25,6 @@ class GeckoReaderableService extends ReaderViewController {
|
||||
_appearanceVisibility.add(visible);
|
||||
}
|
||||
|
||||
@override
|
||||
void readerViewButtonVisibility(bool visible) {
|
||||
_readerVisibility.add(visible);
|
||||
}
|
||||
|
||||
GeckoReaderableService.setUp({
|
||||
ReaderViewEvents? readerEvents,
|
||||
BinaryMessenger? binaryMessenger,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter_mozilla_components/src/data/models/load_url_flags.dart';
|
||||
import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart';
|
||||
|
||||
@@ -118,6 +120,14 @@ class GeckoSessionService {
|
||||
return _api.purgeHistory();
|
||||
}
|
||||
|
||||
Future<Uint8List?> requestScreenshot() {
|
||||
if (tabId != null) {
|
||||
throw Exception('Screenshot only allowed for selected (visible) tab.');
|
||||
}
|
||||
|
||||
return _api.requestScreenshot();
|
||||
}
|
||||
|
||||
Future<void> updateLastAccess({
|
||||
String? tabId, //If null = current tab
|
||||
DateTime? lastAccess, //If null datetime.now
|
||||
|
||||
@@ -10,6 +10,29 @@ class GeckoTabService {
|
||||
|
||||
GeckoTabService({GeckoTabsApi? api}) : _api = api ?? _apiInstance;
|
||||
|
||||
Future<void> syncEvents({
|
||||
bool onSelectedTabChange = true,
|
||||
bool onTabListChange = true,
|
||||
bool onTabContentStateChange = true,
|
||||
bool onIconChange = true,
|
||||
bool onSecurityInfoStateChange = true,
|
||||
bool onHistoryStateChange = true,
|
||||
bool onFindResults = true,
|
||||
bool onThumbnailChange = true,
|
||||
}) {
|
||||
return _api.syncEvents(
|
||||
onSelectedTabChange: onSelectedTabChange,
|
||||
onTabListChange: onTabListChange,
|
||||
onTabContentStateChange: onTabContentStateChange,
|
||||
onIconChange: onIconChange,
|
||||
onSecurityInfoStateChange: onSecurityInfoStateChange,
|
||||
onHistoryStateChange: onHistoryStateChange,
|
||||
onFindResults: onFindResults,
|
||||
onThumbnailChange: onThumbnailChange,
|
||||
onReaderableStateChange: false,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> selectTab({required String tabId}) {
|
||||
return _api.selectTab(tabId: tabId);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -7,7 +9,9 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mozilla_components/src/domain/services/gecko_browser.dart';
|
||||
|
||||
class GeckoView extends StatelessWidget {
|
||||
const GeckoView({super.key});
|
||||
final FutureOr<void> Function()? preInitializationStep;
|
||||
|
||||
const GeckoView({super.key, this.preInitializationStep});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -35,6 +39,7 @@ class GeckoView extends StatelessWidget {
|
||||
params.onPlatformViewCreated(value);
|
||||
|
||||
SchedulerBinding.instance.addPostFrameCallback((_) async {
|
||||
await preInitializationStep?.call();
|
||||
await GeckoBrowserService().showNativeFragment();
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Autogenerated from Pigeon (v22.4.2), do not edit directly.
|
||||
// Autogenerated from Pigeon (v22.5.0), do not edit directly.
|
||||
// See also: https://pub.dev/packages/pigeon
|
||||
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers
|
||||
|
||||
@@ -1589,6 +1589,28 @@ class GeckoSessionApi {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future<Uint8List?> requestScreenshot() async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoSessionApi.requestScreenshot$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_channel.send(null) as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: pigeonVar_replyList[0]! as String,
|
||||
message: pigeonVar_replyList[1] as String?,
|
||||
details: pigeonVar_replyList[2],
|
||||
);
|
||||
} else {
|
||||
return (pigeonVar_replyList[0] as Uint8List?);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GeckoTabsApi {
|
||||
@@ -1604,6 +1626,28 @@ 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 {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoTabsApi.syncEvents$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_channel.send(<Object?>[onSelectedTabChange, onTabListChange, onTabContentStateChange, onIconChange, onSecurityInfoStateChange, onReaderableStateChange, onHistoryStateChange, onFindResults, onThumbnailChange]) as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: pigeonVar_replyList[0]! as String,
|
||||
message: pigeonVar_replyList[1] as String?,
|
||||
details: pigeonVar_replyList[2],
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> selectTab({required String tabId}) async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoTabsApi.selectTab$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
@@ -2199,6 +2243,8 @@ class GeckoCookieApi {
|
||||
abstract class GeckoStateEvents {
|
||||
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
|
||||
|
||||
void onFragmentReadyStateChange(bool state);
|
||||
|
||||
void onTabListChange(List<String> tabIds);
|
||||
|
||||
void onSelectedTabChange(String? id);
|
||||
@@ -2219,6 +2265,31 @@ abstract class GeckoStateEvents {
|
||||
|
||||
static void setUp(GeckoStateEvents? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) {
|
||||
messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
|
||||
{
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.flutter_mozilla_components.GeckoStateEvents.onFragmentReadyStateChange$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_mozilla_components.GeckoStateEvents.onFragmentReadyStateChange was null.');
|
||||
final List<Object?> args = (message as List<Object?>?)!;
|
||||
final bool? arg_state = (args[0] as bool?);
|
||||
assert(arg_state != null,
|
||||
'Argument for dev.flutter.pigeon.flutter_mozilla_components.GeckoStateEvents.onFragmentReadyStateChange was null, expected non-null bool.');
|
||||
try {
|
||||
api.onFragmentReadyStateChange(arg_state!);
|
||||
return wrapResponse(empty: true);
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: e);
|
||||
} catch (e) {
|
||||
return wrapResponse(error: PlatformException(code: 'error', message: e.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.flutter_mozilla_components.GeckoStateEvents.onTabListChange$messageChannelSuffix', pigeonChannelCodec,
|
||||
@@ -2522,8 +2593,6 @@ abstract class ReaderViewController {
|
||||
|
||||
void appearanceButtonVisibility(bool visible);
|
||||
|
||||
void readerViewButtonVisibility(bool visible);
|
||||
|
||||
static void setUp(ReaderViewController? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) {
|
||||
messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
|
||||
{
|
||||
@@ -2551,31 +2620,6 @@ abstract class ReaderViewController {
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.flutter_mozilla_components.ReaderViewController.readerViewButtonVisibility$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_mozilla_components.ReaderViewController.readerViewButtonVisibility was null.');
|
||||
final List<Object?> args = (message as List<Object?>?)!;
|
||||
final bool? arg_visible = (args[0] as bool?);
|
||||
assert(arg_visible != null,
|
||||
'Argument for dev.flutter.pigeon.flutter_mozilla_components.ReaderViewController.readerViewButtonVisibility was null, expected non-null bool.');
|
||||
try {
|
||||
api.readerViewButtonVisibility(arg_visible!);
|
||||
return wrapResponse(empty: true);
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: e);
|
||||
} catch (e) {
|
||||
return wrapResponse(error: PlatformException(code: 'error', message: e.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -624,10 +624,25 @@ abstract class GeckoSessionApi {
|
||||
required String? tabId, //If null = current tab
|
||||
required int? lastAccess, //If null datetime.now
|
||||
});
|
||||
|
||||
@async
|
||||
Uint8List? requestScreenshot();
|
||||
}
|
||||
|
||||
@HostApi()
|
||||
abstract class GeckoTabsApi {
|
||||
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,
|
||||
});
|
||||
|
||||
void selectTab({required String tabId});
|
||||
|
||||
void removeTab({required String tabId});
|
||||
@@ -767,6 +782,8 @@ abstract class GeckoCookieApi {
|
||||
|
||||
@FlutterApi()
|
||||
abstract class GeckoStateEvents {
|
||||
void onFragmentReadyStateChange(bool state);
|
||||
|
||||
void onTabListChange(List<String> tabIds);
|
||||
void onSelectedTabChange(String? id);
|
||||
|
||||
@@ -789,7 +806,6 @@ abstract class ReaderViewEvents {
|
||||
@FlutterApi()
|
||||
abstract class ReaderViewController {
|
||||
void appearanceButtonVisibility(bool visible);
|
||||
void readerViewButtonVisibility(bool visible);
|
||||
}
|
||||
|
||||
@FlutterApi()
|
||||
|
||||
@@ -11,12 +11,13 @@ dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
plugin_platform_interface: ^2.1.8
|
||||
rxdart: ^0.28.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
lint: ^2.3.0
|
||||
pigeon: ^22.4.2
|
||||
pigeon: ^22.5.0
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
Reference in New Issue
Block a user