fix(ui): UX-Audit – Sackgassen, tote Knöpfe, englische Reste; Screenshot-Tour
Bernds Wunsch 2026-10-08: UI grundsätzlich prüfen (Navigation, Sackgassen, Anruf-Logik). Audit + Konzept in docs/UI_AUDIT.md, belegt mit neuer Screenshot-Tour integration_test/ui_audit_tour_test.dart (35 Zustände, Handy + PC, zwei Testkonten, Test-Space mit Sprachkanal). Sofort behoben: - S1/S2: Gegenseite legt auf / Anruf scheitert / Sprachkanal bricht ab → automatisch zurück zum Chat mit Hinweis (Fehler sichtbar statt still); leere Anrufansicht deutsch mit Zurück-Knopf (vorher englische Sackgasse ohne Zurück am Handy). - S4: toter „Threads“-Knopf entfernt. S5: Space betreten (PC) öffnet letzten bzw. ersten Textkanal. S6: keine doppelte Anrufsteuerung am PC. - Annehmen-Fenster mit Anrufer-Avatar und Anrufart; eigene Kachel mit eigenem Initial statt „D“; Mitgliederliste rund mit Profilbild und „(Du)“; Tastaturkürzel nur am PC; englische Texte in Anruf/Leerzuständen deutsch. - Tests: Fehlerempfänger des Testrahmens nach app.main() zurück (vorher verschwanden Fehlermeldungen), Lesebestätigungs-Test im Wegwerf-Raum statt in der DM, robustere Schritte; test.ps1 räumt liegengebliebene Test-Prozesse weg; gemeinsame Hilfen integration_test/support/. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
842dd61031
commit
87b472a373
@@ -49,7 +49,7 @@ class _MiniCallWidgetState extends ConsumerState<MiniCallWidget> {
|
||||
final call = widget.call;
|
||||
|
||||
final String displayName = isVoip
|
||||
? (call.currentCall?.room.getLocalizedDisplayname() ?? 'Unknown')
|
||||
? (call.currentCall?.room.getLocalizedDisplayname() ?? 'Unbekannt')
|
||||
: call.displayName;
|
||||
|
||||
final bool isConnecting = isVoip ? false : call.isConnecting;
|
||||
@@ -160,7 +160,7 @@ class _MiniCallWidgetState extends ConsumerState<MiniCallWidget> {
|
||||
const _LiveDot(),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
isConnecting ? 'CONNECTING...' : 'VOICE CONNECTED',
|
||||
isConnecting ? 'CONNECTING...' : (isVoip ? 'ANRUF LÄUFT' : (call.isVoiceChannel ? 'SPRACHKANAL' : 'GRUPPENANRUF')),
|
||||
style: TextStyle(
|
||||
color: pt.online,
|
||||
fontSize: 10,
|
||||
|
||||
@@ -14,7 +14,7 @@ class _BigAvatar extends StatelessWidget {
|
||||
gradient: LinearGradient(colors: [data.avatarColor, data.avatarColor.withAlpha(150)], begin: Alignment.topLeft, end: Alignment.bottomRight),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(child: Text(data.name.isNotEmpty ? data.name[0].toUpperCase() : '?', style: const TextStyle(color: Colors.white, fontSize: 40, fontWeight: FontWeight.bold))),
|
||||
child: Center(child: Text(data.initial, style: const TextStyle(color: Colors.white, fontSize: 40, fontWeight: FontWeight.bold))),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -34,7 +34,7 @@ class _SmallAvatar extends StatelessWidget {
|
||||
gradient: LinearGradient(colors: [data.avatarColor, data.avatarColor.withAlpha(150)], begin: Alignment.topLeft, end: Alignment.bottomRight),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(child: Text(data.name.isNotEmpty ? data.name[0].toUpperCase() : '?', style: const TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold))),
|
||||
child: Center(child: Text(data.initial, style: const TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold))),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -127,14 +127,12 @@ class _NoCall extends StatelessWidget {
|
||||
child: Row(
|
||||
children: [
|
||||
PyrIconBtn(
|
||||
icon: const Icon(Icons.menu_rounded),
|
||||
tooltip: 'Toggle sidebar',
|
||||
onPressed: () => ref.read(railCollapsedProvider.notifier).update((s) => !s),
|
||||
icon: const Icon(Icons.arrow_back_rounded),
|
||||
tooltip: 'Zurück',
|
||||
onPressed: () => ref.read(viewModeProvider.notifier).state = ViewMode.chat,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Icon(Icons.headphones_rounded, size: 16, color: pt.fgMuted),
|
||||
const SizedBox(width: 8),
|
||||
Text('No active call', style: TextStyle(color: pt.fg, fontSize: 15, fontWeight: FontWeight.w600)),
|
||||
Text('Kein Anruf', style: TextStyle(color: pt.fg, fontSize: 15, fontWeight: FontWeight.w600)),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -143,9 +141,15 @@ class _NoCall extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('𐃏', style: TextStyle(fontSize: 48, color: pt.fgDim.withAlpha(100))),
|
||||
Icon(Icons.call_end_rounded, size: 48, color: pt.fgDim),
|
||||
const SizedBox(height: 12),
|
||||
Text('Join a voice room to start a call', style: TextStyle(color: pt.fgMuted, fontSize: 14)),
|
||||
Text('Gerade läuft kein Anruf.', style: TextStyle(color: pt.fgMuted, fontSize: 14)),
|
||||
const SizedBox(height: 16),
|
||||
FilledButton(
|
||||
onPressed: () => ref.read(viewModeProvider.notifier).state = ViewMode.chat,
|
||||
style: FilledButton.styleFrom(backgroundColor: pt.accent, foregroundColor: pt.accentFg),
|
||||
child: const Text('Zurück zum Chat'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -193,7 +193,7 @@ class _CallHeader extends StatelessWidget {
|
||||
const Spacer(),
|
||||
PyrIconBtn(
|
||||
icon: Icon(isGridView ? Icons.grid_view_rounded : Icons.featured_video_rounded, color: isGridView ? pt.accent : pt.fg),
|
||||
tooltip: isGridView ? 'Hero mode' : 'Grid mode',
|
||||
tooltip: isGridView ? 'Großansicht' : 'Kachelansicht',
|
||||
onPressed: onToggleView,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
|
||||
@@ -12,6 +12,13 @@ class _ParticipantData {
|
||||
final Color avatarColor;
|
||||
final dynamic originalParticipant;
|
||||
final double aspectRatio;
|
||||
/// Woraus der Anfangsbuchstabe im Avatar gebildet wird (Standard: [name]).
|
||||
final String? initialFrom;
|
||||
|
||||
String get initial {
|
||||
final src = (initialFrom ?? name).replaceFirst('@', '').trim();
|
||||
return src.isEmpty ? '?' : src.characters.first.toUpperCase();
|
||||
}
|
||||
|
||||
const _ParticipantData({
|
||||
required this.id,
|
||||
@@ -24,6 +31,7 @@ class _ParticipantData {
|
||||
this.avatarColor = Colors.grey,
|
||||
this.originalParticipant,
|
||||
this.aspectRatio = 16.0 / 9.0,
|
||||
this.initialFrom,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -148,7 +156,7 @@ class VoiceChannelView extends ConsumerWidget {
|
||||
final hasRemoteVideo = voip.remoteRenderer.srcObject != null && voip.remoteRenderer.srcObject!.getVideoTracks().isNotEmpty;
|
||||
participants.add(_ParticipantData(
|
||||
id: 'remote',
|
||||
name: voip.currentCall?.room.getLocalizedDisplayname() ?? 'Remote',
|
||||
name: voip.currentCall?.room.getLocalizedDisplayname() ?? 'Gegenseite',
|
||||
videoWidget: hasRemoteVideo ? rtc.RTCVideoView(voip.remoteRenderer, objectFit: rtc.RTCVideoViewObjectFit.RTCVideoViewObjectFitContain) : null,
|
||||
isMuted: false,
|
||||
isSpeaking: voip.isRemoteSpeaking,
|
||||
@@ -164,6 +172,7 @@ class VoiceChannelView extends ConsumerWidget {
|
||||
participants.add(_ParticipantData(
|
||||
id: 'local',
|
||||
name: 'Du',
|
||||
initialFrom: voip.currentCall?.room.client.userID?.split(':').first,
|
||||
videoWidget: hasLocalVideo ? rtc.RTCVideoView(voip.localRenderer, objectFit: rtc.RTCVideoViewObjectFit.RTCVideoViewObjectFitContain) : null,
|
||||
isMuted: voip.isMicMuted,
|
||||
isSpeaking: voip.isLocalSpeaking,
|
||||
|
||||
Reference in New Issue
Block a user