Skip to content

Commit f502263

Browse files
committed
perf(views): cut the per-row work out of the override editors
1 parent d0e7916 commit f502263

13 files changed

Lines changed: 285 additions & 267 deletions

File tree

‎lib/enum/enum.dart‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,9 @@ enum ItemPosition {
450450
List<T> items,
451451
Set<T> deletedItems,
452452
) {
453+
if (deletedItems.isEmpty) {
454+
return ItemPosition.get(currentIndex, items.length);
455+
}
453456
final currentItem = items[currentIndex];
454457
if (deletedItems.contains(currentItem)) {
455458
return ItemPosition.middle;

‎lib/features/overwrite/overwrite_editor_page.dart‎

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,7 @@ class _OverwriteEditorPageState<T> extends ConsumerState<OverwriteEditorPage<T>>
6868
Set<dynamic> get _selected =>
6969
widget.selectionEnabled ? ref.watch(itemsProvider(key)) : const {};
7070

71-
bool get _isEditing => widget.selectionEnabled && _selected.isNotEmpty;
72-
73-
dynamic _idOf(T item) {
74-
return widget.selectionEnabled ? widget.idOf!(item) : null;
75-
}
76-
77-
bool _isSelected(T item) {
78-
return widget.selectionEnabled && _selected.contains(_idOf(item));
79-
}
71+
dynamic _idOf(T item) => widget.idOf?.call(item) ?? item;
8072

8173
void _handleToggleSelected(T item) {
8274
if (!widget.selectionEnabled) {
@@ -106,28 +98,34 @@ class _OverwriteEditorPageState<T> extends ConsumerState<OverwriteEditorPage<T>>
10698
}
10799
}
108100

109-
Widget _buildItem(BuildContext context, T item, int index, int total) {
110-
final isEditing = _isEditing;
101+
Widget _buildItem(
102+
BuildContext context,
103+
T item,
104+
int index,
105+
int total,
106+
Set<dynamic> selected,
107+
) {
108+
final id = _idOf(item);
111109
final child = ItemPositionProvider(
112110
position: ItemPosition.get(index, total),
113111
child: widget.itemBuilder(
114112
context,
115113
ref,
116114
item,
117115
index,
118-
isEditing,
119-
widget.selectionEnabled && _isSelected(item),
116+
widget.selectionEnabled && selected.isNotEmpty,
117+
widget.selectionEnabled && selected.contains(id),
120118
() => _handleToggleSelected(item),
121119
),
122120
);
123121
if (widget.dragFromRow) {
124122
return ReorderableDelayedDragStartListener(
125-
key: ValueKey(item),
123+
key: ValueKey(id),
126124
index: index,
127125
child: child,
128126
);
129127
}
130-
return KeyedSubtree(key: ValueKey(item), child: child);
128+
return KeyedSubtree(key: ValueKey(id), child: child);
131129
}
132130

133131
@override
@@ -176,14 +174,20 @@ class _OverwriteEditorPageState<T> extends ConsumerState<OverwriteEditorPage<T>>
176174
).copyWith(bottom: 24),
177175
itemBuilder: (_, index) {
178176
final item = items[index];
179-
return _buildItem(context, item, index, items.length);
177+
return _buildItem(
178+
context,
179+
item,
180+
index,
181+
items.length,
182+
selected,
183+
);
180184
},
181185
itemExtent: widget.itemExtent,
182186
itemCount: items.length,
183187
proxyDecorator: (child, index, animation) {
184188
final item = items[index];
185189
return commonProxyDecorator(
186-
_buildItem(context, item, index, items.length),
190+
_buildItem(context, item, index, items.length, selected),
187191
index,
188192
animation,
189193
);

‎lib/features/overwrite/overwrite_selection_sheet.dart‎

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class OverwriteSelectionSheet<T> extends ConsumerWidget {
2020
final String title;
2121
final List<OverwriteSelectionSection<T>> sections;
2222
final String Function(T item) labelBuilder;
23-
final bool Function(WidgetRef ref, T item) isSelectedOf;
23+
final T? Function(WidgetRef ref) selectedOf;
2424
final ValueChanged<T> onSelected;
2525
final double? bottomHeightFactor;
2626
final String? emptyLabel;
@@ -30,21 +30,20 @@ class OverwriteSelectionSheet<T> extends ConsumerWidget {
3030
required this.title,
3131
required this.sections,
3232
required this.labelBuilder,
33-
required this.isSelectedOf,
33+
required this.selectedOf,
3434
required this.onSelected,
3535
this.bottomHeightFactor = 0.70,
3636
this.emptyLabel,
3737
});
3838

3939
Widget _buildItem(
4040
BuildContext context,
41-
WidgetRef ref,
4241
OverwriteSelectionSection<T> section,
4342
T item,
4443
int index,
44+
bool isSelected,
4545
) {
4646
final position = ItemPosition.get(index, section.items.length);
47-
final isSelected = isSelectedOf(ref, item);
4847
return ItemPositionProvider(
4948
position: position,
5049
child: DecorationListItem(
@@ -69,31 +68,46 @@ class OverwriteSelectionSheet<T> extends ConsumerWidget {
6968
Widget build(BuildContext context, ref) {
7069
final height = ref.sheetHeight(context, (bottomHeightFactor ?? 1));
7170
final isEmpty = sections.every((section) => section.items.isEmpty);
71+
final selected = selectedOf(ref);
7272
return AdaptiveSheetScaffold(
7373
sheetTransparentToolBar: true,
7474
body: SizedBox(
7575
height: height,
7676
child: isEmpty && emptyLabel != null
7777
? NullStatus(label: emptyLabel!)
78-
: ListView(
79-
padding: const EdgeInsets.symmetric(
80-
horizontal: 16,
81-
).copyWith(bottom: 20, top: context.sheetTopPadding),
82-
children: [
78+
: CustomScrollView(
79+
slivers: [
80+
SliverToBoxAdapter(
81+
child: SizedBox(height: context.sheetTopPadding),
82+
),
8383
for (final section in sections) ...[
8484
if (section.label != null) ...[
85-
InfoHeader(info: Info(label: section.label!)),
86-
const SizedBox(height: 4),
85+
SliverPadding(
86+
padding: const EdgeInsets.symmetric(horizontal: 16),
87+
sliver: SliverToBoxAdapter(
88+
child: InfoHeader(info: Info(label: section.label!)),
89+
),
90+
),
91+
const SliverToBoxAdapter(child: SizedBox(height: 4)),
8792
],
88-
for (var index = 0; index < section.items.length; index++)
89-
_buildItem(
90-
context,
91-
ref,
92-
section,
93-
section.items[index],
94-
index,
93+
SliverPadding(
94+
padding: const EdgeInsets.symmetric(horizontal: 16),
95+
sliver: SliverList.builder(
96+
itemCount: section.items.length,
97+
itemBuilder: (context, index) {
98+
final item = section.items[index];
99+
return _buildItem(
100+
context,
101+
section,
102+
item,
103+
index,
104+
item == selected,
105+
);
106+
},
95107
),
108+
),
96109
],
110+
const SliverToBoxAdapter(child: SizedBox(height: 20)),
97111
],
98112
),
99113
),

‎lib/providers/generated/state.g.dart‎

Lines changed: 29 additions & 36 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎lib/providers/state/overwrite.dart‎

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -86,21 +86,14 @@ bool customOverwriteProxiesIsValid(
8686
}
8787

8888
@riverpod
89-
bool customOverwriteGroupIsValid(
90-
Ref ref,
91-
int profileId,
92-
ProxyGroup proxyGroup,
93-
) {
94-
final proxies = proxyGroup.proxies ?? [];
95-
final use = proxyGroup.use ?? [];
96-
final valid = ref.watch(
97-
customOverwriteDateProvider(profileId).select(
98-
(state) =>
99-
state.ruleTargets.containsAll(proxies) &&
100-
state.proxyProviders.containsAll(use),
101-
),
102-
);
103-
return valid;
89+
Set<int> invalidProxyGroupIds(Ref ref, int profileId) {
90+
final overwrite = ref.watch(customOverwriteDateProvider(profileId));
91+
return {
92+
for (final proxyGroup in overwrite.proxyGroups)
93+
if (!overwrite.ruleTargets.containsAll(proxyGroup.proxies ?? const []) ||
94+
!overwrite.proxyProviders.containsAll(proxyGroup.use ?? const []))
95+
proxyGroup.id,
96+
};
10497
}
10598

10699
@Riverpod(name: 'proxyGroupProvider')

‎lib/views/profiles/overwrite/custom/custom.dart‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class CustomContent extends ConsumerWidget {
5050
final clashConfig = state.value;
5151
return (
5252
hasGroups: clashConfig?.proxyGroups.isNotEmpty ?? false,
53-
hasRules: clashConfig?.rules.isEmpty ?? false,
53+
hasRules: clashConfig?.rules.isNotEmpty ?? false,
5454
);
5555
}),
5656
);

0 commit comments

Comments
 (0)