suggest title based on selection
This commit is contained in:
@@ -27,6 +27,7 @@ import 'package:nullability/nullability.dart';
|
||||
import 'package:riverpod/riverpod.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:synchronized/synchronized.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart';
|
||||
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||
import 'package:weblibre/utils/lru_cache.dart';
|
||||
@@ -251,6 +252,33 @@ Future<String?> containerTopic(Ref ref, String containerId) async {
|
||||
|
||||
if (!ref.mounted) return null;
|
||||
|
||||
final topic = await ref.watch(topicSuggestionProvider(titles).future);
|
||||
|
||||
if (ref.mounted && topic.isNotEmpty) {
|
||||
ref.keepAlive();
|
||||
}
|
||||
|
||||
return topic;
|
||||
}
|
||||
|
||||
@Riverpod()
|
||||
AsyncValue<String?> tabsTopic(Ref ref, EquatableValue<Set<String>> tabIds) {
|
||||
final tabTitles = ref.watch(
|
||||
tabStatesProvider.select((states) {
|
||||
return EquatableValue(
|
||||
tabIds.value.map((tabId) => states[tabId]?.title).nonNulls.toSet(),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
return ref.watch(topicSuggestionProvider(tabTitles));
|
||||
}
|
||||
|
||||
@Riverpod()
|
||||
Future<String?> topicSuggestion(
|
||||
Ref ref,
|
||||
EquatableValue<Set<String>> titles,
|
||||
) async {
|
||||
final topic = await ref
|
||||
.read(geckoInferenceRepositoryProvider.notifier)
|
||||
.predictDocumentTopic(titles.value);
|
||||
|
||||
+161
-1
@@ -112,7 +112,7 @@ final class ContainerTopicProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$containerTopicHash() => r'ddb306605a0e38b1d750bf4412cbd595f8f264cc';
|
||||
String _$containerTopicHash() => r'c6e4cc316d3f05d0316909ec0bb58a95ad2fd57c';
|
||||
|
||||
final class ContainerTopicFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<String?>, String> {
|
||||
@@ -132,6 +132,166 @@ final class ContainerTopicFamily extends $Family
|
||||
String toString() => r'containerTopicProvider';
|
||||
}
|
||||
|
||||
@ProviderFor(tabsTopic)
|
||||
const tabsTopicProvider = TabsTopicFamily._();
|
||||
|
||||
final class TabsTopicProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
AsyncValue<String?>,
|
||||
AsyncValue<String?>,
|
||||
AsyncValue<String?>
|
||||
>
|
||||
with $Provider<AsyncValue<String?>> {
|
||||
const TabsTopicProvider._({
|
||||
required TabsTopicFamily super.from,
|
||||
required EquatableValue<Set<String>> super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'tabsTopicProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$tabsTopicHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'tabsTopicProvider'
|
||||
''
|
||||
'($argument)';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<AsyncValue<String?>> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
AsyncValue<String?> create(Ref ref) {
|
||||
final argument = this.argument as EquatableValue<Set<String>>;
|
||||
return tabsTopic(ref, argument);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(AsyncValue<String?> value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<AsyncValue<String?>>(value),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is TabsTopicProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
String _$tabsTopicHash() => r'b144f86782510333a48e92c4a2c70ac285da6bcb';
|
||||
|
||||
final class TabsTopicFamily extends $Family
|
||||
with
|
||||
$FunctionalFamilyOverride<
|
||||
AsyncValue<String?>,
|
||||
EquatableValue<Set<String>>
|
||||
> {
|
||||
const TabsTopicFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'tabsTopicProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
TabsTopicProvider call(EquatableValue<Set<String>> tabIds) =>
|
||||
TabsTopicProvider._(argument: tabIds, from: this);
|
||||
|
||||
@override
|
||||
String toString() => r'tabsTopicProvider';
|
||||
}
|
||||
|
||||
@ProviderFor(topicSuggestion)
|
||||
const topicSuggestionProvider = TopicSuggestionFamily._();
|
||||
|
||||
final class TopicSuggestionProvider
|
||||
extends $FunctionalProvider<AsyncValue<String?>, String?, FutureOr<String?>>
|
||||
with $FutureModifier<String?>, $FutureProvider<String?> {
|
||||
const TopicSuggestionProvider._({
|
||||
required TopicSuggestionFamily super.from,
|
||||
required EquatableValue<Set<String>> super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'topicSuggestionProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$topicSuggestionHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'topicSuggestionProvider'
|
||||
''
|
||||
'($argument)';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$FutureProviderElement<String?> $createElement($ProviderPointer pointer) =>
|
||||
$FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
FutureOr<String?> create(Ref ref) {
|
||||
final argument = this.argument as EquatableValue<Set<String>>;
|
||||
return topicSuggestion(ref, argument);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is TopicSuggestionProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
String _$topicSuggestionHash() => r'5401b1cd91e53be6ad1b4c7a39a5253d380e05d4';
|
||||
|
||||
final class TopicSuggestionFamily extends $Family
|
||||
with
|
||||
$FunctionalFamilyOverride<
|
||||
FutureOr<String?>,
|
||||
EquatableValue<Set<String>>
|
||||
> {
|
||||
const TopicSuggestionFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'topicSuggestionProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
TopicSuggestionProvider call(EquatableValue<Set<String>> titles) =>
|
||||
TopicSuggestionProvider._(argument: titles, from: this);
|
||||
|
||||
@override
|
||||
String toString() => r'topicSuggestionProvider';
|
||||
}
|
||||
|
||||
@ProviderFor(suggestClusters)
|
||||
const suggestClustersProvider = SuggestClustersProvider._();
|
||||
|
||||
|
||||
+47
-4
@@ -1,9 +1,13 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:fast_equatable/fast_equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:nullability/nullability.dart';
|
||||
import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:weblibre/core/logger.dart';
|
||||
import 'package:weblibre/core/routing/routes.dart';
|
||||
import 'package:weblibre/core/uuid.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart';
|
||||
@@ -64,8 +68,35 @@ class ContainerDraftSuggestionsScreen extends HookConsumerWidget {
|
||||
itemId: (container) => container,
|
||||
itemAvatar: (container) =>
|
||||
const Icon(MdiIcons.creation, size: 20),
|
||||
itemLabel: (container) =>
|
||||
Text(container.topic ?? 'Untitled'),
|
||||
itemLabel: (container) => HookConsumer(
|
||||
builder: (context, ref, child) {
|
||||
final items = useListenableSelector(
|
||||
selectedContainerTabs,
|
||||
() => selectedContainerTabs.value[container],
|
||||
);
|
||||
|
||||
final topic = items.isNotEmpty
|
||||
? ref.watch(
|
||||
tabsTopicProvider(EquatableValue(items!)),
|
||||
)
|
||||
: AsyncValue.data(container.topic);
|
||||
|
||||
return topic.when(
|
||||
data: (topic) => Text(topic ?? 'Untitled'),
|
||||
error: (error, stackTrace) {
|
||||
logger.e(
|
||||
'Failed predicting selected tabs topic',
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
|
||||
return Text(container.topic ?? 'Untitled');
|
||||
},
|
||||
loading: () =>
|
||||
const Skeletonizer(child: Text('Untitled')),
|
||||
);
|
||||
},
|
||||
),
|
||||
itemBadgeCount: (container) => container.tabIds.length,
|
||||
availableItems: suggestions!,
|
||||
selectedItem: selectedContainer.value,
|
||||
@@ -150,7 +181,19 @@ class ContainerDraftSuggestionsScreen extends HookConsumerWidget {
|
||||
final initialContainer = ContainerData(
|
||||
id: uuid.v7(),
|
||||
color: initialColor,
|
||||
name: selectedContainer.value?.topic,
|
||||
name:
|
||||
(ref.exists(
|
||||
tabsTopicProvider(EquatableValue(selectedTabs!)),
|
||||
))
|
||||
? ref
|
||||
.read(
|
||||
tabsTopicProvider(
|
||||
EquatableValue(selectedTabs),
|
||||
),
|
||||
)
|
||||
.value ??
|
||||
selectedContainer.value?.topic
|
||||
: selectedContainer.value?.topic,
|
||||
);
|
||||
|
||||
if (context.mounted) {
|
||||
@@ -159,7 +202,7 @@ class ContainerDraftSuggestionsScreen extends HookConsumerWidget {
|
||||
).push<ContainerData?>(context);
|
||||
|
||||
if (result != null) {
|
||||
for (final tab in selectedTabs!) {
|
||||
for (final tab in selectedTabs) {
|
||||
await ref
|
||||
.read(tabDataRepositoryProvider.notifier)
|
||||
.assignContainer(tab, result);
|
||||
|
||||
Reference in New Issue
Block a user