feat: UI-Umbau - weiches Dunkel, Schriftgroessen-Regler, Sprechblasen umschaltbar, Einstellungen als Vollbild

Bernds Entscheidungen 2026-10-07:
- theme.dart: ThemeVariant (Dunkel = neues weiches Dunkelgrau als Standard,
  Schwarz = bisheriges Fast-Schwarz, Hell) mit PyramidPalette; Nebentexte
  kontrastreicher. Alte Einstellung theme_dark wird uebernommen
  (dunkel -> weiches Dunkel). Fest verdrahtete Dunkelfarben im Profil-Popup
  und GIF-Picker folgen jetzt dem Farbmodus.
- appearance.dart: Schriftgroesse = Pyramid-Regler x Systemeinstellung
  (Handy-Standard 115 %, PC 100 %), MessageStyle Automatisch/Sprechblasen/
  Liste, gemeinsame isMobileLayout-Regel.
- message_bubbles.dart: Sprechblasen-Darstellung (eigene rechts in
  Akzentfarbe, Gruppen mit Name + Avatar, Bilder ohne Blase in voller Groesse);
  Listen-Darstellung unveraendert, Weiche in MessageGroup.
- Formatierte Nachrichten (u. a. Antworten) nutzten RichText ohne
  Schriftskalierung -> erschienen kleiner; jetzt Text.rich.
- Einstellungen auf dem Handy als ganze Seite, Schalter unter dem Text.
- UI-Durchlauf um Liste/Hell/Gruppe/Einstellungen erweitert; Tests fuer
  Theme-Varianten, Uebernahme alter Werte, Schriftfaktor, Darstellung.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Bernd Steckmeister
2026-10-07 17:16:07 +02:00
co-authored by Claude Opus 5.5
parent a1d64ec813
commit c5f10901e6
17 changed files with 973 additions and 102 deletions
+39 -5
View File
@@ -2,6 +2,8 @@ import 'dart:convert';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:pyramid/core/appearance.dart';
import 'package:pyramid/core/theme.dart';
// ── Generic SharedPreferences-backed bool notifier ──────────────────────────
@@ -143,26 +145,58 @@ class VoicePrefs {
// ── Theme persistence helpers ────────────────────────────────────────────────
Future<void> saveThemePrefs({
bool? isDark,
ThemeVariant? variant,
int? accentIdx,
double? radius,
double? motion,
double? textScale,
bool resetTextScale = false,
MessageStyle? messageStyle,
}) async {
final p = await SharedPreferences.getInstance();
if (isDark != null) await p.setBool('theme_dark', isDark);
if (variant != null) {
await p.setString('theme_variant', variant.name);
// Altes Feld mitpflegen (falls jemand auf eine ältere Version zurückgeht).
await p.setBool('theme_dark', variant.isDark);
}
if (accentIdx != null) await p.setInt('theme_accent', accentIdx);
if (radius != null) await p.setDouble('theme_radius', radius);
if (motion != null) await p.setDouble('theme_motion', motion);
if (resetTextScale) {
await p.remove('ui_text_scale');
} else if (textScale != null) {
await p.setDouble('ui_text_scale', textScale);
}
if (messageStyle != null) {
await p.setString('chat_message_style', messageStyle.name);
}
}
Future<({bool isDark, int accentIdx, double radius, double motion})>
loadThemePrefs() async {
Future<
({
ThemeVariant variant,
int accentIdx,
double radius,
double motion,
double? textScale,
MessageStyle messageStyle,
})> loadThemePrefs() async {
final p = await SharedPreferences.getInstance();
// Vor 2026-10-07 gab es nur hell/dunkel ('theme_dark'). Wer dunkel hatte,
// bekommt jetzt das neue „Weiche Dunkel“ (Bernds Entscheidung).
final storedVariant = p.getString('theme_variant');
final variant = storedVariant != null
? ThemeVariant.fromName(storedVariant)
: (p.getBool('theme_dark') ?? true)
? ThemeVariant.soft
: ThemeVariant.light;
return (
isDark: p.getBool('theme_dark') ?? true,
variant: variant,
accentIdx: p.getInt('theme_accent') ?? 0,
radius: p.getDouble('theme_radius') ?? 12.0,
motion: p.getDouble('theme_motion') ?? 1.0,
textScale: p.getDouble('ui_text_scale'),
messageStyle: MessageStyle.fromName(p.getString('chat_message_style')),
);
}