Files
pyramid/lib/features/rooms/panel/rooms_invite_item.dart
T
Bernd SteckmeisterandClaude Opus 5.5 c817de924a fix: Haken live, Einladung im Chat annehmen, Trenner verschwindet zuverlässig
Bernds Test mit der PC-Testinstanz:
- ✓✓ erschien erst nach erneutem Öffnen: eine Lesebestätigung ohne neue
  Nachricht zeichnete nichts neu (Raum-Update kommt im SDK vor der
  Bestätigung). Jetzt nach jedem Sync Fingerabdruck der Lesepositionen
  prüfen und bei Änderung neu zeichnen.
- Einladung: Chat zeigte leeren Verlauf, Annehmen ging nur in der Liste, und
  danach blieb der Chat leer bis zum App-Neustart. Jetzt Annehmen/Ablehnen
  direkt im Chat; Annehmen wartet auf den Beitritts-Sync, der Verlauf baut
  sich bei invite→join selbst neu auf.
- Trenner blieb stehen, wenn nach dem Öffnen/Zurückkommen nicht gescrollt
  wurde. Jetzt: neueste Nachrichten sichtbar (≤ halbe Bildschirmhöhe
  hochgescrollt) → nach 6 s weich ausblenden, auch ohne Scrollen.
- Live-Test mit beiden Testkonten (Gegenprobe: ohne Fix rot) in
  scripts/test.ps1 -Ui; Testlauf-Sperre erkennt nur noch eigene Testläufe.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 23:33:59 +02:00

114 lines
3.8 KiB
Dart

part of '../rooms_panel.dart';
class _InviteItem extends ConsumerStatefulWidget {
final Room room;
final PyramidTheme pt;
const _InviteItem({required this.room, required this.pt});
@override
ConsumerState<_InviteItem> createState() => _InviteItemState();
}
class _InviteItemState extends ConsumerState<_InviteItem> {
bool _accepting = false;
bool _declining = false;
Future<void> _accept() async {
setState(() => _accepting = true);
try {
await acceptInvite(ref, widget.room);
if (mounted) {
ref.read(activeRoomIdProvider.notifier).state = widget.room.id;
ref.read(viewModeProvider.notifier).state = ViewMode.chat;
}
} catch (_) {
if (mounted) setState(() => _accepting = false);
}
}
Future<void> _decline() async {
setState(() => _declining = true);
try {
await widget.room.leave();
} catch (_) {
if (mounted) setState(() => _declining = false);
}
}
@override
Widget build(BuildContext context) {
final pt = widget.pt;
final name = widget.room.getLocalizedDisplayname();
final isDm = widget.room.isDirectChat;
return Container(
margin: const EdgeInsets.symmetric(vertical: 1),
padding: const EdgeInsets.fromLTRB(10, 8, 10, 8),
decoration: BoxDecoration(
color: pt.accentSoft,
borderRadius: BorderRadius.circular(pt.rSm),
border: Border.all(color: pt.accent.withAlpha(50)),
),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Row(children: [
Icon(isDm ? Icons.person_rounded : Icons.tag_rounded,
size: 12, color: pt.accent),
const SizedBox(width: 6),
Expanded(
child: Text(name,
style: TextStyle(
color: pt.fg,
fontSize: 13,
fontWeight: FontWeight.w500),
overflow: TextOverflow.ellipsis),
),
]),
const SizedBox(height: 6),
Row(children: [
Expanded(
child: OutlinedButton(
style: OutlinedButton.styleFrom(
foregroundColor: pt.danger,
side: BorderSide(color: pt.danger.withAlpha(80)),
padding: const EdgeInsets.symmetric(vertical: 4),
minimumSize: Size.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6)),
),
onPressed: (_declining || _accepting) ? null : _decline,
child: _declining
? const SizedBox(
width: 12,
height: 12,
child: CircularProgressIndicator.adaptive(strokeWidth: 1.5))
: const Text('Ablehnen', style: TextStyle(fontSize: 12)),
),
),
const SizedBox(width: 6),
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: pt.accent,
foregroundColor: pt.accentFg,
elevation: 0,
padding: const EdgeInsets.symmetric(vertical: 4),
minimumSize: Size.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6)),
),
onPressed: (_accepting || _declining) ? null : _accept,
child: _accepting
? const SizedBox(
width: 12,
height: 12,
child: CircularProgressIndicator.adaptive(strokeWidth: 1.5))
: const Text('Annehmen', style: TextStyle(fontSize: 12)),
),
),
]),
]),
);
}
}