perf: prevent expensive blurring when the current page is hidden

This commit is contained in:
Thibault Deckers 2022-05-23 12:32:13 +09:00
parent 25019f8357
commit 512c507942
5 changed files with 95 additions and 51 deletions

View file

@ -27,7 +27,7 @@ class SettingsDefaults {
static const mustBackTwiceToExit = true; static const mustBackTwiceToExit = true;
static const keepScreenOn = KeepScreenOn.viewerOnly; static const keepScreenOn = KeepScreenOn.viewerOnly;
static const homePage = HomePageSetting.collection; static const homePage = HomePageSetting.collection;
static const showBottomNavigationBar = false; static const showBottomNavigationBar = true;
static const confirmDeleteForever = true; static const confirmDeleteForever = true;
static const confirmMoveToBin = true; static const confirmMoveToBin = true;
static const confirmMoveUndatedItems = true; static const confirmMoveUndatedItems = true;

View file

@ -44,6 +44,10 @@ class AvesApp extends StatefulWidget {
static final GlobalKey<NavigatorState> navigatorKey = GlobalKey(debugLabel: 'app-navigator'); static final GlobalKey<NavigatorState> navigatorKey = GlobalKey(debugLabel: 'app-navigator');
// do not monitor all `ModalRoute`s, which would include popup menus,
// so that we can react to fullscreen `PageRoute`s only
static final RouteObserver<PageRoute> pageRouteObserver = RouteObserver<PageRoute>();
const AvesApp({ const AvesApp({
super.key, super.key,
required this.flavor, required this.flavor,
@ -62,7 +66,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
// observers are not registered when using the same list object with different items // observers are not registered when using the same list object with different items
// the list itself needs to be reassigned // the list itself needs to be reassigned
List<NavigatorObserver> _navigatorObservers = []; List<NavigatorObserver> _navigatorObservers = [AvesApp.pageRouteObserver];
final EventChannel _mediaStoreChangeChannel = const EventChannel('deckers.thibault/aves/media_store_change'); final EventChannel _mediaStoreChangeChannel = const EventChannel('deckers.thibault/aves/media_store_change');
final EventChannel _newIntentChannel = const EventChannel('deckers.thibault/aves/intent'); final EventChannel _newIntentChannel = const EventChannel('deckers.thibault/aves/intent');
final EventChannel _analysisCompletionChannel = const EventChannel('deckers.thibault/aves/analysis_events'); final EventChannel _analysisCompletionChannel = const EventChannel('deckers.thibault/aves/analysis_events');
@ -284,6 +288,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
'time_zone': '${now.timeZoneName} (${now.timeZoneOffset})', 'time_zone': '${now.timeZoneName} (${now.timeZoneOffset})',
}); });
_navigatorObservers = [ _navigatorObservers = [
AvesApp.pageRouteObserver,
ReportingRouteTracker(), ReportingRouteTracker(),
]; ];
} }

View file

