Files
pyramid/lib/features/chat/view/chat_misc.dart
T
Bernd SteckmeisterandClaude Opus 5.5 223c9448f6 feat: schwebende Eingabeleiste - Chat laeuft darunter weiter (Milchglas), Flaeche faengt Beruehrungen ab
Bernds Wunsch 2026-10-07: Die Nachrichtenliste reicht jetzt bis ganz unten;
Tipp-Anzeige und Eingabefeld schweben darueber. Um das Feld herum ist die
Flaeche klar (Chat sichtbar), aber beruehrungsdicht - dort reagiert nur die
Eingabe. Hinter dem Feld selbst Milchglas (Unschaerfe + 78 % Flaeche), Rahmen
und Fokus-Ring aussen. Die Liste bekommt unten genau die gemessene Hoehe der
Leiste als Abstand (MeasureSize; waechst mit Antwort-Leiste/mehrzeiligem
Text), damit die neueste Nachricht ganz ueber die Leiste scrollt; der
Nach-unten-Knopf sitzt darueber.

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

154 lines
4.4 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
part of '../chat_view.dart';
class _DragOverlay extends StatefulWidget {
final PyramidTheme pt;
final bool active;
const _DragOverlay({required this.pt, required this.active});
@override
State<_DragOverlay> createState() => _DragOverlayState();
}
class _DragOverlayState extends State<_DragOverlay>
with SingleTickerProviderStateMixin {
// Sanftes Auf-und-ab des Icons, solange das Overlay aktiv ist.
late final AnimationController _bob = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 900),
);
@override
void initState() {
super.initState();
if (widget.active) _bob.repeat(reverse: true);
}
@override
void didUpdateWidget(_DragOverlay old) {
super.didUpdateWidget(old);
if (widget.active && !old.active) {
_bob.repeat(reverse: true);
} else if (!widget.active && old.active) {
_bob.stop();
}
}
@override
void dispose() {
_bob.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final pt = widget.pt;
return Container(
color: pt.bg0.withAlpha(200),
child: Center(
child: AnimatedScale(
scale: widget.active ? 1.0 : 0.88,
duration: const Duration(milliseconds: 220),
curve: Curves.easeOutBack,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 32),
decoration: BoxDecoration(
color: pt.bg2,
borderRadius: BorderRadius.circular(20),
border: Border.all(color: pt.accent, width: 2),
boxShadow: [
BoxShadow(
color: pt.accent.withAlpha(60),
blurRadius: 32,
spreadRadius: 4,
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
AnimatedBuilder(
animation: _bob,
builder: (_, child) => Transform.translate(
offset: Offset(
0, -7 * Curves.easeInOut.transform(_bob.value)),
child: child,
),
child:
Icon(Icons.upload_file_rounded, size: 56, color: pt.accent),
),
const SizedBox(height: 16),
Text(
'Datei hier ablegen',
style: TextStyle(
color: pt.fg,
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
Text(
'Loslassen zum Hochladen',
style: TextStyle(color: pt.fgMuted, fontSize: 14),
),
],
),
),
),
),
);
}
}
// Placeholder shown when no room is selected
class NoChatSelected extends StatelessWidget {
const NoChatSelected({super.key});
@override
Widget build(BuildContext context) {
final pt = PyramidTheme.of(context);
return Container(
color: pt.bg1,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.forum_outlined, size: 64, color: pt.fgDim),
const SizedBox(height: 16),
Text(
'Wähle einen Chat aus',
style: TextStyle(color: pt.fgMuted, fontSize: 16),
),
const SizedBox(height: 8),
Text(
'Choose from the sidebar on the left',
style: TextStyle(color: pt.fgDim, fontSize: 13),
),
],
),
),
);
}
}
/// Fläche der schwebenden Eingabeleiste: um das Eingabefeld herum völlig
/// klar – der Chat ist dort normal zu sehen –, fängt aber alle Berührungen
/// ab (ColoredBox ist auch transparent „opak“ für Treffer), damit dort nur
/// die Eingabe reagiert und nicht der Chat dahinter. Die Unschärfe sitzt nur
/// hinter dem Eingabefeld selbst (chat_composer.dart).
class _FloatingComposerArea extends StatelessWidget {
final PyramidTheme pt;
final Widget child;
const _FloatingComposerArea({required this.pt, required this.child});
@override
Widget build(BuildContext context) {
return ColoredBox(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.only(top: 6),
child: child,
),
);
}
}