import 'dart:io'; import 'dart:math' as math; import 'dart:ui' show ImageFilter; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../providers/appearance_provider.dart'; import '../theme/app_theme.dart'; import 'window_chrome.dart'; class ScrollFadeHeader extends ConsumerWidget { final ValueNotifier scrollProgress; final List actions; const ScrollFadeHeader({ super.key, required this.scrollProgress, this.actions = const [], }); @override Widget build(BuildContext context, WidgetRef ref) { final tokens = context.appTokens; final isDesktop = Platform.isMacOS || Platform.isWindows; final topPadding = isDesktop ? tokens.titleBarHeight : math.max(MediaQuery.paddingOf(context).top, tokens.titleBarHeight); final overlayHeight = topPadding + 12; final headerMode = ref.watch(appearanceProvider).value?.headerMode ?? HeaderMode.frosted; final isFrosted = headerMode == HeaderMode.frosted; final theme = Theme.of(context); final background = ValueListenableBuilder( valueListenable: scrollProgress, builder: (_, raw, _) { final p = raw.clamp(0.0, 1.0); if (isFrosted) { final entryProgress = (p / 0.25).clamp(0.0, 1.0); final glassProgress = Curves.easeOutCubic.transform(entryProgress) * 0.42; return ClipRect( child: BackdropFilter( filter: ImageFilter.blur( sigmaX: glassProgress * 10, sigmaY: glassProgress * 10, ), child: DecoratedBox( decoration: BoxDecoration( color: theme.colorScheme.surface.withValues( alpha: glassProgress * 0.88, ), border: Border( bottom: BorderSide( color: theme.colorScheme.onSurface.withValues( alpha: glassProgress * 0.08, ), width: 1, ), ), ), ), ), ); } return ColoredBox( color: theme.colorScheme.surface.withValues(alpha: p), ); }, ); return SizedBox( height: overlayHeight, width: double.infinity, child: Stack( children: [ Positioned.fill(child: IgnorePointer(child: background)), if (actions.isNotEmpty) Positioned( right: 0, top: tokens.chromeInset, height: WindowChrome.controlsHeight, child: Row( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ ...actions, SizedBox(width: WindowChrome.reservedTrailingWidth(tokens)), ], ), ), ], ), ); } }