Files
buzz/mobile/lib/features/pulse/agent_activity_card.dart
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

180 lines
6.4 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart';
import '../../shared/l10n/l10n.dart';
import '../../shared/theme/theme.dart';
import '../../shared/widgets/avatar_image.dart';
import '../profile/user_cache_provider.dart';
import 'note_card.dart';
import 'pulse_models.dart';
class AgentActivityCard extends HookConsumerWidget {
final AgentNoteGroup group;
final Map<String, PulseReactionState> reactions;
final VoidCallback? onReactionChanged;
const AgentActivityCard({
super.key,
required this.group,
required this.reactions,
this.onReactionChanged,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final expanded = useState(group.notes.length == 1);
final profile =
ref.watch(userCacheProvider.select((cache) => cache[group.pubkey])) ??
ref.read(userCacheProvider.notifier).get(group.pubkey);
final name = profile?.label ?? _shortPubkey(group.pubkey);
return Column(
children: [
InkWell(
onTap: group.notes.length > 1
? () => expanded.value = !expanded.value
: null,
borderRadius: BorderRadius.circular(Radii.md),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: Grid.twelve),
child: Row(
children: [
Stack(
children: [
AvatarImage(
imageUrl: profile?.avatarUrl,
radius: 18,
backgroundColor: context.colors.primaryContainer,
fallback: const Icon(LucideIcons.bot, size: 18),
),
Positioned(
right: 0,
bottom: 0,
child: Container(
width: 10,
height: 10,
decoration: BoxDecoration(
color: context.appColors.success,
shape: BoxShape.circle,
border: Border.all(
color: context.colors.surface,
width: 1.5,
),
),
),
),
],
),
const SizedBox(width: Grid.xs),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Flexible(
child: Text(
name,
overflow: TextOverflow.ellipsis,
style: context.textTheme.labelLarge?.copyWith(
fontWeight: FontWeight.w700,
),
),
),
const SizedBox(width: Grid.half),
Container(
padding: const EdgeInsets.symmetric(
horizontal: Grid.half,
vertical: 2,
),
decoration: BoxDecoration(
color: context.colors.primary.withValues(
alpha: 0.12,
),
borderRadius: BorderRadius.circular(Radii.sm),
),
child: Text(
context.l10n.pulseBot,
style: context.textTheme.labelSmall?.copyWith(
color: context.colors.primary,
fontWeight: FontWeight.w800,
fontSize: 10,
),
),
),
],
),
Text(
'${context.l10n.pulseUpdates(group.notes.length)} · '
'${formatPulseRelativeTime(group.latestAt, l10n: context.l10n)}',
style: context.textTheme.labelSmall?.copyWith(
color: context.colors.onSurfaceVariant,
),
),
],
),
),
if (group.notes.length > 1)
Icon(
expanded.value
? LucideIcons.chevronUp
: LucideIcons.chevronDown,
size: 18,
color: context.colors.onSurfaceVariant,
),
],
),
),
),
if (expanded.value)
Padding(
padding: const EdgeInsets.only(left: Grid.xl),
child: Column(
children: [
for (final note in group.notes) ...[
NoteCard(
note: note,
reaction:
reactions[note.id] ??
const PulseReactionState(
count: 0,
reactedByCurrentUser: false,
),
isAgent: true,
onReactionChanged: onReactionChanged,
),
if (note != group.notes.last)
Divider(
height: 1,
thickness: 1,
color: context.colors.outlineVariant.withValues(
alpha: 0.4,
),
),
],
],
),
)
else
Padding(
padding: const EdgeInsets.only(left: Grid.xl, bottom: Grid.xxs),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
group.notes.first.content,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: context.textTheme.bodyMedium,
),
),
),
],
);
}
}
String _shortPubkey(String pubkey) =>
pubkey.length <= 8 ? pubkey : '${pubkey.substring(0, 8)}';