import 'dart:async'; import 'package:flutter/material.dart'; import '../di/injector.dart'; import '../services/unread_service.dart'; /// Wraps [child] with a small live unread-count badge. It listens to the /// app-wide [UnreadService] and rebuilds whenever a count changes: on a new /// message, or when a chat is opened (marked read). Shows the total across all /// conversations, or — when [peer] is set — just that peer's count. /// /// When no unread tracker is available (widget tests, inventory-only builds) or /// the count is zero, it renders [child] unadorned. Positioning is via Flutter's /// [Badge], which is directional (top-`end`), so it's correct under RTL. class UnreadBadge extends StatefulWidget { const UnreadBadge({ required this.child, this.peer, this.service, super.key, }); final Widget child; /// A specific conversation's count; null means the app-wide total. final String? peer; /// Overrides the [UnreadService] lookup (for tests). Falls back to `getIt`. final UnreadService? service; @override State createState() => _UnreadBadgeState(); } class _UnreadBadgeState extends State { UnreadService? _service; StreamSubscription? _sub; int _count = 0; @override void initState() { super.initState(); _service = widget.service ?? (getIt.isRegistered() ? getIt() : null); final service = _service; if (service != null) { _refresh(); _sub = service.changes.listen((_) => _refresh()); } } @override void didUpdateWidget(UnreadBadge old) { super.didUpdateWidget(old); // A recycled row may now point at a different peer. if (old.peer != widget.peer) _refresh(); } Future _refresh() async { final service = _service; if (service == null) return; final peer = widget.peer; final count = peer == null ? await service.totalUnreadCount() : await service.unreadCount(peer); if (mounted) setState(() => _count = count); } @override void dispose() { _sub?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return Badge( isLabelVisible: _count > 0, label: Text('$_count'), backgroundColor: Theme.of(context).colorScheme.error, child: widget.child, ); } }