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:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/chat.dart'; import 'package:island/models/chat.dart';
import 'package:island/models/developer.dart'; import 'package:island/models/developer.dart';
import 'package:island/models/publisher.dart';
import 'package:island/models/relationship.dart'; import 'package:island/models/relationship.dart';
import 'package:island/models/account.dart'; import 'package:island/models/account.dart';
import 'package:island/pods/config.dart'; import 'package:island/pods/config.dart';
@@ -224,7 +225,13 @@ class _AccountProfileDetail extends StatelessWidget {
spacing: 6, spacing: 6,
children: [ children: [
Icon(Symbols.fingerprint, size: 17, fill: 1).padding(right: 2), Icon(Symbols.fingerprint, size: 17, fill: 1).padding(right: 2),
Text(data.id), Flexible(
child: Text(
data.id,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
], ],
), ),
onTap: () { 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 { class _AccountAction extends StatelessWidget {
final SnAccount data; final SnAccount data;
final AsyncValue<SnRelationship?> accountRelationship; final AsyncValue<SnRelationship?> accountRelationship;
@@ -335,6 +392,7 @@ class _AccountAction extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Card( return Card(
child: Column( child: Column(
spacing: 8,
children: [ children: [
Row( Row(
spacing: 8, spacing: 8,
@@ -427,6 +485,7 @@ class _AccountAction extends StatelessWidget {
color: Theme.of(context).colorScheme.onError, color: Theme.of(context).colorScheme.onError,
), ),
style: ButtonStyle( style: ButtonStyle(
visualDensity: VisualDensity.compact,
backgroundColor: WidgetStatePropertyAll( backgroundColor: WidgetStatePropertyAll(
Theme.of(context).colorScheme.error, 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 { class AccountProfileScreen extends HookConsumerWidget {
final String name; final String name;
const AccountProfileScreen({super.key, required this.name}); const AccountProfileScreen({super.key, required this.name});
@@ -625,245 +698,255 @@ class AccountProfileScreen extends HookConsumerWidget {
); );
return account.when( return account.when(
data: data: (data) {
(data) => AppScaffold( final accountPublishers = ref.watch(accountPublishersProvider(data.id));
isNoBackground: false, return AppScaffold(
appBar: isNoBackground: false,
isWideScreen(context) appBar:
? AppBar( isWideScreen(context)
foregroundColor: appbarColor.value, ? AppBar(
leading: PageBackButton( foregroundColor: appbarColor.value,
color: appbarColor.value, leading: PageBackButton(
shadows: [appbarShadow], color: appbarColor.value,
), shadows: [appbarShadow],
flexibleSpace: Stack( ),
children: [ flexibleSpace: Stack(
Positioned.fill(
child:
data.profile.background?.id != null
? CloudImageWidget(
file: data.profile.background,
)
: Container(
color:
Theme.of(
context,
).appBarTheme.backgroundColor,
),
),
FlexibleSpaceBar(
title: Text(
data.nick,
style: TextStyle(
color:
appbarColor.value ??
Theme.of(
context,
).appBarTheme.foregroundColor,
shadows: [appbarShadow],
),
),
),
],
),
)
: null,
body:
isWideScreen(context)
? Row(
children: [ children: [
Flexible( Positioned.fill(
child: CustomScrollView( child:
slivers: [ data.profile.background?.id != null
SliverToBoxAdapter( ? CloudImageWidget(
child: _AccountBasicInfo( file: data.profile.background,
data: data, )
uname: name, : Container(
accountDeveloper: accountDeveloper,
),
),
if (data.badges.isNotEmpty)
SliverToBoxAdapter(
child: Card(
child: BadgeList(
badges: data.badges,
).padding(horizontal: 26, vertical: 20),
).padding(left: 2, right: 4),
),
SliverToBoxAdapter(
child: Column(
spacing: 12,
children: [
LevelingProgressCard(
level: data.profile.level,
experience: data.profile.experience,
progress: data.profile.levelingProgress,
).padding(left: 2, right: 4),
if (data.profile.verification != null)
Card(
margin: EdgeInsets.zero,
child: VerificationStatusCard(
mark: data.profile.verification!,
),
),
],
).padding(horizontal: 4, top: 8),
),
SliverToBoxAdapter(
child: _AccountProfileBio(
data: data,
).padding(top: 4),
),
if (data.profile.links.isNotEmpty)
SliverToBoxAdapter(
child: _AccountProfileLinks(data: data),
),
SliverToBoxAdapter(
child: _AccountProfileDetail(data: data),
),
],
),
),
Flexible(
child: CustomScrollView(
slivers: [
SliverGap(24),
if (user.value != null && !isCurrentUser)
SliverToBoxAdapter(
child: _AccountAction(
data: data,
accountRelationship: accountRelationship,
accountChat: accountChat,
relationshipAction: relationshipAction,
blockAction: blockAction,
directMessageAction: directMessageAction,
),
),
SliverToBoxAdapter(
child: Card(
child: FortuneGraphWidget(
events: accountEvents,
eventCalanderUser: data.name,
margin: EdgeInsets.zero,
),
),
),
],
),
),
],
).padding(horizontal: 24)
: CustomScrollView(
slivers: [
SliverAppBar(
foregroundColor: appbarColor.value,
expandedHeight: 180,
pinned: true,
leading: PageBackButton(
color: appbarColor.value,
shadows: [appbarShadow],
),
flexibleSpace: Stack(
children: [
Positioned.fill(
child:
data.profile.background?.id != null
? CloudImageWidget(
file: data.profile.background,
)
: Container(
color:
Theme.of(
context,
).appBarTheme.backgroundColor,
),
),
FlexibleSpaceBar(
title: Text(
data.nick,
style: TextStyle(
color: color:
appbarColor.value ??
Theme.of( Theme.of(
context, context,
).appBarTheme.foregroundColor, ).appBarTheme.backgroundColor,
shadows: [appbarShadow],
), ),
),
),
],
),
), ),
SliverToBoxAdapter( FlexibleSpaceBar(
child: _AccountBasicInfo( title: Text(
data: data, data.nick,
uname: name, style: TextStyle(
accountDeveloper: accountDeveloper, color:
), appbarColor.value ??
), Theme.of(context).appBarTheme.foregroundColor,
if (data.badges.isNotEmpty) shadows: [appbarShadow],
SliverToBoxAdapter(
child: Card(
child: BadgeList(
badges: data.badges,
).padding(horizontal: 26, vertical: 20),
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: Column(
children: [
LevelingProgressCard(
level: data.profile.level,
experience: data.profile.experience,
progress: data.profile.levelingProgress,
).padding(top: 8, horizontal: 8, bottom: 4),
if (data.profile.verification != null)
Card(
child: VerificationStatusCard(
mark: data.profile.verification!,
),
).padding(horizontal: 4),
],
),
),
SliverToBoxAdapter(
child: _AccountProfileBio(
data: data,
).padding(horizontal: 4),
),
if (data.profile.links.isNotEmpty)
SliverToBoxAdapter(
child: _AccountProfileLinks(
data: data,
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: _AccountProfileDetail(
data: data,
).padding(horizontal: 4),
),
if (user.value != null && !isCurrentUser)
SliverToBoxAdapter(
child: _AccountAction(
data: data,
accountRelationship: accountRelationship,
accountChat: accountChat,
relationshipAction: relationshipAction,
blockAction: blockAction,
directMessageAction: directMessageAction,
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: Card(
child: FortuneGraphWidget(
events: accountEvents,
eventCalanderUser: data.name,
), ),
).padding(horizontal: 4), ),
), ),
], ],
), ),
), )
: null,
body:
isWideScreen(context)
? Row(
children: [
Flexible(
child: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: _AccountBasicInfo(
data: data,
uname: name,
accountDeveloper: accountDeveloper,
),
),
if (data.badges.isNotEmpty)
SliverToBoxAdapter(
child: Card(
child: BadgeList(
badges: data.badges,
).padding(horizontal: 26, vertical: 20),
).padding(left: 2, right: 4),
),
SliverToBoxAdapter(
child: Column(
spacing: 12,
children: [
LevelingProgressCard(
level: data.profile.level,
experience: data.profile.experience,
progress: data.profile.levelingProgress,
).padding(left: 2, right: 4),
if (data.profile.verification != null)
Card(
margin: EdgeInsets.zero,
child: VerificationStatusCard(
mark: data.profile.verification!,
),
),
],
).padding(horizontal: 4, top: 8),
),
SliverToBoxAdapter(
child: _AccountProfileBio(
data: data,
).padding(top: 4),
),
if (data.profile.links.isNotEmpty)
SliverToBoxAdapter(
child: _AccountProfileLinks(data: data),
),
SliverToBoxAdapter(
child: _AccountProfileDetail(data: data),
),
],
),
),
Flexible(
child: CustomScrollView(
slivers: [
SliverGap(24),
SliverToBoxAdapter(
child: _AccountPublisherList(
publishers: accountPublishers.value ?? [],
),
),
if (user.value != null && !isCurrentUser)
SliverToBoxAdapter(
child: _AccountAction(
data: data,
accountRelationship: accountRelationship,
accountChat: accountChat,
relationshipAction: relationshipAction,
blockAction: blockAction,
directMessageAction: directMessageAction,
),
),
SliverToBoxAdapter(
child: Card(
child: FortuneGraphWidget(
events: accountEvents,
eventCalanderUser: data.name,
margin: EdgeInsets.zero,
),
),
),
],
),
),
],
).padding(horizontal: 24)
: CustomScrollView(
slivers: [
SliverAppBar(
foregroundColor: appbarColor.value,
expandedHeight: 180,
pinned: true,
leading: PageBackButton(
color: appbarColor.value,
shadows: [appbarShadow],
),
flexibleSpace: Stack(
children: [
Positioned.fill(
child:
data.profile.background?.id != null
? CloudImageWidget(
file: data.profile.background,
)
: Container(
color:
Theme.of(
context,
).appBarTheme.backgroundColor,
),
),
FlexibleSpaceBar(
title: Text(
data.nick,
style: TextStyle(
color:
appbarColor.value ??
Theme.of(
context,
).appBarTheme.foregroundColor,
shadows: [appbarShadow],
),
),
),
],
),
),
SliverToBoxAdapter(
child: _AccountBasicInfo(
data: data,
uname: name,
accountDeveloper: accountDeveloper,
),
),
if (data.badges.isNotEmpty)
SliverToBoxAdapter(
child: Card(
child: BadgeList(
badges: data.badges,
).padding(horizontal: 26, vertical: 20),
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: Column(
children: [
LevelingProgressCard(
level: data.profile.level,
experience: data.profile.experience,
progress: data.profile.levelingProgress,
).padding(top: 8, horizontal: 8, bottom: 4),
if (data.profile.verification != null)
Card(
child: VerificationStatusCard(
mark: data.profile.verification!,
),
).padding(horizontal: 4),
],
),
),
SliverToBoxAdapter(
child: _AccountProfileBio(
data: data,
).padding(horizontal: 4),
),
if (data.profile.links.isNotEmpty)
SliverToBoxAdapter(
child: _AccountProfileLinks(
data: data,
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: _AccountPublisherList(
publishers: accountPublishers.value ?? [],
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: _AccountProfileDetail(
data: data,
).padding(horizontal: 4),
),
if (user.value != null && !isCurrentUser)
SliverToBoxAdapter(
child: _AccountAction(
data: data,
accountRelationship: accountRelationship,
accountChat: accountChat,
relationshipAction: relationshipAction,
blockAction: blockAction,
directMessageAction: directMessageAction,
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: Card(
child: FortuneGraphWidget(
events: accountEvents,
eventCalanderUser: data.name,
),
).padding(horizontal: 4),
),
],
),
);
},
error: error:
(error, stackTrace) => AppScaffold( (error, stackTrace) => AppScaffold(
appBar: AppBar(leading: const PageBackButton()), appBar: AppBar(leading: const PageBackButton()),

View File

@@ -762,5 +762,127 @@ class _AccountBotDeveloperProviderElement
String get uname => (origin as AccountBotDeveloperProvider).uname; 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: 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 // 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: () { onTap: () {
Navigator.pop(context, true);
if (data.account?.name != null) { if (data.account?.name != null) {
Navigator.pop(context, true);
context.pushNamed( context.pushNamed(
'accountProfile', 'accountProfile',
pathParameters: {'name': data.account!.name}, pathParameters: {'name': data.account!.name},