fix: hero section gradient gap

This commit is contained in:
edde746
2026-01-19 01:03:29 +01:00
parent 86bb43dfc8
commit 45ff3faddb
+64 -36
View File
@@ -1132,6 +1132,7 @@ class _DiscoverScreenState extends State<DiscoverScreen>
child: SizedBox(
height: heroHeight,
child: Stack(
clipBehavior: Clip.none,
children: [
PageView.builder(
controller: _heroController,
@@ -1149,6 +1150,30 @@ class _DiscoverScreenState extends State<DiscoverScreen>
return _buildHeroItem(_onDeck[index]);
},
),
// Bottom gradient that extends past hero bounds to ensure seamless blend
Positioned(
left: 0,
right: 0,
bottom: -32, // Extend 32px past the hero section bounds
height: 80, // Tall enough to cover any gap
child: IgnorePointer(
child: Builder(
builder: (context) {
final bgColor = Theme.of(context).scaffoldBackgroundColor;
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [bgColor.withValues(alpha: 0), bgColor],
stops: const [0.0, 0.6],
),
),
);
},
),
),
),
// Page indicators with animated progress and pause/play button
Positioned(
bottom: 16,
@@ -1266,47 +1291,50 @@ class _DiscoverScreenState extends State<DiscoverScreen>
},
child: Stack(
fit: StackFit.expand,
clipBehavior: Clip.none,
children: [
// Background Image with fade/zoom animation and parallax
if (heroItem.art != null || heroItem.grandparentArt != null)
AnimatedBuilder(
animation: _scrollController,
builder: (context, child) {
final scrollOffset = _scrollController.hasClients ? _scrollController.offset : 0.0;
return Transform.translate(offset: Offset(0, scrollOffset * 0.3), child: child);
},
child: TweenAnimationBuilder<double>(
tween: Tween(begin: 0.0, end: 1.0),
duration: const Duration(milliseconds: 800),
curve: Curves.easeOut,
builder: (context, value, child) {
return Transform.scale(
scale: 1.0 + (0.1 * (1 - value)),
child: Opacity(opacity: value, child: child),
);
ClipRect(
child: AnimatedBuilder(
animation: _scrollController,
builder: (context, child) {
final scrollOffset = _scrollController.hasClients ? _scrollController.offset : 0.0;
return Transform.translate(offset: Offset(0, scrollOffset * 0.3), child: child);
},
child: Builder(
builder: (context) {
final client = _getClientForItem(heroItem);
final mediaQuery = MediaQuery.of(context);
final imageUrl = PlexImageHelper.getOptimizedImageUrl(
client: client,
thumbPath: heroItem.art ?? heroItem.grandparentArt,
maxWidth: mediaQuery.size.width,
maxHeight: mediaQuery.size.height * 0.7,
devicePixelRatio: mediaQuery.devicePixelRatio,
imageType: ImageType.art,
);
return CachedNetworkImage(
imageUrl: imageUrl,
fit: BoxFit.cover,
placeholder: (context, url) =>
Container(color: Theme.of(context).colorScheme.surfaceContainerHighest),
errorWidget: (context, url, error) =>
Container(color: Theme.of(context).colorScheme.surfaceContainerHighest),
child: TweenAnimationBuilder<double>(
tween: Tween(begin: 0.0, end: 1.0),
duration: const Duration(milliseconds: 800),
curve: Curves.easeOut,
builder: (context, value, child) {
return Transform.scale(
scale: 1.0 + (0.1 * (1 - value)),
child: Opacity(opacity: value, child: child),
);
},
child: Builder(
builder: (context) {
final client = _getClientForItem(heroItem);
final mediaQuery = MediaQuery.of(context);
final imageUrl = PlexImageHelper.getOptimizedImageUrl(
client: client,
thumbPath: heroItem.art ?? heroItem.grandparentArt,
maxWidth: mediaQuery.size.width,
maxHeight: mediaQuery.size.height * 0.7,
devicePixelRatio: mediaQuery.devicePixelRatio,
imageType: ImageType.art,
);
return CachedNetworkImage(
imageUrl: imageUrl,
fit: BoxFit.cover,
placeholder: (context, url) =>
Container(color: Theme.of(context).colorScheme.surfaceContainerHighest),
errorWidget: (context, url, error) =>
Container(color: Theme.of(context).colorScheme.surfaceContainerHighest),
);
},
),
),
),
)
@@ -1318,7 +1346,7 @@ class _DiscoverScreenState extends State<DiscoverScreen>
top: 0,
left: 0,
right: 0,
bottom: -1, // Extend 1px past to prevent subpixel gap
bottom: -4, // Extend past stack bounds to ensure coverage
child: Builder(
builder: (context) {
final bgColor = Theme.of(context).scaffoldBackgroundColor;