mirror of
https://github.com/openlibrecommunity/olcng.git
synced 2026-07-03 14:05:17 +02:00
Add locate FAB and scroll-to-selected server
https://github.com/2dust/v2rayNG/issues/5165
This commit is contained in:
@@ -280,4 +280,38 @@ class GroupServerFragment : BaseFragment<FragmentGroupServerBinding>(),
|
|||||||
ownerActivity.importConfigViaSub()
|
ownerActivity.importConfigViaSub()
|
||||||
binding.refreshLayout.isRefreshing = false
|
binding.refreshLayout.isRefreshing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scrolls to the currently selected server in the RecyclerView
|
||||||
|
*/
|
||||||
|
fun scrollToSelectedServer() {
|
||||||
|
val selectedGuid = MmkvManager.getSelectServer()
|
||||||
|
if (selectedGuid.isNullOrEmpty()) {
|
||||||
|
ownerActivity.toast(R.string.title_file_chooser)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the position of the selected server
|
||||||
|
val serversCache = mainViewModel.serversCache
|
||||||
|
val position = serversCache.indexOfFirst { it.guid == selectedGuid }
|
||||||
|
val recyclerView = binding.recyclerView
|
||||||
|
|
||||||
|
if (position >= 0) {
|
||||||
|
// Get the layout manager
|
||||||
|
val layoutManager = recyclerView.layoutManager as? GridLayoutManager
|
||||||
|
|
||||||
|
if (layoutManager != null) {
|
||||||
|
// Scroll to position with offset to center it on screen
|
||||||
|
// First scroll to position, then adjust to center
|
||||||
|
recyclerView.post {
|
||||||
|
layoutManager.scrollToPositionWithOffset(position, recyclerView.height / 3)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Fallback to smooth scroll if layout manager is not GridLayoutManager
|
||||||
|
recyclerView.smoothScrollToPosition(position)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ownerActivity.toast(R.string.toast_server_not_found_in_group)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -94,6 +94,7 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
|
|||||||
})
|
})
|
||||||
|
|
||||||
binding.fab.setOnClickListener { handleFabAction() }
|
binding.fab.setOnClickListener { handleFabAction() }
|
||||||
|
binding.fabLocate.setOnClickListener { locateSelectedServer() }
|
||||||
binding.layoutTest.setOnClickListener { handleLayoutTestClick() }
|
binding.layoutTest.setOnClickListener { handleLayoutTestClick() }
|
||||||
|
|
||||||
setupGroupTab()
|
setupGroupTab()
|
||||||
@@ -569,6 +570,47 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locates and scrolls to the currently selected server.
|
||||||
|
* If the selected server is in a different group, automatically switches to that group first.
|
||||||
|
*/
|
||||||
|
private fun locateSelectedServer() {
|
||||||
|
val targetSubscriptionId = mainViewModel.findSubscriptionIdBySelect()
|
||||||
|
if (targetSubscriptionId.isNullOrEmpty()) {
|
||||||
|
toast(R.string.title_file_chooser)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val targetGroupIndex = groupPagerAdapter.groups.indexOfFirst { it.id == targetSubscriptionId }
|
||||||
|
if (targetGroupIndex < 0) {
|
||||||
|
toast(R.string.toast_server_not_found_in_group)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch to target group if needed, then scroll to the server
|
||||||
|
if (binding.viewPager.currentItem != targetGroupIndex) {
|
||||||
|
binding.viewPager.setCurrentItem(targetGroupIndex, true)
|
||||||
|
binding.viewPager.postDelayed({ scrollToSelectedServer(targetGroupIndex) }, 1000)
|
||||||
|
} else {
|
||||||
|
scrollToSelectedServer(targetGroupIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scrolls to the selected server in the specified fragment.
|
||||||
|
* @param groupIndex The index of the group/fragment to scroll in
|
||||||
|
*/
|
||||||
|
private fun scrollToSelectedServer(groupIndex: Int) {
|
||||||
|
val itemId = groupPagerAdapter.getItemId(groupIndex)
|
||||||
|
val fragment = supportFragmentManager.findFragmentByTag("f$itemId") as? GroupServerFragment
|
||||||
|
|
||||||
|
if (fragment?.isAdded == true && fragment.view != null) {
|
||||||
|
fragment.scrollToSelectedServer()
|
||||||
|
} else {
|
||||||
|
toast(R.string.toast_fragment_not_available)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_BUTTON_B) {
|
if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_BUTTON_B) {
|
||||||
moveTaskToBack(false)
|
moveTaskToBack(false)
|
||||||
|
|||||||
@@ -402,6 +402,17 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
reloadServerList()
|
reloadServerList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun findSubscriptionIdBySelect(): String? {
|
||||||
|
// Get the selected server GUID
|
||||||
|
val selectedGuid = MmkvManager.getSelectServer()
|
||||||
|
if (selectedGuid.isNullOrEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val config = MmkvManager.decodeServerConfig(selectedGuid)
|
||||||
|
return config?.subscriptionId
|
||||||
|
}
|
||||||
|
|
||||||
fun onTestsFinished() {
|
fun onTestsFinished() {
|
||||||
viewModelScope.launch(Dispatchers.Default) {
|
viewModelScope.launch(Dispatchers.Default) {
|
||||||
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_AUTO_REMOVE_INVALID_AFTER_TEST)) {
|
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_AUTO_REMOVE_INVALID_AFTER_TEST)) {
|
||||||
|
|||||||
@@ -96,6 +96,18 @@
|
|||||||
android:layout_gravity="bottom|end"
|
android:layout_gravity="bottom|end"
|
||||||
android:layout_marginEnd="@dimen/padding_spacing_dp16">
|
android:layout_marginEnd="@dimen/padding_spacing_dp16">
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/fab_locate"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_marginBottom="@dimen/view_height_dp120"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/title_server"
|
||||||
|
android:focusable="true"
|
||||||
|
android:src="@android:drawable/ic_menu_mylocation"
|
||||||
|
app:layout_anchorGravity="bottom|right|end" />
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/fab"
|
android:id="@+id/fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|||||||
@@ -299,6 +299,8 @@
|
|||||||
<string name="title_update_config_count">Update %d configurations</string>
|
<string name="title_update_config_count">Update %d configurations</string>
|
||||||
<string name="title_update_subscription_result">Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped)</string>
|
<string name="title_update_subscription_result">Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped)</string>
|
||||||
<string name="title_update_subscription_no_subscription">No subscriptions</string>
|
<string name="title_update_subscription_no_subscription">No subscriptions</string>
|
||||||
|
<string name="toast_server_not_found_in_group">Selected server not found in current group</string>
|
||||||
|
<string name="toast_fragment_not_available">Unable to locate current view</string>
|
||||||
<string name="tasker_start_service">بدء الخدمة</string>
|
<string name="tasker_start_service">بدء الخدمة</string>
|
||||||
<string name="tasker_setting_confirm">تأكيد</string>
|
<string name="tasker_setting_confirm">تأكيد</string>
|
||||||
|
|
||||||
|
|||||||
@@ -298,6 +298,8 @@
|
|||||||
<string name="title_update_config_count">Update %d configurations</string>
|
<string name="title_update_config_count">Update %d configurations</string>
|
||||||
<string name="title_update_subscription_result">Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped)</string>
|
<string name="title_update_subscription_result">Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped)</string>
|
||||||
<string name="title_update_subscription_no_subscription">No subscriptions</string>
|
<string name="title_update_subscription_no_subscription">No subscriptions</string>
|
||||||
|
<string name="toast_server_not_found_in_group">Selected server not found in current group</string>
|
||||||
|
<string name="toast_fragment_not_available">Unable to locate current view</string>
|
||||||
<string name="tasker_start_service">সার্ভিস শুরু করুন</string>
|
<string name="tasker_start_service">সার্ভিস শুরু করুন</string>
|
||||||
<string name="tasker_setting_confirm">নিশ্চিত করুন</string>
|
<string name="tasker_setting_confirm">নিশ্চিত করুন</string>
|
||||||
|
|
||||||
|
|||||||
@@ -299,6 +299,8 @@
|
|||||||
<string name="title_update_config_count">ورۊ کردن %d کانفیگ</string>
|
<string name="title_update_config_count">ورۊ کردن %d کانفیگ</string>
|
||||||
<string name="title_update_subscription_result">%1$d کانفیگ ورۊ وابی (مووفق: %2$d، شکست خرده: %3$d، رڌ وابیڌه: %4$d)</string>
|
<string name="title_update_subscription_result">%1$d کانفیگ ورۊ وابی (مووفق: %2$d، شکست خرده: %3$d، رڌ وابیڌه: %4$d)</string>
|
||||||
<string name="title_update_subscription_no_subscription">بؽ اشتراک</string>
|
<string name="title_update_subscription_no_subscription">بؽ اشتراک</string>
|
||||||
|
<string name="toast_server_not_found_in_group">Selected server not found in current group</string>
|
||||||
|
<string name="toast_fragment_not_available">Unable to locate current view</string>
|
||||||
<string name="tasker_start_service">ره وندن خدمات</string>
|
<string name="tasker_start_service">ره وندن خدمات</string>
|
||||||
<string name="tasker_setting_confirm">قوۊل</string>
|
<string name="tasker_setting_confirm">قوۊل</string>
|
||||||
|
|
||||||
|
|||||||
@@ -296,6 +296,8 @@
|
|||||||
<string name="title_update_config_count">آپدیت کردن %d کانفیگ</string>
|
<string name="title_update_config_count">آپدیت کردن %d کانفیگ</string>
|
||||||
<string name="title_update_subscription_result">Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped)</string>
|
<string name="title_update_subscription_result">Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped)</string>
|
||||||
<string name="title_update_subscription_no_subscription">No subscriptions</string>
|
<string name="title_update_subscription_no_subscription">No subscriptions</string>
|
||||||
|
<string name="toast_server_not_found_in_group">Selected server not found in current group</string>
|
||||||
|
<string name="toast_fragment_not_available">Unable to locate current view</string>
|
||||||
<string name="tasker_start_service">شروع خدمات</string>
|
<string name="tasker_start_service">شروع خدمات</string>
|
||||||
<string name="tasker_setting_confirm">تایید</string>
|
<string name="tasker_setting_confirm">تایید</string>
|
||||||
|
|
||||||
|
|||||||
@@ -297,6 +297,8 @@
|
|||||||
<string name="title_update_config_count">Обновлено профилей: %d</string>
|
<string name="title_update_config_count">Обновлено профилей: %d</string>
|
||||||
<string name="title_update_subscription_result">Обновлено профилей: %1$d (успешно: %2$d, ошибок: %3$d, пропущено: %4$d)</string>
|
<string name="title_update_subscription_result">Обновлено профилей: %1$d (успешно: %2$d, ошибок: %3$d, пропущено: %4$d)</string>
|
||||||
<string name="title_update_subscription_no_subscription">Нет подписок</string>
|
<string name="title_update_subscription_no_subscription">Нет подписок</string>
|
||||||
|
<string name="toast_server_not_found_in_group">Selected server not found in current group</string>
|
||||||
|
<string name="toast_fragment_not_available">Unable to locate current view</string>
|
||||||
|
|
||||||
<string name="tasker_start_service">Запуск службы</string>
|
<string name="tasker_start_service">Запуск службы</string>
|
||||||
<string name="tasker_setting_confirm">Подтвердить</string>
|
<string name="tasker_setting_confirm">Подтвердить</string>
|
||||||
|
|||||||
@@ -299,6 +299,8 @@
|
|||||||
<string name="title_update_config_count">Update %d configurations</string>
|
<string name="title_update_config_count">Update %d configurations</string>
|
||||||
<string name="title_update_subscription_result">Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped)</string>
|
<string name="title_update_subscription_result">Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped)</string>
|
||||||
<string name="title_update_subscription_no_subscription">No subscriptions</string>
|
<string name="title_update_subscription_no_subscription">No subscriptions</string>
|
||||||
|
<string name="toast_server_not_found_in_group">Selected server not found in current group</string>
|
||||||
|
<string name="toast_fragment_not_available">Unable to locate current view</string>
|
||||||
<string name="tasker_start_service">Khởi động v2rayNG</string>
|
<string name="tasker_start_service">Khởi động v2rayNG</string>
|
||||||
<string name="tasker_setting_confirm">Xác nhận</string>
|
<string name="tasker_setting_confirm">Xác nhận</string>
|
||||||
|
|
||||||
|
|||||||
@@ -297,6 +297,8 @@
|
|||||||
<string name="title_update_config_count">更新 %d 个配置</string>
|
<string name="title_update_config_count">更新 %d 个配置</string>
|
||||||
<string name="title_update_subscription_result">更新了 %1$d 个配置(%2$d 个成功,%3$d 个失败,%4$d 个跳过)</string>
|
<string name="title_update_subscription_result">更新了 %1$d 个配置(%2$d 个成功,%3$d 个失败,%4$d 个跳过)</string>
|
||||||
<string name="title_update_subscription_no_subscription">无订阅</string>
|
<string name="title_update_subscription_no_subscription">无订阅</string>
|
||||||
|
<string name="toast_server_not_found_in_group">当前分组中未找到选中的服务器</string>
|
||||||
|
<string name="toast_fragment_not_available">无法定位当前视图</string>
|
||||||
<string name="tasker_start_service">启动服务</string>
|
<string name="tasker_start_service">启动服务</string>
|
||||||
<string name="tasker_setting_confirm">确定</string>
|
<string name="tasker_setting_confirm">确定</string>
|
||||||
|
|
||||||
|
|||||||
@@ -297,6 +297,8 @@
|
|||||||
<string name="title_update_config_count">更新 %d 個配置</string>
|
<string name="title_update_config_count">更新 %d 個配置</string>
|
||||||
<string name="title_update_subscription_result">更新了 %1$d 個配置(%2$d 個成功,%3$d 個失敗,%4$d 個跳過)</string>
|
<string name="title_update_subscription_result">更新了 %1$d 個配置(%2$d 個成功,%3$d 個失敗,%4$d 個跳過)</string>
|
||||||
<string name="title_update_subscription_no_subscription">無訂閱</string>
|
<string name="title_update_subscription_no_subscription">無訂閱</string>
|
||||||
|
<string name="toast_server_not_found_in_group">當前分組中未找到選中的伺服器</string>
|
||||||
|
<string name="toast_fragment_not_available">無法定位當前視圖</string>
|
||||||
<string name="tasker_start_service">啟動服務</string>
|
<string name="tasker_start_service">啟動服務</string>
|
||||||
<string name="tasker_setting_confirm">確定</string>
|
<string name="tasker_setting_confirm">確定</string>
|
||||||
|
|
||||||
|
|||||||
@@ -7,5 +7,6 @@
|
|||||||
<dimen name="view_height_dp36">36dp</dimen>
|
<dimen name="view_height_dp36">36dp</dimen>
|
||||||
<dimen name="view_height_dp48">48dp</dimen>
|
<dimen name="view_height_dp48">48dp</dimen>
|
||||||
<dimen name="view_height_dp64">64dp</dimen>
|
<dimen name="view_height_dp64">64dp</dimen>
|
||||||
|
<dimen name="view_height_dp120">120dp</dimen>
|
||||||
<dimen name="view_height_dp160">160dp</dimen>
|
<dimen name="view_height_dp160">160dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -303,6 +303,8 @@
|
|||||||
<string name="title_update_config_count">Update %d configs</string>
|
<string name="title_update_config_count">Update %d configs</string>
|
||||||
<string name="title_update_subscription_result">Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped)</string>
|
<string name="title_update_subscription_result">Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped)</string>
|
||||||
<string name="title_update_subscription_no_subscription">No subscriptions</string>
|
<string name="title_update_subscription_no_subscription">No subscriptions</string>
|
||||||
|
<string name="toast_server_not_found_in_group">Selected server not found in current group</string>
|
||||||
|
<string name="toast_fragment_not_available">Unable to locate current view</string>
|
||||||
|
|
||||||
<string name="tasker_start_service">Start Service</string>
|
<string name="tasker_start_service">Start Service</string>
|
||||||
<string name="tasker_setting_confirm">Confirm</string>
|
<string name="tasker_setting_confirm">Confirm</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user