Verification mark

This commit is contained in:
2025-06-11 00:09:19 +08:00
parent 78f258dcea
commit 36b9026e9e
10 changed files with 377 additions and 45 deletions

View File

@ -0,0 +1,63 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:island/models/user.dart';
import 'package:material_symbols_icons/symbols.dart';
const kVerificationMarkColors = [
Colors.teal,
Colors.blue,
Colors.amber,
Colors.blueGrey,
Colors.lightBlue,
];
class AccountName extends StatelessWidget {
final SnAccount account;
final TextStyle? style;
const AccountName({super.key, required this.account, this.style});
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
spacing: 4,
children: [
Flexible(child: Text(account.nick, style: style)),
if (account.profile.verification != null)
VerificationMark(mark: account.profile.verification!),
],
);
}
}
class VerificationMark extends StatelessWidget {
final SnVerificationMark mark;
const VerificationMark({super.key, required this.mark});
@override
Widget build(BuildContext context) {
return Tooltip(
richMessage: TextSpan(
text: mark.title ?? 'No title',
children: [
TextSpan(text: '\n'),
TextSpan(
text: mark.description ?? 'descriptionNone'.tr(),
style: TextStyle(fontWeight: FontWeight.normal),
),
],
style: TextStyle(fontWeight: FontWeight.bold),
),
child: Icon(
mark.type == 4
? Symbols.play_circle
: mark.type == 0
? Symbols.build_circle
: Symbols.verified,
size: 16,
color: kVerificationMarkColors[mark.type],
fill: 1,
),
);
}
}

View File

@ -54,13 +54,15 @@ class CloudFileWidget extends ConsumerWidget {
}
class CloudImageWidget extends ConsumerWidget {
final String fileId;
final String? fileId;
final SnCloudFile? file;
final BoxFit fit;
final double aspectRatio;
final String? blurHash;
const CloudImageWidget({
super.key,
required this.fileId,
this.fileId,
this.file,
this.aspectRatio = 1,
this.fit = BoxFit.cover,
this.blurHash,
@ -68,11 +70,17 @@ class CloudImageWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
assert(fileId != null || file != null);
final serverUrl = ref.watch(serverUrlProvider);
final uri = '$serverUrl/files/$fileId';
final uri = '$serverUrl/files/${file?.id ?? fileId}';
return AspectRatio(
aspectRatio: aspectRatio,
child: UniversalImage(uri: uri, blurHash: blurHash),
child:
file != null
? CloudFileWidget(item: file!, fit: fit)
: UniversalImage(uri: uri, blurHash: blurHash, fit: fit),
);
}
@ -88,12 +96,14 @@ class CloudImageWidget extends ConsumerWidget {
class ProfilePictureWidget extends ConsumerWidget {
final String? fileId;
final SnCloudFile? file;
final double radius;
final IconData? fallbackIcon;
final Color? fallbackColor;
const ProfilePictureWidget({
super.key,
required this.fileId,
this.fileId,
this.file,
this.radius = 20,
this.fallbackIcon,
this.fallbackColor,
@ -101,8 +111,10 @@ class ProfilePictureWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
assert(fileId != null || file != null);
final serverUrl = ref.watch(serverUrlProvider);
final uri = '$serverUrl/files/$fileId';
final uri = '$serverUrl/files/${file?.id ?? fileId}';
return ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(radius)),
@ -119,6 +131,8 @@ class ProfilePictureWidget extends ConsumerWidget {
fallbackColor ??
Theme.of(context).colorScheme.onPrimaryContainer,
).center()
: file != null
? CloudFileWidget(item: file!, fit: BoxFit.cover)
: UniversalImage(uri: uri, fit: BoxFit.cover),
),
);

View File

@ -11,6 +11,7 @@ import 'package:island/pods/network.dart';
import 'package:island/pods/userinfo.dart';
import 'package:island/route.gr.dart';
import 'package:island/services/responsive.dart';
import 'package:island/widgets/account/account_name.dart';
import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/cloud_file_collection.dart';
@ -133,9 +134,7 @@ class PostItem extends HookConsumerWidget {
spacing: 12,
children: [
GestureDetector(
child: ProfilePictureWidget(
fileId: item.publisher.picture?.id,
),
child: ProfilePictureWidget(file: item.publisher.picture),
onTap: () {
context.router.push(
PublisherProfileRoute(name: item.publisher.name),
@ -147,7 +146,15 @@ class PostItem extends HookConsumerWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(item.publisher.nick).bold(),
Row(
children: [
Text(item.publisher.nick).bold(),
if (item.publisher.verification != null)
VerificationMark(
mark: item.publisher.verification!,
).padding(left: 4),
],
),
// Add visibility indicator if not public (visibility != 0)
if (item.visibility != 0)
Row(