refactor(main): unify UI interactions with MainAction dispatcher
Refactored MainActivity and its Compose UI components to use a single onAction: (MainAction) -> Unit callback. This significantly simplifies component signatures and centralizes interaction logic. - Updated MainContract.kt to include all UI-triggered actions. - Modified MainScreen and sub-components (TopBar, BottomBar, Drawer, etc.) to use the unified onAction dispatcher. - Implemented a centralized action handler in MainActivity to dispatch between ViewModel and Activity-specific tasks. - Removed redundant ImportConfigViaSub action. - Moved QR code generation state into MainUiState for MVI consistency. This change reduces parameter drilling and improves maintainability of the main interface.
This commit is contained in:
1 parent
ccadd5453a
commit
4b903cf5e0
9 files changed
+123
-161
No files matched your search
@@ -2,7 +2,6 @@ package com.v2ray.ang.ui.main
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.net.VpnService
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@@ -103,40 +102,33 @@ class MainActivity : HelperBaseComponentActivity() {
|
||||
override fun ScreenContent() {
|
||||
MainScreen(
|
||||
mainViewModel = mainViewModel,
|
||||
onFabClick = ::handleFabAction,
|
||||
onTestClick = ::handleLayoutTestClick,
|
||||
onNavigate = ::navigateTo,
|
||||
onImportManually = ::importManually,
|
||||
onImportQRcode = ::importQRcode,
|
||||
onImportClipboard = ::importClipboard,
|
||||
onImportLocal = ::importConfigLocal,
|
||||
onSubUpdate = ::importConfigViaSub,
|
||||
onExportAll = { mainViewModel.onAction(MainAction.ExportAll) },
|
||||
onRealPingAll = { mainViewModel.onAction(MainAction.TestAllServers) },
|
||||
onRestartService = ::restartV2Ray,
|
||||
onDelAllConfig = { mainViewModel.onAction(MainAction.RemoveAllServers) },
|
||||
onDelDuplicateConfig = { mainViewModel.onAction(MainAction.RemoveDuplicateServers) },
|
||||
onDelInvalidConfig = { mainViewModel.onAction(MainAction.RemoveInvalidServers) },
|
||||
onSortByTestResults = { mainViewModel.onAction(MainAction.SortByTestResults) },
|
||||
onEditServer = ::editServer,
|
||||
onRemoveServer = { guid -> mainViewModel.onAction(MainAction.RemoveServer(guid)) },
|
||||
onSelectServer = ::setSelectServer,
|
||||
onShareQRCode = ::getShareQRCodeBitmap,
|
||||
onShareClipboard = ::shareToClipboard,
|
||||
onShareFullContent = ::shareFullContentAsync,
|
||||
onSubscriptionIdChanged = { id -> mainViewModel.onAction(MainAction.SelectGroup(id)) },
|
||||
onLocateSelectedServer = { mainViewModel.triggerLocateSelectedServer() },
|
||||
onAction = { action ->
|
||||
when (action) {
|
||||
MainAction.ToggleService -> handleFabAction()
|
||||
MainAction.TestCurrentServer -> handleLayoutTestClick()
|
||||
MainAction.ImportQRcode -> importQRcode()
|
||||
MainAction.ImportClipboard -> importClipboard()
|
||||
MainAction.ImportConfigLocal -> importConfigLocal()
|
||||
is MainAction.ImportManually -> importManually(action.type)
|
||||
MainAction.RestartService -> restartV2Ray()
|
||||
MainAction.LocateSelectedServer -> mainViewModel.triggerLocateSelectedServer()
|
||||
is MainAction.SelectServer -> setSelectServer(action.guid)
|
||||
is MainAction.EditServer -> editServer(action.guid, action.profile)
|
||||
is MainAction.ShareClipboard -> shareToClipboard(action.guid)
|
||||
is MainAction.ShareFullContent -> shareFullContentAsync(action.guid)
|
||||
else -> mainViewModel.onAction(action)
|
||||
}
|
||||
},
|
||||
onNavigate = { route -> navigateTo(route) },
|
||||
shareMethodEntries = resources.getStringArray(R.array.share_method).toList(),
|
||||
shareMethodMoreEntries = resources.getStringArray(R.array.share_method_more).toList()
|
||||
)
|
||||
}
|
||||
|
||||
fun getShareQRCodeBitmap(guid: String): Bitmap? = AngConfigManager.share2QRCode(guid)
|
||||
|
||||
fun shareToClipboard(guid: String): Boolean =
|
||||
private fun shareToClipboard(guid: String): Boolean =
|
||||
AngConfigManager.share2Clipboard(this, guid) == 0
|
||||
|
||||
fun shareFullContentAsync(guid: String) {
|
||||
private fun shareFullContentAsync(guid: String) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val result = AngConfigManager.shareFullContent2Clipboard(this@MainActivity, guid)
|
||||
withContext(Dispatchers.Main) {
|
||||
@@ -258,10 +250,6 @@ class MainActivity : HelperBaseComponentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun importConfigViaSub() {
|
||||
mainViewModel.onAction(MainAction.ImportConfigViaSub)
|
||||
}
|
||||
|
||||
private fun editServer(guid: String, profile: ProfileItem) {
|
||||
val activityClass = when (profile.configType) {
|
||||
EConfigType.CUSTOM -> ServerCustomConfigActivity::class.java
|
||||
|
||||
@@ -36,8 +36,7 @@ fun MainBottomBar(
|
||||
displayText: String,
|
||||
isRunning: Boolean,
|
||||
isDarkTheme: Boolean,
|
||||
onTestClick: () -> Unit,
|
||||
onFabClick: () -> Unit
|
||||
onAction: (MainAction) -> Unit
|
||||
) {
|
||||
Box(modifier = Modifier.fillMaxWidth()) {
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
@@ -47,7 +46,7 @@ fun MainBottomBar(
|
||||
.fillMaxWidth()
|
||||
.windowInsetsPadding(WindowInsets.navigationBars)
|
||||
.height(64.dp)
|
||||
.clickable(onClick = onTestClick),
|
||||
.clickable(onClick = { onAction(MainAction.TestCurrentServer) }),
|
||||
color = MaterialTheme.colorScheme.surface,
|
||||
tonalElevation = 0.dp
|
||||
) {
|
||||
@@ -63,7 +62,7 @@ fun MainBottomBar(
|
||||
}
|
||||
}
|
||||
FloatingActionButton(
|
||||
onClick = onFabClick,
|
||||
onClick = { onAction(MainAction.ToggleService) },
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(end = 24.dp)
|
||||
|
||||
@@ -15,7 +15,8 @@ data class MainUiState(
|
||||
val statusText: String = "",
|
||||
val locateTarget: LocateTarget? = null,
|
||||
val confirmRemove: Boolean = false,
|
||||
val doubleColumnDisplay: Boolean = false
|
||||
val doubleColumnDisplay: Boolean = false,
|
||||
val shareQRCodeBitmap: android.graphics.Bitmap? = null
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -34,15 +35,27 @@ sealed interface MainAction {
|
||||
data object SortByTestResults : MainAction
|
||||
data object UpdateSubscriptions : MainAction
|
||||
data object ExportAll : MainAction
|
||||
data object ImportConfigViaSub : MainAction
|
||||
|
||||
data object ImportQRcode : MainAction
|
||||
data object ImportClipboard : MainAction
|
||||
data object ImportConfigLocal : MainAction
|
||||
data class ImportManually(val type: Int) : MainAction
|
||||
data object RestartService : MainAction
|
||||
data object LocateSelectedServer : MainAction
|
||||
|
||||
data class SelectGroup(val groupId: String) : MainAction
|
||||
data class SelectServer(val guid: String) : MainAction
|
||||
data class RemoveServer(val guid: String) : MainAction
|
||||
data class EditServer(val guid: String, val profile: com.v2ray.ang.dto.entities.ProfileItem) : MainAction
|
||||
data class Search(val query: String) : MainAction
|
||||
data class SwapServer(val fromIndex: Int, val toIndex: Int) : MainAction
|
||||
|
||||
data class ShareQRCode(val guid: String) : MainAction
|
||||
data class ShareClipboard(val guid: String) : MainAction
|
||||
data class ShareFullContent(val guid: String) : MainAction
|
||||
data object DismissQRCodeDialog : MainAction
|
||||
|
||||
data class ImportBatchConfig(val configText: String) : MainAction
|
||||
|
||||
data class LocateHandled(val target: LocateTarget) : MainAction
|
||||
data class LocateHandled(val target: com.v2ray.ang.dto.LocateTarget) : MainAction
|
||||
}
|
||||
@@ -55,6 +55,8 @@ interface MainDataSource : Closeable {
|
||||
fun updateConfigViaSub(subscriptionCache: SubscriptionCache): SubscriptionUpdateResult
|
||||
|
||||
fun shareNonCustomConfigsToClipboard(guids: List<String>): Int
|
||||
fun share2QRCode(guid: String): android.graphics.Bitmap?
|
||||
fun share2Clipboard(guid: String): Boolean
|
||||
|
||||
fun sendMsg2Service(msgId: Int, content: String)
|
||||
fun sendMsg2TestService(msg: TestServiceMessage)
|
||||
|
||||
@@ -14,80 +14,72 @@ import com.v2ray.ang.extension.isComplexType
|
||||
|
||||
@Composable
|
||||
fun ImportMenuContent(
|
||||
onImportQRcode: () -> Unit,
|
||||
onImportClipboard: () -> Unit,
|
||||
onImportLocal: () -> Unit,
|
||||
onImportManually: (Int) -> Unit
|
||||
onAction: (MainAction) -> Unit
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.menu_item_import_config_qrcode)) },
|
||||
onClick = onImportQRcode
|
||||
onClick = { onAction(MainAction.ImportQRcode) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.menu_item_import_config_clipboard)) },
|
||||
onClick = onImportClipboard
|
||||
onClick = { onAction(MainAction.ImportClipboard) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.menu_item_import_config_local)) },
|
||||
onClick = onImportLocal
|
||||
onClick = { onAction(MainAction.ImportConfigLocal) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.menu_item_import_config_policy_group)) },
|
||||
onClick = { onImportManually(EConfigType.POLICYGROUP.value) }
|
||||
onClick = { onAction(MainAction.ImportManually(EConfigType.POLICYGROUP.value)) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.menu_item_import_config_proxy_chain)) },
|
||||
onClick = { onImportManually(EConfigType.PROXYCHAIN.value) }
|
||||
onClick = { onAction(MainAction.ImportManually(EConfigType.PROXYCHAIN.value)) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.menu_item_import_config_manually_vmess)) },
|
||||
onClick = { onImportManually(EConfigType.VMESS.value) }
|
||||
onClick = { onAction(MainAction.ImportManually(EConfigType.VMESS.value)) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.menu_item_import_config_manually_vless)) },
|
||||
onClick = { onImportManually(EConfigType.VLESS.value) }
|
||||
onClick = { onAction(MainAction.ImportManually(EConfigType.VLESS.value)) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.menu_item_import_config_manually_ss)) },
|
||||
onClick = { onImportManually(EConfigType.SHADOWSOCKS.value) }
|
||||
onClick = { onAction(MainAction.ImportManually(EConfigType.SHADOWSOCKS.value)) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.menu_item_import_config_manually_socks)) },
|
||||
onClick = { onImportManually(EConfigType.SOCKS.value) }
|
||||
onClick = { onAction(MainAction.ImportManually(EConfigType.SOCKS.value)) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.menu_item_import_config_manually_http)) },
|
||||
onClick = { onImportManually(EConfigType.HTTP.value) }
|
||||
onClick = { onAction(MainAction.ImportManually(EConfigType.HTTP.value)) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.menu_item_import_config_manually_trojan)) },
|
||||
onClick = { onImportManually(EConfigType.TROJAN.value) }
|
||||
onClick = { onAction(MainAction.ImportManually(EConfigType.TROJAN.value)) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.menu_item_import_config_manually_wireguard)) },
|
||||
onClick = { onImportManually(EConfigType.WIREGUARD.value) }
|
||||
onClick = { onAction(MainAction.ImportManually(EConfigType.WIREGUARD.value)) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.menu_item_import_config_manually_hysteria2)) },
|
||||
onClick = { onImportManually(EConfigType.HYSTERIA2.value) }
|
||||
onClick = { onAction(MainAction.ImportManually(EConfigType.HYSTERIA2.value)) }
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MoreMenuContent(
|
||||
onRestartService: () -> Unit,
|
||||
onAction: (MainAction) -> Unit,
|
||||
onDelAllConfig: () -> Unit,
|
||||
onDelDuplicateConfig: () -> Unit,
|
||||
onDelInvalidConfig: () -> Unit,
|
||||
onExportAll: () -> Unit,
|
||||
onRealPingAll: () -> Unit,
|
||||
onLocateSelectedServer: () -> Unit,
|
||||
onSortByTestResults: () -> Unit,
|
||||
onSubUpdate: () -> Unit
|
||||
onDelInvalidConfig: () -> Unit
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.title_service_restart)) },
|
||||
onClick = onRestartService
|
||||
onClick = { onAction(MainAction.RestartService) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.title_del_all_config)) },
|
||||
@@ -103,23 +95,23 @@ fun MoreMenuContent(
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.title_export_all)) },
|
||||
onClick = onExportAll
|
||||
onClick = { onAction(MainAction.ExportAll) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.title_real_ping_all_server)) },
|
||||
onClick = onRealPingAll
|
||||
onClick = { onAction(MainAction.TestAllServers) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.title_locate_selected_config)) },
|
||||
onClick = onLocateSelectedServer
|
||||
onClick = { onAction(MainAction.LocateSelectedServer) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.title_sort_by_test_results)) },
|
||||
onClick = onSortByTestResults
|
||||
onClick = { onAction(MainAction.SortByTestResults) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.title_sub_update)) },
|
||||
onClick = onSubUpdate
|
||||
onClick = { onAction(MainAction.UpdateSubscriptions) }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -131,12 +123,7 @@ fun ShareMethodDialog(
|
||||
shareMethodEntries: List<String>,
|
||||
shareMethodMoreEntries: List<String>,
|
||||
onDismiss: () -> Unit,
|
||||
onShareQRCode: (String) -> Bitmap?,
|
||||
onShareClipboard: (String) -> Boolean,
|
||||
onShareFullContent: (String) -> Unit,
|
||||
onEditServer: (String, ProfileItem) -> Unit,
|
||||
onRemoveServer: (String) -> Unit,
|
||||
showQRCodeBitmap: (Bitmap?) -> Unit
|
||||
onAction: (MainAction) -> Unit
|
||||
) {
|
||||
val isCustom = profile.configType.isComplexType()
|
||||
val (shareOptions, skip) = if (more) {
|
||||
@@ -151,11 +138,11 @@ fun ShareMethodDialog(
|
||||
onSelected = { index, _ ->
|
||||
onDismiss()
|
||||
when (index + skip) {
|
||||
0 -> showQRCodeBitmap(onShareQRCode(guid))
|
||||
1 -> onShareClipboard(guid)
|
||||
2 -> onShareFullContent(guid)
|
||||
3 -> onEditServer(guid, profile)
|
||||
4 -> onRemoveServer(guid)
|
||||
0 -> onAction(MainAction.ShareQRCode(guid))
|
||||
1 -> onAction(MainAction.ShareClipboard(guid))
|
||||
2 -> onAction(MainAction.ShareFullContent(guid))
|
||||
3 -> onAction(MainAction.EditServer(guid, profile))
|
||||
4 -> onAction(MainAction.RemoveServer(guid))
|
||||
}
|
||||
},
|
||||
onDismiss = onDismiss
|
||||
|
||||
@@ -201,6 +201,12 @@ class MainRepository(
|
||||
override fun shareNonCustomConfigsToClipboard(guids: List<String>): Int =
|
||||
AngConfigManager.shareNonCustomConfigsToClipboard(app, guids)
|
||||
|
||||
override fun share2QRCode(guid: String): android.graphics.Bitmap? =
|
||||
AngConfigManager.share2QRCode(guid)
|
||||
|
||||
override fun share2Clipboard(guid: String): Boolean =
|
||||
AngConfigManager.share2Clipboard(app, guid) == 0
|
||||
|
||||
override fun sendMsg2Service(msgId: Int, content: String) =
|
||||
MessageUtil.sendMsg2Service(app, msgId, content)
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.v2ray.ang.ui.main
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@@ -41,29 +40,8 @@ import kotlinx.coroutines.launch
|
||||
@Composable
|
||||
fun MainScreen(
|
||||
mainViewModel: MainViewModel,
|
||||
onFabClick: () -> Unit,
|
||||
onTestClick: () -> Unit,
|
||||
onAction: (MainAction) -> Unit,
|
||||
onNavigate: (String) -> Unit,
|
||||
onImportManually: (Int) -> Unit,
|
||||
onImportQRcode: () -> Unit,
|
||||
onImportClipboard: () -> Unit,
|
||||
onImportLocal: () -> Unit,
|
||||
onSubUpdate: () -> Unit,
|
||||
onExportAll: () -> Unit,
|
||||
onRealPingAll: () -> Unit,
|
||||
onRestartService: () -> Unit,
|
||||
onDelAllConfig: () -> Unit,
|
||||
onDelDuplicateConfig: () -> Unit,
|
||||
onDelInvalidConfig: () -> Unit,
|
||||
onSortByTestResults: () -> Unit,
|
||||
onEditServer: (String, ProfileItem) -> Unit,
|
||||
onRemoveServer: (String) -> Unit,
|
||||
onSelectServer: (String) -> Unit,
|
||||
onShareQRCode: (String) -> Bitmap?,
|
||||
onShareClipboard: (String) -> Boolean,
|
||||
onShareFullContent: (String) -> Unit,
|
||||
onSubscriptionIdChanged: (String) -> Unit,
|
||||
onLocateSelectedServer: () -> Unit,
|
||||
shareMethodEntries: List<String>,
|
||||
shareMethodMoreEntries: List<String>
|
||||
) {
|
||||
@@ -75,6 +53,7 @@ fun MainScreen(
|
||||
val selectedGuid = uiState.selectedGuid
|
||||
val doubleColumnDisplay = uiState.doubleColumnDisplay
|
||||
val confirmRemove = uiState.confirmRemove
|
||||
val shareQRCodeBitmap = uiState.shareQRCodeBitmap
|
||||
|
||||
val isDarkTheme = LocalDarkTheme.current
|
||||
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
||||
@@ -87,7 +66,6 @@ fun MainScreen(
|
||||
var showRemoveConfirm by remember { mutableStateOf<String?>(null) }
|
||||
|
||||
var shareTarget by remember { mutableStateOf<Triple<String, ProfileItem, Boolean>?>(null) }
|
||||
var showQRCodeBitmap by remember { mutableStateOf<Bitmap?>(null) }
|
||||
|
||||
val pagerState = rememberPagerState(
|
||||
initialPage = 0,
|
||||
@@ -125,7 +103,7 @@ fun MainScreen(
|
||||
.collect { page ->
|
||||
val currentGroups = latestGroups
|
||||
if (!latestLocateInProgress && page in currentGroups.indices) {
|
||||
onSubscriptionIdChanged(currentGroups[page].id)
|
||||
onAction(MainAction.SelectGroup(currentGroups[page].id))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,7 +123,7 @@ fun MainScreen(
|
||||
animateAdjacentPage = false
|
||||
)
|
||||
}
|
||||
onSubscriptionIdChanged(target.groupId)
|
||||
onAction(MainAction.SelectGroup(target.groupId))
|
||||
|
||||
repeat(10) {
|
||||
val ready = if (latestDoubleColumnDisplay) {
|
||||
@@ -182,16 +160,16 @@ fun MainScreen(
|
||||
MainDialogs(
|
||||
showDelAllConfirm = showDelAllConfirm,
|
||||
onDismissDelAll = { showDelAllConfirm = false },
|
||||
onConfirmDelAll = { showDelAllConfirm = false; onDelAllConfig() },
|
||||
onConfirmDelAll = { showDelAllConfirm = false; onAction(MainAction.RemoveAllServers) },
|
||||
showDelDuplicateConfirm = showDelDuplicateConfirm,
|
||||
onDismissDelDuplicate = { showDelDuplicateConfirm = false },
|
||||
onConfirmDelDuplicate = { showDelDuplicateConfirm = false; onDelDuplicateConfig() },
|
||||
onConfirmDelDuplicate = { showDelDuplicateConfirm = false; onAction(MainAction.RemoveDuplicateServers) },
|
||||
showDelInvalidConfirm = showDelInvalidConfirm,
|
||||
onDismissDelInvalid = { showDelInvalidConfirm = false },
|
||||
onConfirmDelInvalid = { showDelInvalidConfirm = false; onDelInvalidConfig() },
|
||||
onConfirmDelInvalid = { showDelInvalidConfirm = false; onAction(MainAction.RemoveInvalidServers) },
|
||||
showRemoveConfirm = showRemoveConfirm,
|
||||
onDismissRemove = { showRemoveConfirm = null },
|
||||
onConfirmRemove = { guid -> showRemoveConfirm = null; onRemoveServer(guid) }
|
||||
onConfirmRemove = { guid -> showRemoveConfirm = null; onAction(MainAction.RemoveServer(guid)) }
|
||||
)
|
||||
|
||||
if (shareTarget != null) {
|
||||
@@ -203,16 +181,11 @@ fun MainScreen(
|
||||
shareMethodEntries = shareMethodEntries,
|
||||
shareMethodMoreEntries = shareMethodMoreEntries,
|
||||
onDismiss = { shareTarget = null },
|
||||
onShareQRCode = onShareQRCode,
|
||||
onShareClipboard = onShareClipboard,
|
||||
onShareFullContent = onShareFullContent,
|
||||
onEditServer = onEditServer,
|
||||
onRemoveServer = onRemoveServer,
|
||||
showQRCodeBitmap = { bitmap -> showQRCodeBitmap = bitmap }
|
||||
onAction = onAction
|
||||
)
|
||||
}
|
||||
if (showQRCodeBitmap != null) {
|
||||
QRCodeDialog(bitmap = showQRCodeBitmap, onDismiss = { showQRCodeBitmap = null })
|
||||
if (shareQRCodeBitmap != null) {
|
||||
QRCodeDialog(bitmap = shareQRCodeBitmap, onDismiss = { onAction(MainAction.DismissQRCodeDialog) })
|
||||
}
|
||||
|
||||
ModalNavigationDrawer(
|
||||
@@ -235,28 +208,19 @@ fun MainScreen(
|
||||
searchQuery = searchQuery,
|
||||
onSearchQueryChange = { query: String ->
|
||||
searchQuery = query
|
||||
mainViewModel.filterConfig(query)
|
||||
onAction(MainAction.Search(query))
|
||||
},
|
||||
onSearchClose = {
|
||||
searchQuery = ""
|
||||
mainViewModel.filterConfig("")
|
||||
onAction(MainAction.Search(""))
|
||||
showSearch = false
|
||||
},
|
||||
onSearchToggle = { show: Boolean -> showSearch = show },
|
||||
onMenuClick = { scope.launch { drawerState.open() } },
|
||||
onImportQRcode = onImportQRcode,
|
||||
onImportClipboard = onImportClipboard,
|
||||
onImportLocal = onImportLocal,
|
||||
onImportManually = onImportManually,
|
||||
onRestartService = onRestartService,
|
||||
onAction = onAction,
|
||||
onDelAllConfig = { showDelAllConfirm = true },
|
||||
onDelDuplicateConfig = { showDelDuplicateConfirm = true },
|
||||
onDelInvalidConfig = { showDelInvalidConfirm = true },
|
||||
onExportAll = onExportAll,
|
||||
onRealPingAll = onRealPingAll,
|
||||
onLocateSelectedServer = onLocateSelectedServer,
|
||||
onSortByTestResults = onSortByTestResults,
|
||||
onSubUpdate = onSubUpdate
|
||||
onDelInvalidConfig = { showDelInvalidConfirm = true }
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
@@ -264,8 +228,7 @@ fun MainScreen(
|
||||
displayText = displayText,
|
||||
isRunning = isRunning,
|
||||
isDarkTheme = isDarkTheme,
|
||||
onTestClick = onTestClick,
|
||||
onFabClick = onFabClick
|
||||
onAction = onAction
|
||||
)
|
||||
},
|
||||
floatingActionButton = {},
|
||||
@@ -312,8 +275,8 @@ fun MainScreen(
|
||||
searchQuery = searchQuery,
|
||||
lazyListStates = lazyListStates,
|
||||
lazyGridStates = lazyGridStates,
|
||||
onSelectServer = onSelectServer,
|
||||
onEditServer = onEditServer,
|
||||
onSelectServer = { guid -> onAction(MainAction.SelectServer(guid)) },
|
||||
onEditServer = { guid, profile -> onAction(MainAction.EditServer(guid, profile)) },
|
||||
onShareServer = { guid, profile ->
|
||||
shareTarget = Triple(guid, profile, false)
|
||||
},
|
||||
@@ -322,7 +285,7 @@ fun MainScreen(
|
||||
},
|
||||
onRemoveServer = { guid ->
|
||||
if (confirmRemove) showRemoveConfirm = guid
|
||||
else onRemoveServer(guid)
|
||||
else onAction(MainAction.RemoveServer(guid))
|
||||
},
|
||||
contentPadding = PaddingValues(
|
||||
start = 0.dp,
|
||||
|
||||
@@ -39,19 +39,10 @@ fun MainTopBar(
|
||||
onSearchClose: () -> Unit,
|
||||
onSearchToggle: (Boolean) -> Unit,
|
||||
onMenuClick: () -> Unit,
|
||||
onImportQRcode: () -> Unit,
|
||||
onImportClipboard: () -> Unit,
|
||||
onImportLocal: () -> Unit,
|
||||
onImportManually: (Int) -> Unit,
|
||||
onRestartService: () -> Unit,
|
||||
onAction: (MainAction) -> Unit,
|
||||
onDelAllConfig: () -> Unit,
|
||||
onDelDuplicateConfig: () -> Unit,
|
||||
onDelInvalidConfig: () -> Unit,
|
||||
onExportAll: () -> Unit,
|
||||
onRealPingAll: () -> Unit,
|
||||
onLocateSelectedServer: () -> Unit,
|
||||
onSortByTestResults: () -> Unit,
|
||||
onSubUpdate: () -> Unit
|
||||
onDelInvalidConfig: () -> Unit
|
||||
) {
|
||||
var showImportMenu by remember { mutableStateOf(false) }
|
||||
var showMenu by remember { mutableStateOf(false) }
|
||||
@@ -101,10 +92,10 @@ fun MainTopBar(
|
||||
.verticalScrollbar(importMenuScrollState)
|
||||
) {
|
||||
ImportMenuContent(
|
||||
onImportQRcode = { showImportMenu = false; onImportQRcode() },
|
||||
onImportClipboard = { showImportMenu = false; onImportClipboard() },
|
||||
onImportLocal = { showImportMenu = false; onImportLocal() },
|
||||
onImportManually = { type -> showImportMenu = false; onImportManually(type) }
|
||||
onAction = { action ->
|
||||
showImportMenu = false
|
||||
onAction(action)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -122,15 +113,13 @@ fun MainTopBar(
|
||||
.verticalScrollbar(moreMenuScrollState)
|
||||
) {
|
||||
MoreMenuContent(
|
||||
onRestartService = { showMenu = false; onRestartService() },
|
||||
onAction = { action ->
|
||||
showMenu = false
|
||||
onAction(action)
|
||||
},
|
||||
onDelAllConfig = { showMenu = false; onDelAllConfig() },
|
||||
onDelDuplicateConfig = { showMenu = false; onDelDuplicateConfig() },
|
||||
onDelInvalidConfig = { showMenu = false; onDelInvalidConfig() },
|
||||
onExportAll = { showMenu = false; onExportAll() },
|
||||
onRealPingAll = { showMenu = false; onRealPingAll() },
|
||||
onLocateSelectedServer = { showMenu = false; onLocateSelectedServer() },
|
||||
onSortByTestResults = { showMenu = false; onSortByTestResults() },
|
||||
onSubUpdate = { showMenu = false; onSubUpdate() }
|
||||
onDelInvalidConfig = { showMenu = false; onDelInvalidConfig() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +173,6 @@ class MainViewModel(
|
||||
MainAction.SortByTestResults -> sortByTestResultsAsync()
|
||||
MainAction.UpdateSubscriptions -> importConfigViaSub()
|
||||
MainAction.ExportAll -> exportAllAsync()
|
||||
MainAction.ImportConfigViaSub -> importConfigViaSub()
|
||||
is MainAction.SelectGroup -> subscriptionIdChanged(action.groupId)
|
||||
is MainAction.SelectServer -> updateSelectedGuid(action.guid)
|
||||
is MainAction.RemoveServer -> removeServerAndRefresh(action.guid)
|
||||
@@ -181,9 +180,25 @@ class MainViewModel(
|
||||
is MainAction.SwapServer -> swapServer(action.fromIndex, action.toIndex)
|
||||
is MainAction.ImportBatchConfig -> importBatchConfig(action.configText)
|
||||
is MainAction.LocateHandled -> consumeLocateTarget(action.target)
|
||||
is MainAction.ShareQRCode -> {
|
||||
val bitmap = dataSource.share2QRCode(action.guid)
|
||||
_uiState.update { it.copy(shareQRCodeBitmap = bitmap) }
|
||||
}
|
||||
MainAction.DismissQRCodeDialog -> {
|
||||
_uiState.update { it.copy(shareQRCodeBitmap = null) }
|
||||
}
|
||||
MainAction.ToggleService,
|
||||
MainAction.TestCurrentServer -> {
|
||||
// Platform-specific, handled by Activity
|
||||
MainAction.TestCurrentServer,
|
||||
MainAction.ImportQRcode,
|
||||
MainAction.ImportClipboard,
|
||||
MainAction.ImportConfigLocal,
|
||||
is MainAction.ImportManually,
|
||||
MainAction.RestartService,
|
||||
MainAction.LocateSelectedServer,
|
||||
is MainAction.EditServer,
|
||||
is MainAction.ShareClipboard,
|
||||
is MainAction.ShareFullContent -> {
|
||||
// Handled by Activity via its onAction lambda
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user