mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-10-04 15:16:58 +02:00
perf(store): skip invisible backdrop blur on repo cards
Repo cards, category chips and the Store search field scroll over the plain page background, where a backdrop blur changes nothing visible but re-filters each panel on every scroll frame. MornyeGlass.navigation gains samplesBackdrop; these panels keep the same tint, rim, shadow and glass clarity without the blur pass. Floating chrome keeps its blur.
This commit is contained in:
1 parent
a21e46e6dd
commit
be9e9903d9
5 files changed
+90
-2
No files matched your search
@@ -128,6 +128,7 @@ class _RepoTabState extends ConsumerState<RepoTab> {
|
||||
controller: _searchController,
|
||||
hintText: context.l10n.storeSearch,
|
||||
clearTooltip: context.l10n.dialogClear,
|
||||
samplesBackdrop: false,
|
||||
onChanged: (value) =>
|
||||
ref.read(repoProvider.notifier).setSearchQuery(value),
|
||||
onClear: () =>
|
||||
@@ -657,9 +658,11 @@ class _CategoryChip extends ConsumerWidget {
|
||||
label: label,
|
||||
onTap: onTap,
|
||||
excludeSemantics: true,
|
||||
// Scrolls with the list over the plain page: see ExtensionRepoCard.
|
||||
child: MornyeGlass.navigation(
|
||||
radius: 24,
|
||||
blurEnabled: ref.watch(mornyeBlurEnabledProvider),
|
||||
samplesBackdrop: false,
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
|
||||
@@ -24,6 +24,7 @@ class AppSearchField extends StatelessWidget {
|
||||
this.suffixIcon,
|
||||
this.focusNode,
|
||||
this.autofocus = false,
|
||||
this.samplesBackdrop = true,
|
||||
});
|
||||
|
||||
final TextEditingController controller;
|
||||
@@ -37,6 +38,10 @@ class AppSearchField extends StatelessWidget {
|
||||
final FocusNode? focusNode;
|
||||
final bool autofocus;
|
||||
|
||||
/// See [MornyeGlass.samplesBackdrop]: false where the field scrolls over
|
||||
/// the plain page background.
|
||||
final bool samplesBackdrop;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
@@ -107,6 +112,7 @@ class AppSearchField extends StatelessWidget {
|
||||
builder: (context, ref, child) => MornyeGlass.navigation(
|
||||
radius: 28,
|
||||
blurEnabled: ref.watch(mornyeBlurEnabledProvider),
|
||||
samplesBackdrop: samplesBackdrop,
|
||||
child: child!,
|
||||
),
|
||||
child: field,
|
||||
|
||||
@@ -34,9 +34,12 @@ class ExtensionRepoCard extends ConsumerWidget {
|
||||
}
|
||||
return Padding(
|
||||
padding: margin,
|
||||
// Repo pages scroll these cards over the plain page background, where a
|
||||
// backdrop blur is invisible but re-filters the whole card every frame.
|
||||
child: MornyeGlass.navigation(
|
||||
radius: 24,
|
||||
blurEnabled: ref.watch(mornyeBlurEnabledProvider),
|
||||
samplesBackdrop: false,
|
||||
child: Material(color: Colors.transparent, child: child),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -257,7 +257,8 @@ class MornyeGlass extends StatelessWidget {
|
||||
this.backdropFilter,
|
||||
}) : _useLens = true,
|
||||
firstInGroup = true,
|
||||
lastInGroup = true;
|
||||
lastInGroup = true,
|
||||
samplesBackdrop = true;
|
||||
|
||||
/// Shares the navigation bar's tint, blur and subtle edge reflections.
|
||||
const MornyeGlass.navigation({
|
||||
@@ -271,10 +272,17 @@ class MornyeGlass extends StatelessWidget {
|
||||
this.tintOpacity,
|
||||
this.tintColor,
|
||||
this.backdropFilter,
|
||||
this.samplesBackdrop = true,
|
||||
}) : _useLens = false;
|
||||
|
||||
final Widget child;
|
||||
final bool blurEnabled;
|
||||
|
||||
/// False for panels that only ever scroll over the plain page background.
|
||||
/// Blurring a uniform backdrop changes nothing visible but re-filters the
|
||||
/// panel's whole area on every scroll frame; the translucent tint, rim and
|
||||
/// clarity preference stay exactly as with sampling.
|
||||
final bool samplesBackdrop;
|
||||
final double radius;
|
||||
final bool _useLens;
|
||||
final bool firstInGroup;
|
||||
@@ -311,6 +319,7 @@ class MornyeGlass extends StatelessWidget {
|
||||
tintOpacity: tintOpacity,
|
||||
tintColor: tintColor,
|
||||
backdropFilter: backdropFilter,
|
||||
samplesBackdrop: samplesBackdrop,
|
||||
child: useGlass ? lens(child) : child,
|
||||
);
|
||||
}
|
||||
@@ -389,6 +398,7 @@ class _MornyeGlassSurface extends StatelessWidget {
|
||||
this.tintOpacity,
|
||||
this.tintColor,
|
||||
this.backdropFilter,
|
||||
this.samplesBackdrop = true,
|
||||
});
|
||||
|
||||
final Widget child;
|
||||
@@ -400,6 +410,7 @@ class _MornyeGlassSurface extends StatelessWidget {
|
||||
final double? tintOpacity;
|
||||
final Color? tintColor;
|
||||
final ImageFilter? backdropFilter;
|
||||
final bool samplesBackdrop;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -452,7 +463,7 @@ class _MornyeGlassSurface extends StatelessWidget {
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: shape,
|
||||
child: useBlur
|
||||
child: useBlur && samplesBackdrop
|
||||
? BackdropFilter(
|
||||
filter:
|
||||
backdropFilter ?? (dark ? _darkBackdrop : _backdropBlur),
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:liquid_glass_easy/liquid_glass_easy.dart';
|
||||
import 'package:spotiflac_android/providers/runtime_profile_provider.dart';
|
||||
import 'package:spotiflac_android/theme/mornye_theme.dart';
|
||||
import 'package:spotiflac_android/widgets/app_switch.dart';
|
||||
import 'package:spotiflac_android/widgets/extension_repo_card.dart';
|
||||
import 'package:spotiflac_android/widgets/mornye_chrome.dart';
|
||||
|
||||
MornyeGlassLevel _levelFor({
|
||||
@@ -183,6 +184,70 @@ void main() {
|
||||
});
|
||||
}
|
||||
|
||||
testWidgets('plain-page panels keep the glass tint without a backdrop pass', (
|
||||
tester,
|
||||
) async {
|
||||
Color? tintOf(Finder panel) {
|
||||
final decorated = tester
|
||||
.widgetList<DecoratedBox>(
|
||||
find.descendant(of: panel, matching: find.byType(DecoratedBox)),
|
||||
)
|
||||
.map((box) => box.decoration)
|
||||
.whereType<BoxDecoration>()
|
||||
.firstWhere((decoration) => decoration.color != null);
|
||||
return decorated.color;
|
||||
}
|
||||
|
||||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
child: MaterialApp(
|
||||
theme: MornyeTheme.build(Brightness.dark),
|
||||
home: const Scaffold(
|
||||
body: Column(
|
||||
children: [
|
||||
MornyeGlass.navigation(
|
||||
key: ValueKey('sampled'),
|
||||
blurEnabled: true,
|
||||
child: SizedBox(width: 200, height: 40),
|
||||
),
|
||||
MornyeGlass.navigation(
|
||||
key: ValueKey('plain-page'),
|
||||
blurEnabled: true,
|
||||
samplesBackdrop: false,
|
||||
child: SizedBox(width: 200, height: 40),
|
||||
),
|
||||
ExtensionRepoCard(child: SizedBox(width: 200, height: 40)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
final sampled = find.byKey(const ValueKey('sampled'));
|
||||
final plain = find.byKey(const ValueKey('plain-page'));
|
||||
expect(
|
||||
find.descendant(of: sampled, matching: find.byType(BackdropFilter)),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(
|
||||
find.descendant(of: plain, matching: find.byType(BackdropFilter)),
|
||||
findsNothing,
|
||||
);
|
||||
expect(
|
||||
find.descendant(
|
||||
of: find.byType(ExtensionRepoCard),
|
||||
matching: find.byType(BackdropFilter),
|
||||
),
|
||||
findsNothing,
|
||||
);
|
||||
// Same translucent material, so the page looks identical behind it.
|
||||
expect(tintOf(plain), tintOf(sampled));
|
||||
expect(tintOf(plain)!.a, lessThan(1));
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
testWidgets('liquid level keeps the shader glass', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
|
||||
Reference in new issue
Block a user