container topic inference
This commit is contained in:
@@ -64,3 +64,9 @@ Stream<Map<String, String?>> tabDescendants(Ref ref, String tabId) {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Riverpod()
|
||||
Stream<List<TabData>> containerTabsData(Ref ref, String containerId) {
|
||||
final db = ref.watch(tabDatabaseProvider);
|
||||
return db.containerDao.getContainerTabsData(containerId).watch();
|
||||
}
|
||||
|
||||
@@ -442,5 +442,127 @@ class _TabDescendantsProviderElement
|
||||
String get tabId => (origin as TabDescendantsProvider).tabId;
|
||||
}
|
||||
|
||||
String _$containerTabsDataHash() => r'1987b2d69f2ba663a7343e93572aad3c31a29be3';
|
||||
|
||||
/// See also [containerTabsData].
|
||||
@ProviderFor(containerTabsData)
|
||||
const containerTabsDataProvider = ContainerTabsDataFamily();
|
||||
|
||||
/// See also [containerTabsData].
|
||||
class ContainerTabsDataFamily extends Family<AsyncValue<List<TabData>>> {
|
||||
/// See also [containerTabsData].
|
||||
const ContainerTabsDataFamily();
|
||||
|
||||
/// See also [containerTabsData].
|
||||
ContainerTabsDataProvider call(String containerId) {
|
||||
return ContainerTabsDataProvider(containerId);
|
||||
}
|
||||
|
||||
@override
|
||||
ContainerTabsDataProvider getProviderOverride(
|
||||
covariant ContainerTabsDataProvider provider,
|
||||
) {
|
||||
return call(provider.containerId);
|
||||
}
|
||||
|
||||
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'containerTabsDataProvider';
|
||||
}
|
||||
|
||||
/// See also [containerTabsData].
|
||||
class ContainerTabsDataProvider
|
||||
extends AutoDisposeStreamProvider<List<TabData>> {
|
||||
/// See also [containerTabsData].
|
||||
ContainerTabsDataProvider(String containerId)
|
||||
: this._internal(
|
||||
(ref) => containerTabsData(ref as ContainerTabsDataRef, containerId),
|
||||
from: containerTabsDataProvider,
|
||||
name: r'containerTabsDataProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$containerTabsDataHash,
|
||||
dependencies: ContainerTabsDataFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
ContainerTabsDataFamily._allTransitiveDependencies,
|
||||
containerId: containerId,
|
||||
);
|
||||
|
||||
ContainerTabsDataProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.containerId,
|
||||
}) : super.internal();
|
||||
|
||||
final String containerId;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
Stream<List<TabData>> Function(ContainerTabsDataRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: ContainerTabsDataProvider._internal(
|
||||
(ref) => create(ref as ContainerTabsDataRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
containerId: containerId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeStreamProviderElement<List<TabData>> createElement() {
|
||||
return _ContainerTabsDataProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is ContainerTabsDataProvider &&
|
||||
other.containerId == containerId;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, containerId.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin ContainerTabsDataRef on AutoDisposeStreamProviderRef<List<TabData>> {
|
||||
/// The parameter `containerId` of this provider.
|
||||
String get containerId;
|
||||
}
|
||||
|
||||
class _ContainerTabsDataProviderElement
|
||||
extends AutoDisposeStreamProviderElement<List<TabData>>
|
||||
with ContainerTabsDataRef {
|
||||
_ContainerTabsDataProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String get containerId => (origin as ContainerTabsDataProvider).containerId;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
||||
@@ -38,8 +38,7 @@ class SelectedContainer extends _$SelectedContainer {
|
||||
.read(localAuthenticationServiceProvider.notifier)
|
||||
.authenticate(
|
||||
authKey: 'container_access::${container.id}',
|
||||
localizedReason:
|
||||
'Require authentication for container ${container.name ?? 'New Container'}',
|
||||
localizedReason: 'Require authentication for container',
|
||||
settings: container.metadata.authSettings,
|
||||
useAuthCache: true,
|
||||
);
|
||||
|
||||
@@ -25,7 +25,7 @@ final selectedContainerDataProvider =
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef SelectedContainerDataRef = AutoDisposeStreamProviderRef<ContainerData?>;
|
||||
String _$selectedContainerHash() => r'736a60b8f19273d3bdc25d1717e3a613384e59a6';
|
||||
String _$selectedContainerHash() => r'34457f0adc45d437a9ab817387be4b1664cd2e7a';
|
||||
|
||||
/// See also [SelectedContainer].
|
||||
@ProviderFor(SelectedContainer)
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:fast_equatable/fast_equatable.dart';
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:riverpod/riverpod.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:synchronized/synchronized.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart';
|
||||
import 'package:weblibre/utils/lru_cache.dart';
|
||||
|
||||
part 'container_topic.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class ContainerTopicRepository extends _$ContainerTopicRepository {
|
||||
final _service = GeckoMlService();
|
||||
|
||||
final _lock = Lock();
|
||||
|
||||
final _cache = LRUCache<Set<String>, String>(
|
||||
50,
|
||||
equals: (a, b) {
|
||||
return const DeepCollectionEquality.unordered().equals(a, b);
|
||||
},
|
||||
hashCode: (key) {
|
||||
return const DeepCollectionEquality.unordered().hash(key);
|
||||
},
|
||||
);
|
||||
|
||||
Future<String?> getContainerTopic(Set<String> titles) async {
|
||||
if (titles.isNotEmpty) {
|
||||
if (_cache.get(titles) case final String title) {
|
||||
return title;
|
||||
}
|
||||
|
||||
try {
|
||||
final title = await _lock.synchronized(() async {
|
||||
final title = await _service.getContainerTopic(titles);
|
||||
|
||||
return _cache.set(titles, title);
|
||||
}, timeout: const Duration(seconds: 120));
|
||||
|
||||
return title;
|
||||
} on TimeoutException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
void build() {}
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
Future<String?> containerTopic(Ref ref, String containerId) async {
|
||||
final titles = await ref.watch(
|
||||
containerTabsDataProvider(containerId).selectAsync(
|
||||
(tabData) =>
|
||||
EquatableValue(tabData.map((tab) => tab.title).nonNulls.toSet()),
|
||||
),
|
||||
);
|
||||
|
||||
final topic = await ref
|
||||
.read(containerTopicRepositoryProvider.notifier)
|
||||
.getContainerTopic(titles.value);
|
||||
|
||||
return topic;
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'container_topic.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$containerTopicHash() => r'aa3fd27f26bb94b6c9e794d8470537240b8d2713';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
/// See also [containerTopic].
|
||||
@ProviderFor(containerTopic)
|
||||
const containerTopicProvider = ContainerTopicFamily();
|
||||
|
||||
/// See also [containerTopic].
|
||||
class ContainerTopicFamily extends Family<AsyncValue<String?>> {
|
||||
/// See also [containerTopic].
|
||||
const ContainerTopicFamily();
|
||||
|
||||
/// See also [containerTopic].
|
||||
ContainerTopicProvider call(String containerId) {
|
||||
return ContainerTopicProvider(containerId);
|
||||
}
|
||||
|
||||
@override
|
||||
ContainerTopicProvider getProviderOverride(
|
||||
covariant ContainerTopicProvider provider,
|
||||
) {
|
||||
return call(provider.containerId);
|
||||
}
|
||||
|
||||
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'containerTopicProvider';
|
||||
}
|
||||
|
||||
/// See also [containerTopic].
|
||||
class ContainerTopicProvider extends FutureProvider<String?> {
|
||||
/// See also [containerTopic].
|
||||
ContainerTopicProvider(String containerId)
|
||||
: this._internal(
|
||||
(ref) => containerTopic(ref as ContainerTopicRef, containerId),
|
||||
from: containerTopicProvider,
|
||||
name: r'containerTopicProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$containerTopicHash,
|
||||
dependencies: ContainerTopicFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
ContainerTopicFamily._allTransitiveDependencies,
|
||||
containerId: containerId,
|
||||
);
|
||||
|
||||
ContainerTopicProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.containerId,
|
||||
}) : super.internal();
|
||||
|
||||
final String containerId;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
FutureOr<String?> Function(ContainerTopicRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: ContainerTopicProvider._internal(
|
||||
(ref) => create(ref as ContainerTopicRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
containerId: containerId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
FutureProviderElement<String?> createElement() {
|
||||
return _ContainerTopicProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is ContainerTopicProvider && other.containerId == containerId;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, containerId.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin ContainerTopicRef on FutureProviderRef<String?> {
|
||||
/// The parameter `containerId` of this provider.
|
||||
String get containerId;
|
||||
}
|
||||
|
||||
class _ContainerTopicProviderElement extends FutureProviderElement<String?>
|
||||
with ContainerTopicRef {
|
||||
_ContainerTopicProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String get containerId => (origin as ContainerTopicProvider).containerId;
|
||||
}
|
||||
|
||||
String _$containerTopicRepositoryHash() =>
|
||||
r'20ae14772821ac8a4ec0c16bc551e29098556189';
|
||||
|
||||
/// See also [ContainerTopicRepository].
|
||||
@ProviderFor(ContainerTopicRepository)
|
||||
final containerTopicRepositoryProvider =
|
||||
NotifierProvider<ContainerTopicRepository, void>.internal(
|
||||
ContainerTopicRepository.new,
|
||||
name: r'containerTopicRepositoryProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$containerTopicRepositoryHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$ContainerTopicRepository = Notifier<void>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/container_topic.dart';
|
||||
|
||||
part 'container_topic.g.dart';
|
||||
|
||||
@Riverpod()
|
||||
class ContainerTopicController extends _$ContainerTopicController {
|
||||
Future<String?> getContainerTopic(String containerId) async {
|
||||
state = const AsyncLoading();
|
||||
|
||||
final result = await AsyncValue.guard(() async {
|
||||
return await ref.read(containerTopicProvider(containerId).future);
|
||||
});
|
||||
state = result;
|
||||
|
||||
return result.valueOrNull;
|
||||
}
|
||||
|
||||
@override
|
||||
AsyncValue<void> build() {
|
||||
return const AsyncData(null);
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'container_topic.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$containerTopicControllerHash() =>
|
||||
r'229709202edecb21b20432f8e4d0d7aee293f623';
|
||||
|
||||
/// See also [ContainerTopicController].
|
||||
@ProviderFor(ContainerTopicController)
|
||||
final containerTopicControllerProvider =
|
||||
AutoDisposeNotifierProvider<
|
||||
ContainerTopicController,
|
||||
AsyncValue<void>
|
||||
>.internal(
|
||||
ContainerTopicController.new,
|
||||
name: r'containerTopicControllerProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$containerTopicControllerHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$ContainerTopicController = AutoDisposeNotifier<AsyncValue<void>>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
@@ -6,6 +6,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:weblibre/core/uuid.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/data/models/container_data.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/container.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/presentation/controllers/container_topic.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/color_picker_dialog.dart';
|
||||
import 'package:weblibre/features/user/domain/services/local_authentication.dart';
|
||||
import 'package:weblibre/presentation/icons/tor_icons.dart';
|
||||
@@ -59,6 +60,11 @@ class ContainerEditScreen extends HookConsumerWidget {
|
||||
text: initialContainer.name,
|
||||
);
|
||||
|
||||
final containerHasTabs = switch (initialContainer) {
|
||||
ContainerDataWithCount(:final tabCount?) when tabCount > 0 => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(switch (_mode) {
|
||||
@@ -89,8 +95,7 @@ class ContainerEditScreen extends HookConsumerWidget {
|
||||
.read(localAuthenticationServiceProvider.notifier)
|
||||
.authenticate(
|
||||
authKey: 'container_access::${container.id}',
|
||||
localizedReason:
|
||||
'Require authentication for container ${container.name ?? 'New Container'}',
|
||||
localizedReason: 'Require authentication for container',
|
||||
);
|
||||
|
||||
if (!authResult) {
|
||||
@@ -140,6 +145,38 @@ class ContainerEditScreen extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
label: const Text('Name'),
|
||||
suffixIcon:
|
||||
(_mode == _DialogMode.edit && containerHasTabs)
|
||||
? Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final isLoading = ref.watch(
|
||||
containerTopicControllerProvider.select(
|
||||
(value) => value.isLoading,
|
||||
),
|
||||
);
|
||||
|
||||
return IconButton(
|
||||
onPressed: isLoading
|
||||
? null
|
||||
: () async {
|
||||
final topic = await ref
|
||||
.read(
|
||||
containerTopicControllerProvider
|
||||
.notifier,
|
||||
)
|
||||
.getContainerTopic(
|
||||
initialContainer.id,
|
||||
);
|
||||
|
||||
if (topic != null) {
|
||||
textController.text = topic;
|
||||
}
|
||||
},
|
||||
icon: const Icon(MdiIcons.creation),
|
||||
);
|
||||
},
|
||||
)
|
||||
: null,
|
||||
),
|
||||
controller: textController,
|
||||
),
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:weblibre/data/models/drag_data.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/data/models/container_data.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_title.dart';
|
||||
import 'package:weblibre/presentation/widgets/selectable_chips.dart';
|
||||
|
||||
class ContainerChips extends HookConsumerWidget {
|
||||
@@ -75,7 +76,7 @@ class ContainerChips extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
itemLabel: (container) =>
|
||||
Text(container.name ?? 'New Container'),
|
||||
ContainerTitle(container: container),
|
||||
itemBadgeCount: (container) => container.tabCount,
|
||||
itemWrap: (child, container) {
|
||||
return HookBuilder(
|
||||
@@ -169,6 +170,7 @@ class ContainerChips extends HookConsumerWidget {
|
||||
),
|
||||
if (displayMenu)
|
||||
IconButton(
|
||||
visualDensity: VisualDensity.compact,
|
||||
onPressed: () async {
|
||||
await ContainerListRoute().push(context);
|
||||
},
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/data/models/container_data.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_title.dart';
|
||||
|
||||
class ContainerListTile extends HookWidget {
|
||||
final ContainerData container;
|
||||
@@ -22,7 +23,7 @@ class ContainerListTile extends HookWidget {
|
||||
child: ListTile(
|
||||
selected: isSelected,
|
||||
leading: CircleAvatar(backgroundColor: container.color),
|
||||
title: Text(container.name ?? 'New Container'),
|
||||
title: ContainerTitle(container: container),
|
||||
onTap: onTap,
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
),
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
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:nullability/nullability.dart';
|
||||
import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:weblibre/core/logger.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/data/models/container_data.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/container_topic.dart';
|
||||
|
||||
class ContainerTitle extends HookConsumerWidget {
|
||||
final ContainerData container;
|
||||
|
||||
const ContainerTitle({super.key, required this.container});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
if (container.name.isNotEmpty) {
|
||||
return Text(container.name!);
|
||||
}
|
||||
|
||||
final topicAsync = ref.watch(containerTopicProvider(container.id));
|
||||
|
||||
return topicAsync.when(
|
||||
skipLoadingOnReload: true,
|
||||
data: (data) =>
|
||||
data.mapNotNull(
|
||||
(name) => RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(text: name),
|
||||
const WidgetSpan(child: SizedBox(width: 4)),
|
||||
const WidgetSpan(child: Icon(MdiIcons.creation, size: 16)),
|
||||
],
|
||||
),
|
||||
),
|
||||
) ??
|
||||
const Text('New Container'),
|
||||
error: (error, stackTrace) {
|
||||
logger.e(
|
||||
'Could not determine container name ${container.id}',
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
|
||||
return const Text('New Container');
|
||||
},
|
||||
loading: () => const Skeletonizer(child: Text('container')),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user