cache
This commit is contained in:
@@ -28,7 +28,7 @@ class RuleItem extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CommonSelectedListItem(
|
||||
return SelectedDecorationListItem(
|
||||
isSelected: isSelected,
|
||||
onSelected: () {
|
||||
onSelected();
|
||||
|
||||
@@ -117,124 +117,3 @@ class _CustomContent extends ConsumerWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _CustomRulesView extends ConsumerStatefulWidget {
|
||||
final int profileId;
|
||||
|
||||
const _CustomRulesView(this.profileId);
|
||||
|
||||
@override
|
||||
ConsumerState createState() => _CustomRulesViewState();
|
||||
}
|
||||
|
||||
class _CustomRulesViewState extends ConsumerState<_CustomRulesView> {
|
||||
final _key = utils.id;
|
||||
|
||||
int get _profileId => widget.profileId;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
void _handleReorder(int oldIndex, int newIndex) {
|
||||
ref
|
||||
.read(profileCustomRulesProvider(_profileId).notifier)
|
||||
.order(oldIndex, newIndex);
|
||||
}
|
||||
|
||||
void _handleSelected(int ruleId) {
|
||||
ref.read(itemsProvider(_key).notifier).update((selectedRules) {
|
||||
final newSelectedRules = Set<int>.from(selectedRules)
|
||||
..addOrRemove(ruleId);
|
||||
return newSelectedRules;
|
||||
});
|
||||
}
|
||||
|
||||
void _handleSelectAll() {
|
||||
final ids =
|
||||
ref
|
||||
.read(profileCustomRulesProvider(_profileId))
|
||||
.value
|
||||
?.map((item) => item.id)
|
||||
.toSet() ??
|
||||
{};
|
||||
ref.read(itemsProvider(_key).notifier).update((selected) {
|
||||
return selected.containsAll(ids) ? {} : ids;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _handleDelete() async {
|
||||
final res = await globalState.showMessage(
|
||||
title: appLocalizations.tip,
|
||||
message: TextSpan(
|
||||
text: appLocalizations.deleteMultipTip(appLocalizations.rule),
|
||||
),
|
||||
);
|
||||
if (res != true) {
|
||||
return;
|
||||
}
|
||||
final selectedRules = ref.read(itemsProvider(_key));
|
||||
ref
|
||||
.read(profileCustomRulesProvider(_profileId).notifier)
|
||||
.delAll(selectedRules.cast<int>());
|
||||
ref.read(itemsProvider(_key).notifier).value = {};
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(context) {
|
||||
final rules = ref.watch(profileCustomRulesProvider(_profileId)).value ?? [];
|
||||
final selectedRules = ref.watch(itemsProvider(_key));
|
||||
return CommonScaffold(
|
||||
title: appLocalizations.rule,
|
||||
actions: [
|
||||
if (selectedRules.isNotEmpty) ...[
|
||||
CommonMinIconButtonTheme(
|
||||
child: IconButton.filledTonal(
|
||||
onPressed: _handleDelete,
|
||||
icon: Icon(Icons.delete),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 2),
|
||||
],
|
||||
CommonMinFilledButtonTheme(
|
||||
child: selectedRules.isNotEmpty
|
||||
? FilledButton(
|
||||
onPressed: _handleSelectAll,
|
||||
child: Text(appLocalizations.selectAll),
|
||||
)
|
||||
: FilledButton.tonal(
|
||||
onPressed: () {
|
||||
// _handleAddOrUpdate();
|
||||
},
|
||||
child: Text(appLocalizations.add),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
],
|
||||
body: ReorderableListView.builder(
|
||||
buildDefaultDragHandles: false,
|
||||
itemBuilder: (_, index) {
|
||||
final rule = rules[index];
|
||||
return ReorderableDelayedDragStartListener(
|
||||
key: ObjectKey(rule),
|
||||
index: index,
|
||||
child: RuleItem(
|
||||
isEditing: selectedRules.isNotEmpty,
|
||||
isSelected: selectedRules.contains(rule.id),
|
||||
rule: rule,
|
||||
onSelected: () {
|
||||
_handleSelected(rule.id);
|
||||
},
|
||||
onEdit: (rule) {
|
||||
// _handleAddOrUpdate(rule);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
itemCount: rules.length,
|
||||
onReorder: _handleReorder,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,12 +330,20 @@ class _EditProxyGroupViewState extends ConsumerState<_EditProxyGroupView> {
|
||||
);
|
||||
}
|
||||
|
||||
void _handleChangeName(String value) {
|
||||
ref
|
||||
.read(proxyGroupProvider.notifier)
|
||||
.update((state) => state.copyWith(name: value));
|
||||
}
|
||||
|
||||
Widget _buildNameItem(String name) {
|
||||
return _buildItem(
|
||||
title: Text('名称'),
|
||||
trailing: TextFormField(
|
||||
initialValue: name,
|
||||
onChanged: (value) {},
|
||||
onChanged: (value) {
|
||||
_handleChangeName(value);
|
||||
},
|
||||
textAlign: TextAlign.end,
|
||||
decoration: InputDecoration.collapsed(
|
||||
border: NoInputBorder(),
|
||||
@@ -385,6 +393,8 @@ class _EditProxyGroupViewState extends ConsumerState<_EditProxyGroupView> {
|
||||
);
|
||||
}
|
||||
|
||||
void _handleDelete() {}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isBottomSheet =
|
||||
@@ -506,7 +516,17 @@ class _EditProxyGroupViewState extends ConsumerState<_EditProxyGroupView> {
|
||||
),
|
||||
generateSectionV3(
|
||||
title: '操作',
|
||||
items: [_buildItem(title: Text('删除'), onPressed: () {})],
|
||||
items: [
|
||||
_buildItem(
|
||||
title: Text(
|
||||
'删除',
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
color: context.colorScheme.error,
|
||||
),
|
||||
),
|
||||
onPressed: _handleDelete,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -523,9 +543,8 @@ class _EditProxiesView extends ConsumerStatefulWidget {
|
||||
ConsumerState<_EditProxiesView> createState() => _EditProxiesViewState();
|
||||
}
|
||||
|
||||
class _EditProxiesViewState extends ConsumerState<_EditProxiesView> {
|
||||
final _dismissItemController = ValueNotifier<String?>(null);
|
||||
|
||||
class _EditProxiesViewState extends ConsumerState<_EditProxiesView>
|
||||
with UniqueKeyStateMixin {
|
||||
void _handleToAddProxiesView() {
|
||||
Navigator.of(
|
||||
context,
|
||||
@@ -538,10 +557,11 @@ class _EditProxiesViewState extends ConsumerState<_EditProxiesView> {
|
||||
}
|
||||
|
||||
void _handleRemove(String proxyName) {
|
||||
if (_dismissItemController.value != null) {
|
||||
final dismissItem = ref.read(itemProvider(key));
|
||||
if (dismissItem != null) {
|
||||
return;
|
||||
}
|
||||
_dismissItemController.value = proxyName;
|
||||
ref.read(itemProvider(key).notifier).value = proxyName;
|
||||
}
|
||||
|
||||
void _handleRealRemove(String proxyName) {
|
||||
@@ -551,7 +571,7 @@ class _EditProxiesViewState extends ConsumerState<_EditProxiesView> {
|
||||
return state.copyWith(proxies: newProxies);
|
||||
});
|
||||
if (mounted) {
|
||||
_dismissItemController.value = null;
|
||||
ref.read(itemProvider(key).notifier).value = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -633,6 +653,7 @@ class _EditProxiesViewState extends ConsumerState<_EditProxiesView> {
|
||||
(state) => VM2(state.includeAllProxies ?? false, state.proxies ?? []),
|
||||
),
|
||||
);
|
||||
final dismissItem = ref.watch(itemProvider(key));
|
||||
final includeAllProxies = vm2.a;
|
||||
final proxyNames = vm2.b;
|
||||
final proxyTypeMap =
|
||||
@@ -692,32 +713,30 @@ class _EditProxiesViewState extends ConsumerState<_EditProxiesView> {
|
||||
),
|
||||
),
|
||||
),
|
||||
ValueListenableBuilder(
|
||||
valueListenable: _dismissItemController,
|
||||
builder: (_, dismissItem, _) {
|
||||
return SliverReorderableList(
|
||||
findChildIndexCallback: (Key key) {
|
||||
final String keyValue = (key as dynamic).subKey?.value;
|
||||
final index = proxyNames.indexOf(keyValue);
|
||||
return index;
|
||||
},
|
||||
itemBuilder: (_, index) {
|
||||
final proxyName = proxyNames[index];
|
||||
return _buildItem(
|
||||
dismiss: dismissItem == proxyName,
|
||||
proxyName: proxyName,
|
||||
proxyType: proxyTypeMap[proxyName],
|
||||
index: index,
|
||||
length: proxyNames.length,
|
||||
);
|
||||
},
|
||||
itemCount: proxyNames.length,
|
||||
onReorder: (int oldIndex, int newIndex) {
|
||||
_handleReorder(oldIndex, newIndex);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
if (proxyNames.isNotEmpty)
|
||||
SliverReorderableList(
|
||||
findChildIndexCallback: (Key key) {
|
||||
final String keyValue = (key as dynamic).subKey?.value;
|
||||
final index = proxyNames.indexOf(keyValue);
|
||||
return index;
|
||||
},
|
||||
itemBuilder: (_, index) {
|
||||
final proxyName = proxyNames[index];
|
||||
return _buildItem(
|
||||
dismiss: dismissItem == proxyName,
|
||||
proxyName: proxyName,
|
||||
proxyType: proxyTypeMap[proxyName],
|
||||
index: index,
|
||||
length: proxyNames.length,
|
||||
);
|
||||
},
|
||||
itemCount: proxyNames.length,
|
||||
onReorder: (int oldIndex, int newIndex) {
|
||||
_handleReorder(oldIndex, newIndex);
|
||||
},
|
||||
)
|
||||
else
|
||||
SliverFillRemaining(child: NullStatus(label: '代理为空')),
|
||||
SliverToBoxAdapter(child: SizedBox(height: 16)),
|
||||
],
|
||||
),
|
||||
@@ -817,66 +836,74 @@ class _AddProxiesViewState extends ConsumerState<_AddProxiesView>
|
||||
child: AdaptiveSheetScaffold(
|
||||
sheetTransparentToolBar: true,
|
||||
title: '添加代理',
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
SliverToBoxAdapter(
|
||||
child: SizedBox(height: context.sheetTopPadding),
|
||||
),
|
||||
if (proxyGroups.isNotEmpty) ...[
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: InfoHeader(info: Info(label: '策略组')),
|
||||
),
|
||||
body: proxies.isEmpty && proxyGroups.isEmpty
|
||||
? NullStatus(label: appLocalizations.noData)
|
||||
: CustomScrollView(
|
||||
slivers: [
|
||||
SliverToBoxAdapter(
|
||||
child: SizedBox(height: context.sheetTopPadding),
|
||||
),
|
||||
if (proxyGroups.isNotEmpty) ...[
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: InfoHeader(info: Info(label: '策略组')),
|
||||
),
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate((_, index) {
|
||||
final proxyGroup = proxyGroups[index];
|
||||
final position = ItemPosition.get(
|
||||
index,
|
||||
proxyGroups.length,
|
||||
);
|
||||
return _buildItem(
|
||||
title: proxyGroup.name,
|
||||
subtitle: proxyGroup.type.value,
|
||||
position: position,
|
||||
dismiss: dismissItem == proxyGroup.name,
|
||||
onAdd: () {
|
||||
_handleAdd(proxyGroup.name);
|
||||
},
|
||||
onDismissed: () {
|
||||
_handleRealAdd(proxyGroup.name);
|
||||
},
|
||||
);
|
||||
}, childCount: proxyGroups.length),
|
||||
),
|
||||
SliverToBoxAdapter(child: SizedBox(height: 8)),
|
||||
],
|
||||
if (proxies.isNotEmpty) ...[
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: InfoHeader(info: Info(label: '代理')),
|
||||
),
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate((_, index) {
|
||||
final proxy = proxies[index];
|
||||
final position = ItemPosition.get(
|
||||
index,
|
||||
proxies.length,
|
||||
);
|
||||
return _buildItem(
|
||||
title: proxy.name,
|
||||
subtitle: proxy.type,
|
||||
position: position,
|
||||
dismiss: dismissItem == proxy.name,
|
||||
onAdd: () {
|
||||
_handleAdd(proxy.name);
|
||||
},
|
||||
onDismissed: () {
|
||||
_handleRealAdd(proxy.name);
|
||||
},
|
||||
);
|
||||
}, childCount: proxies.length),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate((_, index) {
|
||||
final proxyGroup = proxyGroups[index];
|
||||
final position = ItemPosition.get(index, proxyGroups.length);
|
||||
return _buildItem(
|
||||
title: proxyGroup.name,
|
||||
subtitle: proxyGroup.type.value,
|
||||
position: position,
|
||||
dismiss: dismissItem == proxyGroup.name,
|
||||
onAdd: () {
|
||||
_handleAdd(proxyGroup.name);
|
||||
},
|
||||
onDismissed: () {
|
||||
_handleRealAdd(proxyGroup.name);
|
||||
},
|
||||
);
|
||||
}, childCount: proxyGroups.length),
|
||||
),
|
||||
SliverToBoxAdapter(child: SizedBox(height: 8)),
|
||||
],
|
||||
if (proxies.isNotEmpty) ...[
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: InfoHeader(info: Info(label: '代理')),
|
||||
),
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate((_, index) {
|
||||
final proxy = proxies[index];
|
||||
final position = ItemPosition.get(index, proxies.length);
|
||||
return _buildItem(
|
||||
title: proxy.name,
|
||||
subtitle: proxy.type,
|
||||
position: position,
|
||||
dismiss: dismissItem == proxy.name,
|
||||
onAdd: () {
|
||||
_handleAdd(proxy.name);
|
||||
},
|
||||
onDismissed: () {
|
||||
_handleRealAdd(proxy.name);
|
||||
},
|
||||
);
|
||||
}, childCount: proxies.length),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
127
lib/views/profiles/overwrite/custom_rules.dart
Normal file
127
lib/views/profiles/overwrite/custom_rules.dart
Normal file
@@ -0,0 +1,127 @@
|
||||
part of 'overwrite.dart';
|
||||
|
||||
class _CustomRulesView extends ConsumerStatefulWidget {
|
||||
final int profileId;
|
||||
|
||||
const _CustomRulesView(this.profileId);
|
||||
|
||||
@override
|
||||
ConsumerState createState() => _CustomRulesViewState();
|
||||
}
|
||||
|
||||
class _CustomRulesViewState extends ConsumerState<_CustomRulesView>
|
||||
with UniqueKeyStateMixin {
|
||||
int get _profileId => widget.profileId;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
void _handleReorder(int oldIndex, int newIndex) {
|
||||
ref
|
||||
.read(profileCustomRulesProvider(_profileId).notifier)
|
||||
.order(oldIndex, newIndex);
|
||||
}
|
||||
|
||||
void _handleSelected(int ruleId) {
|
||||
ref.read(itemsProvider(key).notifier).update((selectedRules) {
|
||||
final newSelectedRules = Set<int>.from(selectedRules)
|
||||
..addOrRemove(ruleId);
|
||||
return newSelectedRules;
|
||||
});
|
||||
}
|
||||
|
||||
void _handleSelectAll() {
|
||||
final ids =
|
||||
ref
|
||||
.read(profileCustomRulesProvider(_profileId))
|
||||
.value
|
||||
?.map((item) => item.id)
|
||||
.toSet() ??
|
||||
{};
|
||||
ref.read(itemsProvider(key).notifier).update((selected) {
|
||||
return selected.containsAll(ids) ? {} : ids;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _handleDelete() async {
|
||||
final res = await globalState.showMessage(
|
||||
title: appLocalizations.tip,
|
||||
message: TextSpan(
|
||||
text: appLocalizations.deleteMultipTip(appLocalizations.rule),
|
||||
),
|
||||
);
|
||||
if (res != true) {
|
||||
return;
|
||||
}
|
||||
final selectedRules = ref.read(itemsProvider(key));
|
||||
ref
|
||||
.read(profileCustomRulesProvider(_profileId).notifier)
|
||||
.delAll(selectedRules.cast<int>());
|
||||
ref.read(itemsProvider(key).notifier).value = {};
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(context) {
|
||||
final rules = ref.watch(profileCustomRulesProvider(_profileId)).value ?? [];
|
||||
final selectedRules = ref.watch(itemsProvider(key));
|
||||
return CommonScaffold(
|
||||
title: appLocalizations.rule,
|
||||
actions: [
|
||||
if (selectedRules.isNotEmpty) ...[
|
||||
CommonMinIconButtonTheme(
|
||||
child: IconButton.filledTonal(
|
||||
onPressed: _handleDelete,
|
||||
icon: Icon(Icons.delete),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 2),
|
||||
],
|
||||
CommonMinFilledButtonTheme(
|
||||
child: selectedRules.isNotEmpty
|
||||
? FilledButton(
|
||||
onPressed: _handleSelectAll,
|
||||
child: Text(appLocalizations.selectAll),
|
||||
)
|
||||
: FilledButton.tonal(
|
||||
onPressed: () {
|
||||
// _handleAddOrUpdate();
|
||||
},
|
||||
child: Text(appLocalizations.add),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
],
|
||||
body: ReorderableListView.builder(
|
||||
buildDefaultDragHandles: false,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
itemBuilder: (_, index) {
|
||||
final rule = rules[index];
|
||||
final position = ItemPosition.get(index, rules.length);
|
||||
return ReorderableDelayedDragStartListener(
|
||||
key: ValueKey(rule),
|
||||
index: index,
|
||||
child: ItemPositionProvider(
|
||||
position: position,
|
||||
child: RuleItem(
|
||||
isEditing: selectedRules.isNotEmpty,
|
||||
isSelected: selectedRules.contains(rule.id),
|
||||
rule: rule,
|
||||
onSelected: () {
|
||||
_handleSelected(rule.id);
|
||||
},
|
||||
onEdit: (rule) {
|
||||
// _handleAddOrUpdate(rule);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
itemExtent: globalState.measure.bodyMediumHeight * 2 + 12,
|
||||
itemCount: rules.length,
|
||||
onReorder: _handleReorder,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import 'package:smooth_sheets/smooth_sheets.dart';
|
||||
|
||||
part 'custom.dart';
|
||||
part 'custom_groups.dart';
|
||||
part 'custom_rules.dart';
|
||||
part 'script.dart';
|
||||
part 'standard.dart';
|
||||
part 'widgets.dart';
|
||||
|
||||
Reference in New Issue
Block a user