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/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:synchronized/synchronized.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/geckoview/features/tabs/domain/providers.dart';
|
||||||
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
import 'package:weblibre/utils/lru_cache.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;
|
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
|
final topic = await ref
|
||||||
.read(geckoInferenceRepositoryProvider.notifier)
|
.read(geckoInferenceRepositoryProvider.notifier)
|
||||||
.predictDocumentTopic(titles.value);
|
.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
|
final class ContainerTopicFamily extends $Family
|
||||||
with $FunctionalFamilyOverride<FutureOr<String?>, String> {
|
with $FunctionalFamilyOverride<FutureOr<String?>, String> {
|
||||||
@@ -132,6 +132,166 @@ final class ContainerTopicFamily extends $Family
|
|||||||
String toString() => r'containerTopicProvider';
|
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)
|
@ProviderFor(suggestClusters)
|
||||||
const suggestClustersProvider = SuggestClustersProvider._();
|
const suggestClustersProvider = SuggestClustersProvider._();
|
||||||
|
|
||||||
|
|||||||
+47
-4
@@ -1,9 +1,13 @@
|
|||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
import 'package:fast_equatable/fast_equatable.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.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/routing/routes.dart';
|
||||||
import 'package:weblibre/core/uuid.dart';
|
import 'package:weblibre/core/uuid.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.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,
|
itemId: (container) => container,
|
||||||
itemAvatar: (container) =>
|
itemAvatar: (container) =>
|
||||||
const Icon(MdiIcons.creation, size: 20),
|
const Icon(MdiIcons.creation, size: 20),
|
||||||
itemLabel: (container) =>
|
itemLabel: (container) => HookConsumer(
|
||||||
Text(container.topic ?? 'Untitled'),
|
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,
|
itemBadgeCount: (container) => container.tabIds.length,
|
||||||
availableItems: suggestions!,
|
availableItems: suggestions!,
|
||||||
selectedItem: selectedContainer.value,
|
selectedItem: selectedContainer.value,
|
||||||
@@ -150,7 +181,19 @@ class ContainerDraftSuggestionsScreen extends HookConsumerWidget {
|
|||||||
final initialContainer = ContainerData(
|
final initialContainer = ContainerData(
|
||||||
id: uuid.v7(),
|
id: uuid.v7(),
|
||||||
color: initialColor,
|
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) {
|
if (context.mounted) {
|
||||||
@@ -159,7 +202,7 @@ class ContainerDraftSuggestionsScreen extends HookConsumerWidget {
|
|||||||
).push<ContainerData?>(context);
|
).push<ContainerData?>(context);
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
for (final tab in selectedTabs!) {
|
for (final tab in selectedTabs) {
|
||||||
await ref
|
await ref
|
||||||
.read(tabDataRepositoryProvider.notifier)
|
.read(tabDataRepositoryProvider.notifier)
|
||||||
.assignContainer(tab, result);
|
.assignContainer(tab, result);
|
||||||
|
|||||||
Reference in New Issue
Block a user