f9979e4f32
Qualitäts-Review-Befund (a): Alle 6 part/part-of-Aufteilungen hatten Code vollständig übernommen (Zeilen-Multiset-Vergleich Original vs. heutiger Stand: keine Code-Zeile verloren, keine hinzugefügt), ABER erklärende Kommentare über den Klassen gingen verloren (24 Blöcke, u. a. die HTML-Subset-Doku über _MatrixHtmlText, die Selbst-Aussperr-Warnung über updatePowerLevelsSafely, TURN-Verbrauchskarte, PDF-Cache/Viewer-Doku). Alle an den richtigen Klassen wiederhergestellt; reine Trennlinien und ALL-CAPS-Abschnittslabels bewusst nicht (Gott-Datei-Navigation, durch die neuen Dateinamen ersetzt). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
132 lines
3.7 KiB
Dart
132 lines
3.7 KiB
Dart
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(
|
|
'Select a room to start chatting',
|
|
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),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|