Publisher list on account

This commit is contained in:
2025-09-07 01:02:40 +08:00
parent 187c2ea43e
commit 28fda3d0c7
3 changed files with 436 additions and 231 deletions

View File

@@ -9,6 +9,7 @@ import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/chat.dart';
import 'package:island/models/developer.dart';
import 'package:island/models/publisher.dart';
import 'package:island/models/relationship.dart';
import 'package:island/models/account.dart';
import 'package:island/pods/config.dart';
@@ -224,7 +225,13 @@ class _AccountProfileDetail extends StatelessWidget {
spacing: 6,
children: [
Icon(Symbols.fingerprint, size: 17, fill: 1).padding(right: 2),
Text(data.id),
Flexible(
child: Text(
data.id,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
onTap: () {
@@ -314,6 +321,56 @@ class _AccountProfileLinks extends StatelessWidget {
}
}
class _AccountPublisherList extends StatelessWidget {
final List<SnPublisher> publishers;
const _AccountPublisherList({required this.publishers});
@override
Widget build(BuildContext context) {
if (publishers.isEmpty) return const SizedBox.shrink();
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'publishers',
).tr().bold().padding(horizontal: 24, top: 12, bottom: 4),
for (final publisher in publishers)
ListTile(
title: Text(publisher.nick),
subtitle:
publisher.bio.isNotEmpty
? Text(
publisher.bio,
maxLines: 3,
overflow: TextOverflow.ellipsis,
)
: null,
leading: ProfilePictureWidget(
file: publisher.picture,
borderRadius: publisher.type == 1 ? 8 : null,
),
isThreeLine: true,
contentPadding: EdgeInsets.symmetric(horizontal: 24),
trailing: const Icon(Symbols.chevron_right),
shape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(Radius.circular(8)),
),
onTap: () {
Navigator.pop(context, true);
context.pushNamed(
'publisherProfile',
pathParameters: {'name': publisher.name},
);
},
),
],
),
);
}
}
class _AccountAction extends StatelessWidget {
final SnAccount data;
final AsyncValue<SnRelationship?> accountRelationship;
@@ -335,6 +392,7 @@ class _AccountAction extends StatelessWidget {
Widget build(BuildContext context) {
return Card(
child: Column(
spacing: 8,
children: [
Row(
spacing: 8,
@@ -427,6 +485,7 @@ class _AccountAction extends StatelessWidget {
color: Theme.of(context).colorScheme.onError,
),
style: ButtonStyle(
visualDensity: VisualDensity.compact,
backgroundColor: WidgetStatePropertyAll(
Theme.of(context).colorScheme.error,
),
@@ -533,6 +592,20 @@ Future<SnDeveloper?> accountBotDeveloper(Ref ref, String uname) async {
}
}
@riverpod
Future<List<SnPublisher>> accountPublishers(Ref ref, String id) async {
final apiClient = ref.watch(apiClientProvider);
try {
final resp = await apiClient.get('/sphere/publishers/of/$id');
return resp.data
.map((e) => SnPublisher.fromJson(e))
.cast<SnPublisher>()
.toList();
} catch (err) {
return [];
}
}
class AccountProfileScreen extends HookConsumerWidget {
final String name;
const AccountProfileScreen({super.key, required this.name});
@@ -625,8 +698,9 @@ class AccountProfileScreen extends HookConsumerWidget {
);
return account.when(
data:
(data) => AppScaffold(
data: (data) {
final accountPublishers = ref.watch(accountPublishersProvider(data.id));
return AppScaffold(
isNoBackground: false,
appBar:
isWideScreen(context)
@@ -657,9 +731,7 @@ class AccountProfileScreen extends HookConsumerWidget {
style: TextStyle(
color:
appbarColor.value ??
Theme.of(
context,
).appBarTheme.foregroundColor,
Theme.of(context).appBarTheme.foregroundColor,
shadows: [appbarShadow],
),
),
@@ -728,6 +800,11 @@ class AccountProfileScreen extends HookConsumerWidget {
child: CustomScrollView(
slivers: [
SliverGap(24),
SliverToBoxAdapter(
child: _AccountPublisherList(
publishers: accountPublishers.value ?? [],
),
),
if (user.value != null && !isCurrentUser)
SliverToBoxAdapter(
child: _AccountAction(
@@ -837,6 +914,11 @@ class AccountProfileScreen extends HookConsumerWidget {
data: data,
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: _AccountPublisherList(
publishers: accountPublishers.value ?? [],
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: _AccountProfileDetail(
data: data,
@@ -863,7 +945,8 @@ class AccountProfileScreen extends HookConsumerWidget {
),
],
),
),
);
},
error:
(error, stackTrace) => AppScaffold(
appBar: AppBar(leading: const PageBackButton()),

View File

@@ -762,5 +762,127 @@ class _AccountBotDeveloperProviderElement
String get uname => (origin as AccountBotDeveloperProvider).uname;
}
String _$accountPublishersHash() => r'25f5695b4a5154163d77f1769876d826bf736609';
/// See also [accountPublishers].
@ProviderFor(accountPublishers)
const accountPublishersProvider = AccountPublishersFamily();
/// See also [accountPublishers].
class AccountPublishersFamily extends Family<AsyncValue<List<SnPublisher>>> {
/// See also [accountPublishers].
const AccountPublishersFamily();
/// See also [accountPublishers].
AccountPublishersProvider call(String id) {
return AccountPublishersProvider(id);
}
@override
AccountPublishersProvider getProviderOverride(
covariant AccountPublishersProvider provider,
) {
return call(provider.id);
}
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'accountPublishersProvider';
}
/// See also [accountPublishers].
class AccountPublishersProvider
extends AutoDisposeFutureProvider<List<SnPublisher>> {
/// See also [accountPublishers].
AccountPublishersProvider(String id)
: this._internal(
(ref) => accountPublishers(ref as AccountPublishersRef, id),
from: accountPublishersProvider,
name: r'accountPublishersProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$accountPublishersHash,
dependencies: AccountPublishersFamily._dependencies,
allTransitiveDependencies:
AccountPublishersFamily._allTransitiveDependencies,
id: id,
);
AccountPublishersProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.id,
}) : super.internal();
final String id;
@override
Override overrideWith(
FutureOr<List<SnPublisher>> Function(AccountPublishersRef provider) create,
) {
return ProviderOverride(
origin: this,
override: AccountPublishersProvider._internal(
(ref) => create(ref as AccountPublishersRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
id: id,
),
);
}
@override
AutoDisposeFutureProviderElement<List<SnPublisher>> createElement() {
return _AccountPublishersProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is AccountPublishersProvider && other.id == id;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, id.hashCode);
return _SystemHash.finish(hash);
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
mixin AccountPublishersRef on AutoDisposeFutureProviderRef<List<SnPublisher>> {
/// The parameter `id` of this provider.
String get id;
}
class _AccountPublishersProviderElement
extends AutoDisposeFutureProviderElement<List<SnPublisher>>
with AccountPublishersRef {
_AccountPublishersProviderElement(super.provider);
@override
String get id => (origin as AccountPublishersProvider).id;
}
// 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

View File

@@ -66,8 +66,8 @@ class _PublisherBasisWidget extends StatelessWidget {
),
),
onTap: () {
Navigator.pop(context, true);
if (data.account?.name != null) {
Navigator.pop(context, true);
context.pushNamed(
'accountProfile',
pathParameters: {'name': data.account!.name},