diff --git a/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt b/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt index 17e544a0f..5e1e6181d 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt @@ -111,7 +111,7 @@ object RawUpdater : GroupUpdater() { val uniqueProxies = LinkedHashSet() val uniqueNames = HashMap() for (_proxy in proxies) { - val proxy = Protocols.Deduplication(_proxy) + val proxy = Protocols.Deduplication(_proxy, _proxy.javaClass.toString()) if (!uniqueProxies.add(proxy)) { val index = uniqueProxies.indexOf(proxy) if (uniqueNames.containsKey(proxy)) { diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt index 01e872a62..4905d1911 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt @@ -501,7 +501,57 @@ class ConfigurationFragment @JvmOverloads constructor( } } } - + R.id.action_remove_duplicate -> { + runOnDefaultDispatcher { + val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId()) + val toClear = mutableListOf() + val uniqueProxies = LinkedHashSet() + for (pf in profiles) { + val proxy = Protocols.Deduplication(pf.requireBean(), pf.displayType()) + if (!uniqueProxies.add(proxy)) { + toClear += pf + } + } + if (toClear.isNotEmpty()) { + onMainDispatcher { + MaterialAlertDialogBuilder(requireContext()).setTitle(R.string.confirm) + .setMessage( + getString(R.string.delete_confirm_prompt) + "\n" + + toClear.mapIndexedNotNull { index, proxyEntity -> + if (index < 20) { + proxyEntity.displayName() + } else if (index == 20) { + "......" + } else { + null + } + }.joinToString("\n") + ) + .setPositiveButton(R.string.yes) { _, _ -> + for (profile in toClear) { + adapter.groupFragments[DataStore.selectedGroup]?.adapter?.apply { + val index = configurationIdList.indexOf(profile.id) + if (index >= 0) { + configurationIdList.removeAt(index) + configurationList.remove(profile.id) + notifyItemRemoved(index) + } + } + } + runOnDefaultDispatcher { + for (profile in toClear) { + ProfileManager.deleteProfile2( + profile.groupId, profile.id + ) + } + } + } + .setNegativeButton(R.string.no, null) + .show() + } + } + } + } R.id.action_connection_icmp_ping -> { pingTest(true) } diff --git a/app/src/main/java/moe/matsuri/nya/Protocols.kt b/app/src/main/java/moe/matsuri/nya/Protocols.kt index 7e7e40e9a..db7d61d6b 100644 --- a/app/src/main/java/moe/matsuri/nya/Protocols.kt +++ b/app/src/main/java/moe/matsuri/nya/Protocols.kt @@ -33,11 +33,11 @@ object Protocols { // Deduplication class Deduplication( - val bean: AbstractBean + val bean: AbstractBean, val type: String ) { fun hash(): String { - return bean.serverAddress + bean.serverPort + return bean.serverAddress + bean.serverPort + type } override fun hashCode(): Int { diff --git a/app/src/main/res/menu/add_profile_menu.xml b/app/src/main/res/menu/add_profile_menu.xml index e7111eb3a..955413178 100644 --- a/app/src/main/res/menu/add_profile_menu.xml +++ b/app/src/main/res/menu/add_profile_menu.xml @@ -80,6 +80,9 @@ + diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index b6efc7867..6dce70484 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -484,4 +484,5 @@ 分享订阅 在通知中显示组名 重置连接 + 删除重复的服务器 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index abe1ca201..631ec97cb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -524,5 +524,6 @@ Anyone can write advanced plugins, which can control Matsuri. please download an Share Subscription Show group name in in notification Reset Connections + Remove duplicate servers \ No newline at end of file