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 7673ade66..4facfdf9b 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt @@ -303,6 +303,7 @@ class ConfigurationFragment : ToolbarFragment(R.layout.layout_group_list), if (!select) { testPanel = TestPanelController(this, panelContainer, side = sidePanel).apply { onSelectProfile = { id -> selectProfile(id, toggleOnTv = false) } + onSorted = { groupId, id -> revealSorted(groupId, id) } onHeightChanged = { height -> if (height != panelHeight) { panelHeight = height @@ -413,6 +414,16 @@ class ConfigurationFragment : ToolbarFragment(R.layout.layout_group_list), } } + /** After a sort from the test panel: brings the group's fastest profile into view once the new order is shown. */ + private fun revealSorted(groupId: Long, profileId: Long) { + val owner = viewLifecycleOwnerLiveData.value ?: return + owner.lifecycleScope.launch { + val list = listFor(groupId) ?: return@launch + list.adapter.reload()?.join() + if (query.isEmpty() && !selection.active) list.revealProfile(profileId) + } + } + /** The navigation icon in the toolbar's colours (the white theme draws it dark, as ToolbarFragment does). */ private fun setNavigationIcon(@DrawableRes icon: Int, @StringRes description: Int) { val toolbar = toolbar ?: return diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/test/TestPanelController.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/test/TestPanelController.kt index 30b67c5c4..fbb5764ba 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/test/TestPanelController.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/test/TestPanelController.kt @@ -79,6 +79,9 @@ class TestPanelController( /** Selects a profile like a tap in the list; by default the panel selects it and reloads a running service. */ var onSelectProfile: ((profileId: Long) -> Unit)? = null + /** Called with the group and its fastest profile once a sort from the panel has been written. */ + var onSorted: ((groupId: Long, profileId: Long) -> Unit)? = null + /** Called when the panel starts to appear, and when it has gone (after sliding out). */ var onVisibilityChanged: ((visible: Boolean) -> Unit)? = null @@ -844,6 +847,7 @@ class TestPanelController( if (groupId <= 0) return val bySpeed = s.kind == TestSpec.KIND_SPEED && !s.countryMode val upload = s.speedMode == TestUiState.SPEED_MODE_UPLOAD + val fastest = s.ranking.firstOrNull()?.profileId runOnDefaultDispatcher { val sorted = if (bySpeed) { // Kept like the latency sort, so the next stored result re-sorts instead of undoing the order. @@ -855,6 +859,7 @@ class TestPanelController( onMainDispatcher { if (fragment.isAdded) { fragment.snackbar(if (sorted) R.string.test_panel_sorted else R.string.test_panel_sort_busy).show() + if (sorted && fastest != null) onSorted?.invoke(groupId, fastest) } } }