Files
2026-07-14 11:11:36 +08:00

102 lines
3.0 KiB
Dart

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<double> scrollProgress;
final List<Widget> 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<double>(
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)),
],
),
),
],
),
);
}
}