Frosted bottom bar: adjustable blur and opacity with Less/Default/More presets

Settings > Appearance shows a preset control plus Blur and Opacity sliders
(new NooSlider) while frosted glass is on; values persist and feed
NooBottomBar.frostedBlur/frostedOpacity. Default matches the old fixed look.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Ayushya Amitabh
2026-10-06 19:46:54 -04:00
co-authored by Claude Sonnet 5.5
parent 0c063c1fb4
commit 0cda4a1241
10 changed files with 431 additions and 16 deletions
+30
View File
@@ -10,6 +10,7 @@ import 'package:noo/widgets/noo/core/noo_chip.dart';
import 'package:noo/widgets/noo/core/noo_fab.dart';
import 'package:noo/widgets/noo/core/noo_progress_bar.dart';
import 'package:noo/widgets/noo/core/noo_search_field.dart';
import 'package:noo/widgets/noo/core/noo_slider.dart';
import 'package:noo/widgets/noo/core/noo_segmented_control.dart';
import 'package:noo/widgets/noo/core/noo_toggle.dart';
import 'package:noo/widgets/noo/nav/noo_nav_style.dart';
@@ -98,6 +99,35 @@ void main() {
}
});
group('NooSlider', () {
testNooWidgets('dragging reports a value within min..max', (
tester,
theme,
c,
) async {
var value = 10.0;
await pumpNoo(
tester,
StatefulBuilder(
builder: (context, setState) => SizedBox(
width: 300,
child: NooSlider(
value: value,
min: 0,
max: 40,
onChanged: (v) => setState(() => value = v),
),
),
),
theme: theme,
);
await tester.drag(find.byType(Slider), const Offset(150, 0));
await tester.pump();
expect(value, greaterThan(10));
expect(value, lessThanOrEqualTo(40));
});
});
group('NooAvatar', () {
testNooWidgets('current user uses accent-soft/accent-text', (
tester,
+39
View File
@@ -1,3 +1,4 @@
import 'dart:ui' show ImageFilter;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart';
@@ -62,6 +63,44 @@ void main() {
}
}
testNooWidgets('frosted bar uses the given blur sigma and fill opacity', (
tester,
theme,
c,
) async {
await pumpNoo(
tester,
SizedBox(
width: 360,
height: 120,
child: NooBottomBar(
style: NooNavStyle.android,
frosted: true,
frostedBlur: 31,
frostedOpacity: 0.5,
destinations: _destinations,
selectedIndex: 0,
onSelected: (_) {},
),
),
theme: theme,
);
expect(
tester.widget<BackdropFilter>(find.byType(BackdropFilter)).filter,
ImageFilter.blur(sigmaX: 31, sigmaY: 31),
);
expect(
find.byWidgetPredicate(
(w) =>
w is Container &&
w.decoration is BoxDecoration &&
(w.decoration as BoxDecoration).color ==
c.surface.withValues(alpha: 0.5),
),
findsOneWidget,
);
});
test('drawsBehindBody: floating or frosted', () {
expect(
NooBottomBar.drawsBehindBody(NooBottomBarStyle.attached, false),