Skip to content

Commit c7bc86c

Browse files
committed
routing improvements
- update routing metadata to use enum-based paths and shared route lists - simplify pane selection using enum order and direct path navigation - restrict AutoSuggestBoxItem to tweaks-only items - include icons in AutoSuggestBox items - cache breadcrumb items to reduce allocations - reduce runtime list building for pane/search items
1 parent ffd53f2 commit c7bc86c

6 files changed

Lines changed: 241 additions & 195 deletions

File tree

src/lib/core/routing/app_router.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ final _shellNavigatorKey = GlobalKey<NavigatorState>(debugLabel: 'shell');
2121

2222
final appRouter = GoRouter(
2323
navigatorKey: _rootNavigatorKey,
24-
initialLocation: initialRoute ?? AppRoutes.home,
24+
initialLocation: initialRoute ?? RouteMeta.home.path,
2525
redirect: (context, state) {
2626
if (!WinRegistryService.isSupported) {
2727
return AppRoutes.unsupported;
@@ -36,12 +36,12 @@ final appRouter = GoRouter(
3636
},
3737
routes: [
3838
GoRoute(
39-
path: AppRoutes.home,
39+
path: RouteMeta.home.path,
4040
name: 'home',
4141
builder: (context, state) => const HomePage(),
4242
),
4343
GoRoute(
44-
path: AppRoutes.tweaks,
44+
path: RouteMeta.tweaks.path,
4545
name: 'tweaks',
4646
builder: (context, state) => const TweaksPage(),
4747
routes: [
@@ -98,12 +98,12 @@ final appRouter = GoRouter(
9898
],
9999
),
100100
GoRoute(
101-
path: AppRoutes.msStore,
101+
path: RouteMeta.msStore.path,
102102
name: 'msstore',
103103
builder: (context, state) => const MSStorePage(),
104104
),
105105
GoRoute(
106-
path: AppRoutes.settings,
106+
path: RouteMeta.settings.path,
107107
name: 'settings',
108108
builder: (context, state) => const SettingsPage(),
109109
),

src/lib/core/routing/app_routes.dart

Lines changed: 170 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,157 @@
11
import 'package:fluent_ui/fluent_ui.dart';
2+
import 'package:fluentui_system_icons/fluentui_system_icons.dart' as msicons;
23
import 'package:go_router/go_router.dart';
34
import 'package:revitool/i18n/generated/strings.g.dart';
45

5-
class AppRoutes {
6-
static const String home = '/';
7-
static const String tweaks = '/tweaks';
8-
static const String msStore = '/msstore';
9-
static const String settings = '/settings';
6+
enum RouteSection { main, footer, search }
107

11-
static const String security = '/tweaks/security';
12-
static const String performance = '/tweaks/performance';
13-
static const String personalization = '/tweaks/personalization';
14-
static const String utilities = '/tweaks/utilities';
15-
static const String updates = '/tweaks/updates';
8+
enum RouteMeta {
9+
home(
10+
path: '/',
11+
section: RouteSection.main,
12+
icon: msicons.FluentIcons.home_24_regular,
13+
),
14+
tweaks(
15+
path: '/tweaks',
16+
section: RouteSection.main,
17+
icon: msicons.FluentIcons.wrench_24_regular,
18+
),
19+
msStore(
20+
path: '/msstore',
21+
section: RouteSection.main,
22+
icon: msicons.FluentIcons.store_microsoft_24_regular,
23+
),
24+
settings(
25+
path: '/settings',
26+
section: RouteSection.footer,
27+
icon: msicons.FluentIcons.settings_24_regular,
28+
),
29+
tweaksSecurity(
30+
path: '/tweaks/security',
31+
section: RouteSection.search,
32+
icon: msicons.FluentIcons.shield_lock_20_regular,
33+
),
34+
tweaksPerformance(
35+
path: '/tweaks/performance',
36+
section: RouteSection.search,
37+
icon: msicons.FluentIcons.top_speed_24_regular,
38+
),
39+
tweaksPersonalization(
40+
path: '/tweaks/personalization',
41+
section: RouteSection.search,
42+
icon: msicons.FluentIcons.color_24_regular,
43+
),
44+
tweaksUtilities(
45+
path: '/tweaks/utilities',
46+
section: RouteSection.search,
47+
icon: msicons.FluentIcons.toolbox_24_regular,
48+
),
49+
tweaksUpdates(
50+
path: '/tweaks/updates',
51+
section: RouteSection.search,
52+
icon: msicons.FluentIcons.arrow_download_24_regular,
53+
);
1654

17-
static const String unsupported = '/unsupported';
55+
const RouteMeta({
56+
required this.path,
57+
required this.section,
58+
required this.icon,
59+
});
1860

19-
static String getRouteName(String path, BuildContext context) {
20-
switch (path) {
21-
case home:
61+
final String path;
62+
final RouteSection section;
63+
final IconData icon;
64+
65+
String get label {
66+
switch (this) {
67+
case RouteMeta.home:
2268
return t.pageHome;
23-
case tweaks:
69+
case RouteMeta.tweaks:
2470
return t.pageTweaks;
25-
case msStore:
71+
case RouteMeta.msStore:
2672
return t.pageMSStore;
27-
case settings:
73+
case RouteMeta.settings:
2874
return t.pageSettings;
29-
default:
30-
final segment = path.split('/').last;
31-
return segment.isEmpty ? 'Home' : segment.capitalize();
75+
case RouteMeta.tweaksSecurity:
76+
return t.pageTweaksSecurity;
77+
case RouteMeta.tweaksPerformance:
78+
return t.pageTweaksPerformance;
79+
case RouteMeta.tweaksPersonalization:
80+
return t.pageTweaksPersonalization;
81+
case RouteMeta.tweaksUtilities:
82+
return t.pageTweaksUtilities;
83+
case RouteMeta.tweaksUpdates:
84+
return t.pageTweaksUpdates;
3285
}
3386
}
3487

88+
static final _pathLookup = {for (final r in values) r.path: r};
89+
90+
static RouteMeta? fromPath(String path, {bool allowPrefix = false}) {
91+
if (!allowPrefix) return _pathLookup[path];
92+
for (final route in _navigationRoutes) {
93+
if (path == route.path ||
94+
(route.path != '/' && path.startsWith('${route.path}/'))) {
95+
return route;
96+
}
97+
}
98+
return null;
99+
}
100+
}
101+
102+
class AppRoutes {
103+
static const String unsupported = '/unsupported';
104+
105+
static const List<RouteMeta> navigationRoutes = _navigationRoutes;
106+
107+
static final mainPaneItems = _buildPaneItems(_mainNavigationRoutes);
108+
static final footerPaneItems = _buildPaneItems(_footerNavigationRoutes);
109+
static final searchableItems = _buildPaneItems(_searchableRoutes);
110+
111+
static String getRouteName(String path, BuildContext context) {
112+
final meta = RouteMeta.fromPath(path);
113+
if (meta != null) {
114+
return meta.label;
115+
}
116+
final segment = path.split('/').last;
117+
return segment.isEmpty ? t.pageHome : segment.capitalize();
118+
}
119+
120+
static int? getPaneIndexFromRoute(RouteMeta? route) =>
121+
route != null && route.section != RouteSection.search
122+
? route.index
123+
: null;
124+
125+
static final _breadcrumbsCache = <String, List<BreadcrumbItem<String>>>{};
126+
35127
static List<BreadcrumbItem<String>> buildBreadcrumbs(
36128
String location,
37129
BuildContext context,
38130
) {
39-
final segments = location.split('/').where((s) => s.isNotEmpty).toList();
40-
final breadcrumbs = <BreadcrumbItem<String>>[];
41-
final theme = FluentTheme.of(context);
42-
43-
String currentPath = '';
44-
for (int i = 0; i < segments.length; i++) {
45-
currentPath += '/${segments[i]}';
46-
final name = getRouteName(currentPath, context);
47-
final isLast = i == segments.length - 1;
48-
49-
breadcrumbs.add(
50-
BreadcrumbItem(
51-
label: Text(
52-
name,
53-
style: TextStyle(
54-
color: isLast
55-
? theme.typography.body?.color
56-
: theme.resources.textFillColorSecondary,
57-
),
58-
),
59-
value: currentPath,
60-
),
61-
);
62-
}
131+
return _breadcrumbsCache.putIfAbsent(location, () {
132+
final segments = location.split('/').where((s) => s.isNotEmpty).toList();
133+
final theme = FluentTheme.of(context);
63134

64-
return breadcrumbs;
135+
String currentPath = '';
136+
return [
137+
for (int i = 0; i < segments.length; i++)
138+
(() {
139+
currentPath += '/${segments[i]}';
140+
final isLast = i == segments.length - 1;
141+
return BreadcrumbItem(
142+
label: Text(
143+
getRouteName(currentPath, context),
144+
style: TextStyle(
145+
color: isLast
146+
? theme.typography.body?.color
147+
: theme.resources.textFillColorSecondary,
148+
),
149+
),
150+
value: currentPath,
151+
);
152+
})(),
153+
];
154+
});
65155
}
66156

67157
/// Creates a page with [HorizontalSlidePageTransition] for nested routes.
@@ -92,6 +182,41 @@ class AppRoutes {
92182
}
93183
}
94184

185+
const List<RouteMeta> _mainNavigationRoutes = [
186+
RouteMeta.home,
187+
RouteMeta.tweaks,
188+
RouteMeta.msStore,
189+
];
190+
191+
const List<RouteMeta> _footerNavigationRoutes = [RouteMeta.settings];
192+
193+
const List<RouteMeta> _searchableRoutes = [
194+
RouteMeta.tweaksSecurity,
195+
RouteMeta.tweaksPerformance,
196+
RouteMeta.tweaksPersonalization,
197+
RouteMeta.tweaksUtilities,
198+
RouteMeta.tweaksUpdates,
199+
];
200+
201+
const List<RouteMeta> _navigationRoutes = [
202+
..._mainNavigationRoutes,
203+
..._footerNavigationRoutes,
204+
];
205+
206+
List<NavigationPaneItem> _buildPaneItems(List<RouteMeta> routes) {
207+
return routes
208+
.map(
209+
(route) => PaneItem(
210+
key: ValueKey(route.path),
211+
icon: Icon(route.icon, size: 20),
212+
title: Text(route.label),
213+
body: const SizedBox.shrink(),
214+
),
215+
)
216+
.toList(growable: false)
217+
.cast<NavigationPaneItem>();
218+
}
219+
95220
extension _StringExtension on String {
96221
String capitalize() {
97222
if (isEmpty) return this;

0 commit comments

Comments
 (0)