HomeShell: Blur-Layer und Mini-Player-Fade an progress gekoppelt

This commit is contained in:
Hermes (Server)
2026-08-29 14:39:56 +02:00
parent aea80d9755
commit 96113a3e41
2 changed files with 156 additions and 28 deletions
+82 -26
View File
@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:ui';
import 'package:audio_service/audio_service.dart';
import 'package:flutter/material.dart';
@@ -255,38 +256,93 @@ class _HomeShellState extends State<HomeShell>
child: child!,
),
child: Scaffold(
body: Column(
extendBody: true, // NowPlayingScreen (Task 5) braucht die volle Höhe bis unter die BottomNavigationBar
body: Stack(
children: [
Expanded(child: IndexedStack(index: _index, children: tabs)),
const MiniPlayer(),
AnimatedBuilder(
animation: _expansion,
builder: (context, child) => IgnorePointer(
ignoring: _expansion.progress > 0,
child: ExcludeSemantics(
excluding: _expansion.progress > 0,
child: child,
),
),
child: Column(
children: [
Expanded(child: IndexedStack(index: _index, children: tabs)),
const SizedBox(height: MiniPlayer.hoehe), // Platz für den Overlay-Mini-Player
],
),
),
AnimatedBuilder(
animation: _expansion,
builder: (context, child) {
final p = _expansion.progress;
if (p == 0) return const SizedBox.shrink();
return Positioned.fill(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: p * 20.0, sigmaY: p * 20.0),
child: Container(color: Colors.transparent),
),
);
},
),
AnimatedBuilder(
animation: _expansion,
builder: (context, child) => Positioned(
left: 0,
right: 0,
bottom: 0,
child: Opacity(
opacity: (1 - _expansion.progress).clamp(0.0, 1.0),
child: IgnorePointer(
ignoring: _expansion.progress > 0,
child: child,
),
),
),
child: const MiniPlayer(),
),
// NowPlayingScreen-Overlay-Inhalt folgt in Task 5 hier.
],
),
// Haarlinie darüber: ohne sie geht die Leiste auf schwarzem Grund
// optisch im Inhalt auf und wirkt nicht wie ein Hauptmenü.
bottomNavigationBar: DecoratedBox(
decoration: const BoxDecoration(
border: Border(top: BorderSide(color: MeloTheme.border)),
bottomNavigationBar: AnimatedBuilder(
animation: _expansion,
builder: (context, child) => Opacity(
opacity: (1 - _expansion.progress).clamp(0.0, 1.0),
child: IgnorePointer(
ignoring: _expansion.progress > 0,
child: child,
),
),
child: BottomNavigationBar(
currentIndex: _index,
onTap: _goTo,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.headphones), label: 'Meine Musik'),
BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Suchen'),
BottomNavigationBarItem(
icon: Icon(Icons.download_outlined),
activeIcon: Icon(Icons.download),
label: 'Download'),
BottomNavigationBarItem(
icon: Icon(Icons.favorite_border),
activeIcon: Icon(Icons.favorite),
label: 'Favoriten'),
BottomNavigationBarItem(
icon: Icon(Icons.smart_display_outlined),
activeIcon: Icon(Icons.smart_display),
label: 'YT-Suche'),
],
child: DecoratedBox(
decoration: const BoxDecoration(
border: Border(top: BorderSide(color: MeloTheme.border)),
),
child: BottomNavigationBar(
currentIndex: _index,
onTap: _goTo,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.headphones), label: 'Meine Musik'),
BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Suchen'),
BottomNavigationBarItem(
icon: Icon(Icons.download_outlined),
activeIcon: Icon(Icons.download),
label: 'Download'),
BottomNavigationBarItem(
icon: Icon(Icons.favorite_border),
activeIcon: Icon(Icons.favorite),
label: 'Favoriten'),
BottomNavigationBarItem(
icon: Icon(Icons.smart_display_outlined),
activeIcon: Icon(Icons.smart_display),
label: 'YT-Suche'),
],
),
),
),
),