Files
cls 9dfa06ffee
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
feat: import Chinese-localized Buzz source snapshot
Signed-off-by: cls_宁波本机 <908705107@qq.com>
2026-08-13 18:34:25 +08:00

201 lines
5.9 KiB
Dart

part of '../channel_detail_page.dart';
double _scaledTextHeight(BuildContext context, TextStyle style) {
final scaledFontSize = MediaQuery.textScalerOf(
context,
).scale(style.fontSize ?? 0);
return scaledFontSize * (style.height ?? 1);
}
double _dmAppBarTitleContentHeight(BuildContext context) {
const titleStyle = channelTitleTextStyle;
final presenceStyle = context.textTheme.bodySmall;
if (presenceStyle == null) {
return 30;
}
final textHeight =
_scaledTextHeight(context, titleStyle) +
_scaledTextHeight(context, presenceStyle);
return textHeight > 30 ? textHeight : 30;
}
class _MembersButton extends ConsumerWidget {
final String channelId;
final Channel channel;
final String? currentPubkey;
const _MembersButton({
required this.channelId,
required this.channel,
required this.currentPubkey,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final hasWorkingBot = ref
.watch(workingBotPubkeysProvider(channelId))
.isNotEmpty;
return IconButton(
color: context.colors.primary,
onPressed: () {
showBuzzModalBottomSheet<void>(
context: context,
isScrollControlled: true,
showDragHandle: true,
builder: (_) =>
MembersSheet(channel: channel, currentPubkey: currentPubkey),
);
},
tooltip: context.l10n.viewMembers,
icon: Stack(
clipBehavior: Clip.none,
children: [
const Icon(LucideIcons.users, size: 22),
if (hasWorkingBot)
Positioned(
top: -2,
right: -2,
child: Container(
width: 8,
height: 8,
decoration: BoxDecoration(
color: context.appColors.success,
shape: BoxShape.circle,
border: Border.all(color: context.colors.surface, width: 1.5),
),
),
),
],
),
);
}
}
class _DmAppBarTitle extends ConsumerWidget {
final Channel channel;
final String? currentPubkey;
const _DmAppBarTitle({required this.channel, required this.currentPubkey});
@override
Widget build(BuildContext context, WidgetRef ref) {
final profiles = ref.watch(userCacheProvider);
final presenceMap = ref.watch(presenceCacheProvider);
final normalizedCurrent = currentPubkey?.toLowerCase();
String? otherPubkey;
for (final pk in channel.participantPubkeys) {
if (pk.toLowerCase() != normalizedCurrent) {
otherPubkey = pk.toLowerCase();
break;
}
}
final profile = otherPubkey != null ? profiles[otherPubkey] : null;
if (otherPubkey != null) {
if (profile == null) {
ref.read(userCacheProvider.notifier).preload([otherPubkey]);
}
ref.read(presenceCacheProvider.notifier).track([otherPubkey]);
}
final avatarUrl = profile?.avatarUrl;
final initial =
profile?.initial ??
(channel.participants.isNotEmpty
? channel.participants.first[0].toUpperCase()
: '?');
final presence = otherPubkey != null
? (presenceMap[otherPubkey] ?? 'offline')
: 'offline';
final presenceLabel = switch (presence) {
'online' => context.l10n.online,
'away' => context.l10n.away,
_ => context.l10n.offline,
};
return Row(
children: [
SizedBox(
width: 30,
height: 30,
child: Stack(
clipBehavior: Clip.none,
children: [
AvatarImage(
imageUrl: avatarUrl,
radius: 14,
backgroundColor: context.colors.primaryContainer,
fallback: Text(
initial,
style: context.textTheme.labelSmall?.copyWith(
color: context.colors.onPrimaryContainer,
fontWeight: FontWeight.w600,
),
),
),
Positioned(
right: -1,
bottom: -1,
child: Container(
width: 10,
height: 10,
decoration: BoxDecoration(
color: switch (presence) {
'online' => context.appColors.success,
'away' => context.appColors.warning,
_ => context.colors.outline,
},
shape: BoxShape.circle,
border: Border.all(
color: context.colors.surface,
width: 1.5,
),
),
),
),
],
),
),
const SizedBox(width: Grid.xxs),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: Text(
resolveDmChannelDisplayLabel(
channel,
currentPubkey: currentPubkey,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: channelTitleTextStyle,
),
),
if (channel.isEphemeral) ...[
const SizedBox(width: Grid.quarter),
_HeaderEphemeralBadge(channel: channel),
],
],
),
Text(
presenceLabel,
style: context.textTheme.bodySmall?.copyWith(
color: context.colors.onSurfaceVariant,
),
),
],
),
),
],
);
}
}