Initial commit
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
import 'dart:io' show Platform;
|
||||
import 'dart:ui' show ImageFilter;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'detail_backdrop.dart';
|
||||
|
||||
|
||||
class DetailImmersiveScaffold extends StatelessWidget {
|
||||
final ScrollController scrollController;
|
||||
final ValueNotifier<double> scrollProgress;
|
||||
final String? backdropUrl;
|
||||
final List<String> fallbackUrls;
|
||||
final String embyBaseUrl;
|
||||
final Map<String, String>? imageHeaders;
|
||||
final Widget child;
|
||||
final bool compact;
|
||||
final double horizontalPadding;
|
||||
|
||||
const DetailImmersiveScaffold({
|
||||
super.key,
|
||||
required this.scrollController,
|
||||
required this.scrollProgress,
|
||||
required this.child,
|
||||
this.backdropUrl,
|
||||
this.fallbackUrls = const <String>[],
|
||||
this.embyBaseUrl = '',
|
||||
this.imageHeaders,
|
||||
this.compact = false,
|
||||
this.horizontalPadding = 32,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final screenSize = MediaQuery.sizeOf(context);
|
||||
final screenHeight = screenSize.height;
|
||||
final screenWidth = screenSize.width;
|
||||
final bannerHeight = compact
|
||||
? screenHeight * 0.30
|
||||
: (screenWidth * 9.0 / 16.0).clamp(280.0, screenHeight * 0.6);
|
||||
final backdrop = backdropUrl;
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
if (backdrop != null)
|
||||
DetailBackdrop(
|
||||
scrollProgress: scrollProgress,
|
||||
backdropUrl: backdrop,
|
||||
fallbackUrls: fallbackUrls,
|
||||
embyBaseUrl: embyBaseUrl,
|
||||
imageHeaders: imageHeaders,
|
||||
),
|
||||
SingleChildScrollView(
|
||||
controller: scrollController,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: bannerHeight - 80),
|
||||
Stack(
|
||||
children: [
|
||||
Positioned.fill(child: _FrostedPanelVeil()),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
horizontalPadding,
|
||||
64,
|
||||
horizontalPadding,
|
||||
48,
|
||||
),
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 1200),
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _FrostedPanelVeil extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (Platform.isAndroid) {
|
||||
return IgnorePointer(
|
||||
child: ShaderMask(
|
||||
shaderCallback: (rect) {
|
||||
final ratio = (140.0 / rect.height).clamp(0.02, 0.5);
|
||||
return LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: const [Colors.transparent, Colors.black],
|
||||
stops: [0.0, ratio],
|
||||
).createShader(rect);
|
||||
},
|
||||
blendMode: BlendMode.dstIn,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
stops: const [0.0, 0.12, 1.0],
|
||||
colors: [
|
||||
const Color(0xFF0a0c10).withValues(alpha: 0.0),
|
||||
const Color(0xFF0a0c10).withValues(alpha: 0.88),
|
||||
const Color(0xFF0a0c10).withValues(alpha: 0.96),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return IgnorePointer(
|
||||
child: ShaderMask(
|
||||
shaderCallback: (rect) {
|
||||
final ratio = (140.0 / rect.height).clamp(0.02, 0.5);
|
||||
return LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: const [Colors.transparent, Colors.black],
|
||||
stops: [0.0, ratio],
|
||||
).createShader(rect);
|
||||
},
|
||||
blendMode: BlendMode.dstIn,
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 40, sigmaY: 40),
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
stops: const [0.0, 0.20, 1.0],
|
||||
colors: [
|
||||
const Color(0xFF0a0c10).withValues(alpha: 0.0),
|
||||
const Color(0xFF0a0c10).withValues(alpha: 0.12),
|
||||
const Color(0xFF0a0c10).withValues(alpha: 0.20),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user