@ -1,5 +1,6 @@
import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/settings/settings.dart';
import 'package:aves/theme/durations.dart'; import 'package:aves/theme/durations.dart';
import 'package:aves/widgets/aves_app.dart';
import 'package:aves/widgets/common/fx/blurred.dart'; import 'package:aves/widgets/common/fx/blurred.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -35,37 +36,38 @@ class AvesAppBar extends StatelessWidget {
child: SafeArea( child: SafeArea(
bottom: false, bottom: false,
child: AvesFloatingBar( child: AvesFloatingBar(
builder: (context, backgroundColor) => Material( builder: (context, backgroundColor, child) => Material(
color: backgroundColor, color: backgroundColor,
textStyle: Theme.of(context).appBarTheme.titleTextStyle, textStyle: Theme.of(context).appBarTheme.titleTextStyle,
child: Column( child: child,
children: [ ),
SizedBox( child: Column(
height: kToolbarHeight, children: [
child: Row( SizedBox(
children: [ height: kToolbarHeight,
Padding( child: Row(
padding: const EdgeInsets.symmetric(horizontal: 4), children: [
child: leading, Padding(
), padding: const EdgeInsets.symmetric(horizontal: 4),
Expanded( child: leading,
child: AnimatedSwitcher( ),
duration: context.read<DurationsData>().iconAnimation, Expanded(
child: Row( child: AnimatedSwitcher(
key: ValueKey(transitionKey), duration: context.read<DurationsData>().iconAnimation,
children: [ child: Row(
Expanded(child: title), key: ValueKey(transitionKey),
...actions, children: [
], Expanded(child: title),
), ...actions,
],
), ),
), ),
], ),
), ],
), ),
if (bottom != null) bottom!, ),
], if (bottom != null) bottom!,
), ],
), ),
), ),
), ),
@ -100,39 +102,75 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
bool shouldRebuild(covariant _SliverAppBarDelegate oldDelegate) => true; bool shouldRebuild(covariant _SliverAppBarDelegate oldDelegate) => true;
} }
class AvesFloatingBar extends StatelessWidget { class AvesFloatingBar extends StatefulWidget {
final Widget Function(BuildContext context, Color backgroundColor) builder; final Widget Function(BuildContext context, Color backgroundColor, Widget? child) builder;
final Widget? child;
static const margin = EdgeInsets.all(8);
static const borderRadius = BorderRadius.all(Radius.circular(8));
const AvesFloatingBar({ const AvesFloatingBar({
super.key, super.key,
required this.builder, required this.builder,
this.child,
}); });
static const margin = EdgeInsets.all(8); @override
static const borderRadius = BorderRadius.all(Radius.circular(8)); State<AvesFloatingBar> createState() => _AvesFloatingBarState();
}
class _AvesFloatingBarState extends State<AvesFloatingBar> with RouteAware {
// prevent expensive blurring when the current page is hidden
final ValueNotifier<bool> _isBlurAllowedNotifier = ValueNotifier(true);
@override
void didChangeDependencies() {
super.didChangeDependencies();
final route = ModalRoute.of(context);
if (route is PageRoute) {
AvesApp.pageRouteObserver.subscribe(this, route);
}
}
@override
void dispose() {
AvesApp.pageRouteObserver.unsubscribe(this);
super.dispose();
}
@override
void didPopNext() => _isBlurAllowedNotifier.value = true;
@override
void didPushNext() => _isBlurAllowedNotifier.value = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final backgroundColor = theme.appBarTheme.backgroundColor!; final backgroundColor = theme.appBarTheme.backgroundColor!;
final blurred = context.select<Settings, bool>((s) => s.enableOverlayBlurEffect); return ValueListenableBuilder<bool>(
valueListenable: _isBlurAllowedNotifier,
return Container( builder: (context, isBlurAllowed, child) {
foregroundDecoration: BoxDecoration( final blurred = isBlurAllowed && context.select<Settings, bool>((s) => s.enableOverlayBlurEffect);
border: Border.all( return Container(
color: theme.dividerColor, foregroundDecoration: BoxDecoration(
), border: Border.all(
borderRadius: borderRadius, color: theme.dividerColor,
), ),
margin: margin, borderRadius: AvesFloatingBar.borderRadius,
child: BlurredRRect( ),
enabled: blurred, margin: AvesFloatingBar.margin,
borderRadius: borderRadius, child: BlurredRRect(
child: builder( enabled: blurred,
context, borderRadius: AvesFloatingBar.borderRadius,
blurred ? backgroundColor.withOpacity(.85) : backgroundColor, child: widget.builder(
), context,
), blurred ? backgroundColor.withOpacity(.85) : backgroundColor,
widget.child,
),
),
);
},
); );
} }
} }

View file

@ -75,7 +75,7 @@ class _AppBottomNavBarState extends State<AppBottomNavBar> {
]; ];
Widget child = AvesFloatingBar( Widget child = AvesFloatingBar(
builder: (context, backgroundColor) => BottomNavigationBar( builder: (context, backgroundColor, child) => BottomNavigationBar(
items: items items: items
.map((item) => BottomNavigationBarItem( .map((item) => BottomNavigationBarItem(
icon: item.icon(context), icon: item.icon(context),

View file

@ -20,6 +20,7 @@ Future<void> configureAndLaunch() async {
..isErrorReportingAllowed = false ..isErrorReportingAllowed = false
..keepScreenOn = KeepScreenOn.always ..keepScreenOn = KeepScreenOn.always
..homePage = HomePageSetting.collection ..homePage = HomePageSetting.collection
..showBottomNavigationBar = true
..setTileExtent(CountryListPage.routeName, 112) ..setTileExtent(CountryListPage.routeName, 112)
..setTileLayout(CountryListPage.routeName, TileLayout.grid) ..setTileLayout(CountryListPage.routeName, TileLayout.grid)
// collection // collection