From caff51eaf19de795aac24b3bcc8d4dcf297894a6 Mon Sep 17 00:00:00 2001 From: Fasdeq13 Date: Sat, 14 Nov 2026 23:53:09 +0300 Subject: [PATCH 1/8] Update SelectionMode.kt --- .../nekohasekai/sagernet/ui/profiles/SelectionMode.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/profiles/SelectionMode.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/profiles/SelectionMode.kt index e2f7c7ef..05d0c118 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/profiles/SelectionMode.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/profiles/SelectionMode.kt @@ -123,6 +123,16 @@ class SelectionMode(private val host: ConfigurationFragment) { refreshPinTitle() } + private fun invertSelection() { + val shown = host.listFor(groupId)?.adapter?.displayedIds ?: return + for (id in shown) { + if (!checked.remove(id)) checked.add(id) + } + if (checked.isEmpty()) return finish() + host.onSelectionChanged(null) + refreshPinTitle() + } + /** Every checked profile is pinned, so the action unpins (refresh_pin_action). */ private fun allPinned(): Boolean { val adapter = host.listFor(groupId)?.adapter ?: return false @@ -155,6 +165,7 @@ class SelectionMode(private val host: ConfigurationFragment) { } R.id.action_selection_all -> selectAll() + R.id.action_selection_invert -> invertSelection() R.id.action_selection_delete -> delete(ids) R.id.action_selection_pin -> pin(ids) R.id.action_selection_clear_results -> clearResults(ids) From 0f4a49ed2c2fa3eb252e480bca4fdc3481bbbd78 Mon Sep 17 00:00:00 2001 From: Fasdeq13 Date: Sat, 14 Nov 2026 23:53:31 +0300 Subject: [PATCH 2/8] Update profile_selection_menu.xml --- app/src/main/res/menu/profile_selection_menu.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/res/menu/profile_selection_menu.xml b/app/src/main/res/menu/profile_selection_menu.xml index 74e99f3f..16448b10 100644 --- a/app/src/main/res/menu/profile_selection_menu.xml +++ b/app/src/main/res/menu/profile_selection_menu.xml @@ -33,6 +33,10 @@ android:id="@+id/action_selection_all" android:title="@string/profiles_select_all" app:showAsAction="never" /> + Date: Sat, 14 Nov 2026 23:53:52 +0300 Subject: [PATCH 3/8] Update strings.xml --- app/src/main/res/values/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8b6872e7..6a43e30e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1302,6 +1302,7 @@ %d selected Select all + Invert selection Move to group There is no other basic group to move to. From 9b722e2776c6f730471d7d1ec6512b6bdfd4ddc5 Mon Sep 17 00:00:00 2001 From: Fasdeq13 Date: Sat, 14 Nov 2026 23:54:14 +0300 Subject: [PATCH 4/8] Update strings.xml --- app/src/main/res/values-ru/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 9cdeb915..0bd1fcca 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -975,6 +975,7 @@ Разрешить домен Работающий профиль сохранён. Выбрать все + Инвертировать выбор Показать Внешний IP Скорость From 0b3f989750fe16dfb174170692231aa3d48bc878 Mon Sep 17 00:00:00 2001 From: Fasdeq13 Date: Sun, 15 Nov 2026 20:56:08 +0300 Subject: [PATCH 5/8] Add resolve and clearTraffic functions in SelectionMode --- .../sagernet/ui/profiles/SelectionMode.kt | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/profiles/SelectionMode.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/profiles/SelectionMode.kt index 05d0c118..3933e973 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/profiles/SelectionMode.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/profiles/SelectionMode.kt @@ -10,11 +10,14 @@ import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.GroupRepo import io.nekohasekai.sagernet.database.ProfileManager import io.nekohasekai.sagernet.database.ProxyEntity +import io.nekohasekai.sagernet.group.SubscriptionClient +import io.nekohasekai.sagernet.ktx.Logs import io.nekohasekai.sagernet.ktx.confirmAction import io.nekohasekai.sagernet.ktx.nameList import io.nekohasekai.sagernet.ktx.showAllowingStateLoss import io.nekohasekai.sagernet.ktx.snackbar import io.nekohasekai.sagernet.ui.ConfigurationFragment +import io.nekohasekai.sagernet.ui.MainActivity import io.nekohasekai.sagernet.widget.QRCodeDialog /** @@ -169,6 +172,8 @@ class SelectionMode(private val host: ConfigurationFragment) { R.id.action_selection_delete -> delete(ids) R.id.action_selection_pin -> pin(ids) R.id.action_selection_clear_results -> clearResults(ids) + R.id.action_selection_resolve_domain -> resolve(ids) + R.id.action_selection_clear_traffic -> clearTraffic(ids) R.id.action_selection_move -> moveToGroup(ids) R.id.action_selection_copy_links -> copyLinks(ids, throne = false) R.id.action_selection_copy_throne -> copyLinks(ids, throne = true) @@ -210,6 +215,35 @@ class SelectionMode(private val host: ConfigurationFragment) { } } + private fun resolve(ids: List) { + if (ids.isEmpty()) return + val gid = groupId + finish() + host.launchIo { + val report = SubscriptionClient.resolveProfiles(gid, ids) + if (report.isNotBlank()) host.onUi { snackbar(report).show() } + } + } + + private fun clearTraffic(ids: List) { + val gid = groupId + confirm(ids, host.getString(R.string.confirm_clear_traffic), R.string.confirm_clear) { + val service = (host.activity as? MainActivity)?.connection?.service + val adapter = host.listFor(gid)?.adapter + finish() + ids.forEach { adapter?.clearTraffic(it) } + host.launchIo { + val array = ids.toLongArray() + try { + service?.resetTraffic(array) + } catch (e: Exception) { + Logs.w(e) + } + ProfileManager.resetTraffic(array) + } + } + } + /** [title] above the names of [ids] in list order. */ private fun confirm(ids: List, title: String, @StringRes action: Int, run: () -> Unit) { host.launchIo { From 3f953e9b19c45566a39d794cbc5aa2a5440b083f Mon Sep 17 00:00:00 2001 From: Fasdeq13 Date: Sun, 15 Nov 2026 20:56:38 +0300 Subject: [PATCH 6/8] Add new menu items for domain resolution and traffic clear --- app/src/main/res/menu/profile_selection_menu.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/res/menu/profile_selection_menu.xml b/app/src/main/res/menu/profile_selection_menu.xml index 16448b10..7980aec2 100644 --- a/app/src/main/res/menu/profile_selection_menu.xml +++ b/app/src/main/res/menu/profile_selection_menu.xml @@ -45,6 +45,14 @@ android:id="@+id/action_selection_clear_results" android:title="@string/connection_test_clear_results" app:showAsAction="never" /> + + Date: Sun, 15 Nov 2026 20:57:33 +0300 Subject: [PATCH 7/8] Fix missing newline at end of SelectionMode.kt Add missing newline at the end of SelectionMode.kt From b2a3eca76c3aabbc86f21c87d3598e01eb09ee56 Mon Sep 17 00:00:00 2001 From: Fasdeq13 Date: Sun, 15 Nov 2026 20:57:53 +0300 Subject: [PATCH 8/8] Add newline at end of profile_selection_menu.xml Fix missing newline at the end of profile_selection_menu.xml