Code clean

This commit is contained in:
2dust committed 2026-07-21 18:24:27 +08:00
1 parent f6ea2df5a0
commit 4949528eeb
34 files changed
+172 -79

No files matched your search

@@ -140,7 +140,9 @@ private fun SearchInputField(
)
),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
modifier = Modifier.weight(1f).focusRequester(focusRequester)
modifier = Modifier
.weight(1f)
.focusRequester(focusRequester)
)
if (query.isNotEmpty()) {
IconButton(onClick = { onQueryChange("") }) {
@@ -176,6 +178,7 @@ fun AppListItem(
contentScale = ContentScale.Fit
)
}
is Int -> {
Image(
painter = painterResource(id = icon),
@@ -184,6 +187,7 @@ fun AppListItem(
contentScale = ContentScale.Fit
)
}
is Drawable -> {
val bitmap = remember(icon) { createBitmapFromDrawable(icon) }
Image(
@@ -193,6 +197,7 @@ fun AppListItem(
contentScale = ContentScale.Fit
)
}
else -> {
Box(modifier = Modifier.size(40.dp))
}
@@ -29,7 +29,6 @@ import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import com.v2ray.ang.R
@Composable
fun ConfirmDialog(
@@ -175,7 +174,9 @@ fun SelectListDialog(
text = option,
style = MaterialTheme.typography.bodyMedium,
modifier = if (!showRadio)
Modifier.fillMaxWidth().padding(vertical = 8.dp, horizontal = 4.dp)
Modifier
.fillMaxWidth()
.padding(vertical = 8.dp, horizontal = 4.dp)
else Modifier
)
}
@@ -26,7 +26,6 @@ import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import com.v2ray.ang.R
@Composable
fun PreferenceGroupHeader(title: String, modifier: Modifier = Modifier) {
@@ -113,7 +112,9 @@ fun SettingsEditItem(
title = title,
description = description,
enabled = enabled,
onClick = if (enabled) { { showDialog = true } } else null,
onClick = if (enabled) {
{ showDialog = true }
} else null,
modifier = modifier
)
@@ -157,7 +158,9 @@ fun SettingsListItem(
title = title,
description = summary.ifEmpty { null },
enabled = enabled,
onClick = if (enabled) { { showDialog = true } } else null,
onClick = if (enabled) {
{ showDialog = true }
} else null,
modifier = modifier
)
@@ -209,7 +212,9 @@ fun SettingsSwitchItem(
title = title,
description = summary,
enabled = enabled,
onClick = if (enabled) { { onCheckedChange(!checked) } } else null,
onClick = if (enabled) {
{ onCheckedChange(!checked) }
} else null,
modifier = modifier,
trailing = {
Switch(
@@ -6,8 +6,8 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
@@ -92,7 +92,7 @@ class AppSnackbarController(
val hostState: SnackbarHostState,
private val scope: CoroutineScope,
) {
fun show(message: CharSequence, type: ToastType = ToastType.NORMAL, long: Boolean = false, ) {
fun show(message: CharSequence, type: ToastType = ToastType.NORMAL, long: Boolean = false) {
scope.launch {
hostState.currentSnackbarData?.dismiss()
hostState.showSnackbar(
@@ -104,30 +104,30 @@ class AppSnackbarController(
}
}
fun showInfo(context: Context, @StringRes messageRes: Int, long: Boolean = false, ) {
fun showInfo(context: Context, @StringRes messageRes: Int, long: Boolean = false) {
show(context.getString(messageRes), ToastType.NORMAL, long)
}
fun showInfo(message: CharSequence, long: Boolean = false, ) {
fun showInfo(message: CharSequence, long: Boolean = false) {
show(message, ToastType.NORMAL, long)
}
fun showSuccess(context: Context, @StringRes messageRes: Int, long: Boolean = false, ) {
fun showSuccess(context: Context, @StringRes messageRes: Int, long: Boolean = false) {
show(context.getString(messageRes), ToastType.SUCCESS, long)
}
fun showSuccess(message: CharSequence, long: Boolean = false, ) {
fun showSuccess(message: CharSequence, long: Boolean = false) {
show(message, ToastType.SUCCESS, long)
}
fun showError(context: Context, @StringRes messageRes: Int, long: Boolean = false, ) {
fun showError(context: Context, @StringRes messageRes: Int, long: Boolean = false) {
show(context.getString(messageRes), ToastType.ERROR, long)
}
fun showError(message: CharSequence, long: Boolean = false, ) {
fun showError(message: CharSequence, long: Boolean = false) {
show(message, ToastType.ERROR, long)
}
}
@@ -915,7 +915,7 @@ object CoreConfigManager {
return hosts
}
private fun buildDnsCnModeFromRoutingRules(configContext: CoreConfigContext, servers: ArrayList<Any>, domesticDns: List<String>, ): List<String> {
private fun buildDnsCnModeFromRoutingRules(configContext: CoreConfigContext, servers: ArrayList<Any>, domesticDns: List<String>): List<String> {
val cnRegionFilter = { domain: String ->
domain.startsWith("geosite:") && (domain.endsWith("-cn") || domain.endsWith("@cn"))
|| domain == AppConfig.GEOSITE_CN
@@ -981,6 +981,7 @@ object CoreConfigManager {
domesticDnsTags.add(tag)
}
}
AppConfig.TAG_BLOCKED -> Unit
else -> {
servers.add(
@@ -61,6 +61,7 @@ data class V2rayNShareItem(
val Filter: String?,
val MultipleLoad: Int?,
)
data class V2rayNTransportExtraShareItem(
val RawHeaderType: String?,
val Host: String?,
@@ -497,7 +497,8 @@ object AngConfigManager {
config.description = generateDescription(config)
if (str.startsWith(AppConfig.V2RAYNFMTS, ignoreCase = true)
&& config.policyGroupSubscriptionId == "self") {
&& config.policyGroupSubscriptionId == "self"
) {
config.policyGroupSubscriptionId = subid
}
@@ -38,7 +38,7 @@ object SettingsChangeManager {
fun makeRestartService() {
restartService.set(true)
}
/**
* Atomically consumes the restart flag.
* @return true if a restart was requested, false otherwise.
@@ -114,7 +114,9 @@ fun AboutScreen(onBackClick: () -> Unit) {
loadUrl("file:///android_asset/open_source_licenses.html")
}
},
modifier = Modifier.fillMaxWidth().heightIn(min = 300.dp)
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 300.dp)
)
},
confirmButton = {
@@ -3,7 +3,6 @@ package com.v2ray.ang.ui
import android.content.Intent
import android.graphics.BitmapFactory
import android.os.Bundle
import android.util.Size as TargetSize
import androidx.camera.compose.CameraXViewfinder
import androidx.camera.core.Camera
import androidx.camera.core.CameraControl
@@ -72,6 +71,7 @@ import com.v2ray.ang.util.LogUtil
import com.v2ray.ang.util.QRCodeDecoder
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean
import android.util.Size as TargetSize
private val qrReader = MultiFormatReader()
@@ -24,8 +24,8 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@@ -14,7 +14,6 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.withContext
import java.text.Collator
import kotlin.collections.plus
/**
* ViewModel for AppPicker screen.
@@ -168,7 +168,7 @@ fun LogcatScreen(
IconButton(onClick = {
val all = viewModel.filteredLogs.value.joinToString("\n")
Utils.setClipboard(context, all)
snackbar.showInfo(context,R.string.toast_success)
snackbar.showInfo(context, R.string.toast_success)
}) {
Icon(
painterResource(R.drawable.ic_copy),
@@ -26,14 +26,11 @@ import com.v2ray.ang.handler.SettingsChangeManager
import com.v2ray.ang.handler.SettingsManager
import com.v2ray.ang.ui.AboutActivity
import com.v2ray.ang.ui.backup.BackupActivity
import com.v2ray.ang.ui.checkupdate.CheckUpdateActivity
import com.v2ray.ang.ui.base.HelperBaseComponentActivity
import com.v2ray.ang.ui.checkupdate.CheckUpdateActivity
import com.v2ray.ang.ui.logcat.LogcatActivity
import com.v2ray.ang.ui.perappproxy.PerAppProxyActivity
import com.v2ray.ang.ui.routing.RoutingSettingActivity
import com.v2ray.ang.ui.settings.SettingsActivity
import com.v2ray.ang.ui.subscription.SubSettingActivity
import com.v2ray.ang.ui.userasset.UserAssetActivity
import com.v2ray.ang.ui.server.ProfileEditorResult
import com.v2ray.ang.ui.server.ServerCustomConfigActivity
import com.v2ray.ang.ui.server.ServerGroupActivity
@@ -46,6 +43,9 @@ import com.v2ray.ang.ui.server.ServerTrojanActivity
import com.v2ray.ang.ui.server.ServerVlessActivity
import com.v2ray.ang.ui.server.ServerVmessActivity
import com.v2ray.ang.ui.server.ServerWireguardActivity
import com.v2ray.ang.ui.settings.SettingsActivity
import com.v2ray.ang.ui.subscription.SubSettingActivity
import com.v2ray.ang.ui.userasset.UserAssetActivity
import com.v2ray.ang.util.LogUtil
import com.v2ray.ang.util.Utils
import kotlinx.coroutines.Dispatchers
@@ -65,7 +65,7 @@ class MainActivity : HelperBaseComponentActivity() {
private val profileEditorLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode != Activity.RESULT_OK) return@registerForActivityResult
if (result.resultCode != RESULT_OK) return@registerForActivityResult
val data = result.data ?: return@registerForActivityResult
val action = data.getStringExtra(ProfileEditorResult.EXTRA_ACTION)
?: return@registerForActivityResult
@@ -155,6 +155,7 @@ class MainActivity : HelperBaseComponentActivity() {
)
return
}
else -> return
}
settingsActivityLauncher.launch(intent)
@@ -5,15 +5,15 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
@@ -57,5 +57,5 @@ sealed interface MainAction {
data class ImportBatchConfig(val configText: String) : MainAction
data class LocateHandled(val target: com.v2ray.ang.dto.LocateTarget) : MainAction
data class LocateHandled(val target: LocateTarget) : MainAction
}
@@ -53,9 +53,11 @@ fun MainDrawerContent(onNavigate: (String) -> Unit) {
.verticalScrollbar(drawerScrollState)
.padding(bottom = 80.dp)
) {
Surface(modifier = Modifier
.fillMaxWidth()
.height(160.dp)) {
Surface(
modifier = Modifier
.fillMaxWidth()
.height(160.dp)
) {
Column(
modifier = Modifier
.fillMaxSize()
@@ -1,12 +1,10 @@
package com.v2ray.ang.ui.main
import android.graphics.Bitmap
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.v2ray.ang.R
import com.v2ray.ang.compose.QRCodeDialog
import com.v2ray.ang.compose.SelectListDialog
import com.v2ray.ang.dto.entities.ProfileItem
import com.v2ray.ang.enums.EConfigType
@@ -51,17 +51,21 @@ class MainRepository(
AppConfig.MSG_STATE_START_FAILURE -> MainServiceEvent.StateStartFailure(
safeIntent.getStringExtra("content").orEmpty()
)
AppConfig.MSG_STATE_STOP_SUCCESS -> MainServiceEvent.StateStopSuccess
AppConfig.MSG_MEASURE_DELAY_SUCCESS -> MainServiceEvent.MeasureDelaySuccess(
safeIntent.getStringExtra("content").orEmpty()
)
AppConfig.MSG_MEASURE_CONFIG_SUCCESS -> MainServiceEvent.MeasureConfigSuccess
AppConfig.MSG_MEASURE_CONFIG_NOTIFY -> MainServiceEvent.MeasureConfigNotify(
safeIntent.getStringExtra("content").orEmpty()
)
AppConfig.MSG_MEASURE_CONFIG_FINISH -> MainServiceEvent.MeasureConfigFinish(
safeIntent.getStringExtra("content")
)
else -> null
}
event?.let { _mainServiceEvent.tryEmit(it) }
@@ -4,10 +4,10 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.grid.LazyGridState
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ModalNavigationDrawer
@@ -317,18 +317,36 @@ fun ServerListItem(
dragModifier: Modifier = Modifier
) {
Row(
modifier = modifier.fillMaxWidth().height(IntrinsicSize.Min).clickable(onClick = onClick).then(dragModifier)
modifier = modifier
.fillMaxWidth()
.height(IntrinsicSize.Min)
.clickable(onClick = onClick)
.then(dragModifier)
) {
Box(Modifier.width(10.dp).fillMaxHeight()) {
Box(
Modifier
.width(10.dp)
.fillMaxHeight()
) {
if (isSelected) {
Row {
Spacer(Modifier.width(6.dp))
Box(Modifier.width(4.dp).fillMaxHeight().padding(vertical = 10.dp).background(MaterialTheme.colorScheme.primary))
Box(
Modifier
.width(4.dp)
.fillMaxHeight()
.padding(vertical = 10.dp)
.background(MaterialTheme.colorScheme.primary)
)
}
}
}
Column(Modifier.weight(1f).padding(start = 8.dp, end = 12.dp, top = 8.dp, bottom = 8.dp)) {
Column(
Modifier
.weight(1f)
.padding(start = 8.dp, end = 12.dp, top = 8.dp, bottom = 8.dp)
) {
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text(remarks, Modifier.weight(1f), style = MaterialTheme.typography.bodyLarge.copy(lineBreak = LineBreak.Paragraph), maxLines = 2, overflow = TextOverflow.Ellipsis)
if (doubleColumnDisplay) {
@@ -344,7 +362,12 @@ fun ServerListItem(
Spacer(modifier = Modifier.height(6.dp))
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
if (subscriptionRemarks.isNotBlank()) {
Box(Modifier.size(24.dp).clip(CircleShape).background(MaterialTheme.colorScheme.primary.copy(alpha = 0.2f)), Alignment.Center) {
Box(
Modifier
.size(24.dp)
.clip(CircleShape)
.background(MaterialTheme.colorScheme.primary.copy(alpha = 0.2f)), Alignment.Center
) {
Text(subscriptionRemarks.take(1).uppercase(), fontSize = 11.sp, fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.primary)
}
}
@@ -3,7 +3,6 @@ package com.v2ray.ang.ui.main
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.statusBars
@@ -181,9 +181,11 @@ class MainViewModel(
val bitmap = dataSource.share2QRCode(action.guid)
_uiState.update { it.copy(shareQRCodeBitmap = bitmap) }
}
MainAction.DismissQRCodeDialog -> {
_uiState.update { it.copy(shareQRCodeBitmap = null) }
}
MainAction.ToggleService,
MainAction.TestCurrentServer,
MainAction.ImportQRcode,
@@ -31,8 +31,8 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
@@ -192,7 +192,11 @@ fun PerAppProxyScreen(
)
}
) { innerPadding ->
Column(modifier = Modifier.fillMaxSize().padding(innerPadding)) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
) {
Surface(
modifier = Modifier.fillMaxWidth(),
color = MaterialTheme.colorScheme.surface
@@ -4,12 +4,12 @@ import android.os.Bundle
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Button
import androidx.compose.material3.Icon
@@ -3,8 +3,8 @@ package com.v2ray.ang.ui.server
import android.os.Bundle
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
@@ -19,8 +19,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
@@ -375,13 +375,21 @@ fun ServerScreen(
if (configType != EConfigType.HYSTERIA2) item { FormTextField(stringResource(R.string.server_lab_port), port, { port = it }, keyboardType = KeyboardType.Number) }
when {
isVmess || isTrojan || isShadowsocks || isHysteria2 -> item {
FormTextField(stringResource(when { isTrojan||isShadowsocks||isHysteria2 -> R.string.server_lab_id3 else -> R.string.server_lab_id }), password, { password = it })
FormTextField(
stringResource(
when {
isTrojan || isShadowsocks || isHysteria2 -> R.string.server_lab_id3
else -> R.string.server_lab_id
}
), password, { password = it })
}
isVless -> {
item { FormTextField(stringResource(R.string.server_lab_id), password, { password = it }) }
item { FormTextField(stringResource(R.string.server_lab_encryption), encryption, { encryption = it }) }
item { FormDropdownField(stringResource(R.string.server_lab_flow), flow, flowOptions, { flow = it }) }
}
isSocksOrHttp -> {
item { FormTextField(stringResource(R.string.server_lab_security4), username, { username = it }) }
item { FormTextField(stringResource(R.string.server_lab_id4), password, { password = it }) }
@@ -415,26 +423,40 @@ fun ServerScreen(
if (headerOptions.size > 1) {
item {
FormDropdownField(
stringResource(when (network) { NetworkType.GRPC.type -> R.string.server_lab_mode_type; NetworkType.XHTTP.type -> R.string.server_lab_xhttp_mode; else -> R.string.server_lab_head_type }),
stringResource(
when (network) {
NetworkType.GRPC.type -> R.string.server_lab_mode_type; NetworkType.XHTTP.type -> R.string.server_lab_xhttp_mode; else -> R.string.server_lab_head_type
}
),
headerType, headerOptions, { headerType = it }
)
}
}
item { FormTextField(stringResource(when (network) {
NetworkType.TCP.type, NetworkType.HTTP_UPGRADE.type, NetworkType.XHTTP.type, NetworkType.H2.type -> R.string.server_lab_request_host_http
NetworkType.WS.type -> R.string.server_lab_request_host_ws
NetworkType.GRPC.type -> R.string.server_lab_request_host_grpc
else -> R.string.server_lab_request_host6
}), host, { host = it }) }
item { FormTextField(stringResource(when (network) {
NetworkType.KCP.type -> R.string.server_lab_path_kcp
NetworkType.WS.type -> R.string.server_lab_path_ws
NetworkType.HTTP_UPGRADE.type -> R.string.server_lab_path_httpupgrade
NetworkType.XHTTP.type -> R.string.server_lab_path_xhttp
NetworkType.H2.type -> R.string.server_lab_path_h2
NetworkType.GRPC.type -> R.string.server_lab_path_grpc
else -> R.string.server_lab_path
}), path, { path = it }) }
item {
FormTextField(
stringResource(
when (network) {
NetworkType.TCP.type, NetworkType.HTTP_UPGRADE.type, NetworkType.XHTTP.type, NetworkType.H2.type -> R.string.server_lab_request_host_http
NetworkType.WS.type -> R.string.server_lab_request_host_ws
NetworkType.GRPC.type -> R.string.server_lab_request_host_grpc
else -> R.string.server_lab_request_host6
}
), host, { host = it })
}
item {
FormTextField(
stringResource(
when (network) {
NetworkType.KCP.type -> R.string.server_lab_path_kcp
NetworkType.WS.type -> R.string.server_lab_path_ws
NetworkType.HTTP_UPGRADE.type -> R.string.server_lab_path_httpupgrade
NetworkType.XHTTP.type -> R.string.server_lab_path_xhttp
NetworkType.H2.type -> R.string.server_lab_path_h2
NetworkType.GRPC.type -> R.string.server_lab_path_grpc
else -> R.string.server_lab_path
}
), path, { path = it })
}
if (network == NetworkType.XHTTP.type) {
item { FormTextField(stringResource(R.string.server_lab_xhttp_extra), xhttpExtra, { xhttpExtra = it }) }
}
@@ -459,8 +481,12 @@ fun ServerScreen(
item {
Button(
onClick = {
if (address.isBlank()) { context.toast(R.string.server_lab_address); return@Button }
if (configType != EConfigType.HYSTERIA2 && (port.toIntOrNull() ?: 0) <= 0) { context.toast(R.string.server_lab_port); return@Button }
if (address.isBlank()) {
context.toast(R.string.server_lab_address); return@Button
}
if (configType != EConfigType.HYSTERIA2 && (port.toIntOrNull() ?: 0) <= 0) {
context.toast(R.string.server_lab_port); return@Button
}
val temp = buildProfileItem()
scope.launch {
isFetchingCert = true
@@ -470,7 +496,9 @@ fun ServerScreen(
pinnedCA256 = sha256
context.toastSuccess(R.string.toast_fetch_cert_sha256_success)
}
} finally { isFetchingCert = false }
} finally {
isFetchingCert = false
}
}
},
enabled = !isFetchingCert,
@@ -268,8 +268,10 @@ fun ServerCustomConfigScreen(
val targetY = when {
lineBottom > scrollY + vh - pad ->
(lineBottom - vh + pad).toInt()
lineTop < scrollY + pad ->
(lineTop - pad).toInt()
else -> null
}
targetY?.let {
@@ -288,9 +290,11 @@ fun ServerCustomConfigScreen(
val targetX = when {
cursorX < scrollX + pad ->
(cursorX - pad).toInt().coerceAtLeast(0)
cursorX > scrollX + vw - pad ->
(cursorX - vw + pad).toInt()
.coerceAtMost(horizontalScroll.maxValue)
else -> null
}
targetX?.let {
@@ -14,8 +14,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringArrayResource
@@ -27,8 +27,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
@@ -141,7 +141,11 @@ fun TaskerScreen(
)
}
) { innerPadding ->
Column(modifier = Modifier.fillMaxSize().padding(innerPadding)) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
) {
SettingsSwitchItem(
title = stringResource(R.string.tasker_start_service),
checked = switchState.value,
@@ -16,8 +16,8 @@ import androidx.compose.material3.ScaffoldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@@ -145,7 +145,7 @@ fun SubEditScreen(
val confirmRemove = MmkvManager.decodeSettingsBool(AppConfig.PREF_CONFIRM_REMOVE, false)
val scrollState = rememberScrollState()
fun buildSubItem(): SubscriptionItem? {
fun buildSubItem(): SubscriptionItem {
val subItem = MmkvManager.decodeSubscription(editSubId) ?: SubscriptionItem()
subItem.remarks = remarks
subItem.url = url
@@ -43,9 +43,9 @@ import com.v2ray.ang.R
import com.v2ray.ang.compose.AppDivider
import com.v2ray.ang.compose.AppTopBar
import com.v2ray.ang.compose.ConfirmDialog
import com.v2ray.ang.compose.SelectListDialog
import com.v2ray.ang.compose.QRCodeDialog
import com.v2ray.ang.compose.ReorderableListItem
import com.v2ray.ang.compose.SelectListDialog
import com.v2ray.ang.compose.SettingsSwitchItem
import com.v2ray.ang.compose.colorFabActive
import com.v2ray.ang.compose.verticalScrollbar
@@ -254,6 +254,7 @@ fun SubSettingScreen(
// QRCode
showQRCodeBitmap = onShareQRCode(url)
}
1 -> {
// Export to clipboard
onShareClipboard(url)
@@ -52,10 +52,10 @@ import com.v2ray.ang.compose.SettingsListItem
import com.v2ray.ang.compose.verticalScrollbar
import com.v2ray.ang.dto.entities.AssetUrlCache
import com.v2ray.ang.dto.entities.AssetUrlItem
import com.v2ray.ang.extension.toTrafficString
import com.v2ray.ang.extension.toast
import com.v2ray.ang.extension.toastError
import com.v2ray.ang.extension.toastSuccess
import com.v2ray.ang.extension.toTrafficString
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.handler.SettingsManager
import com.v2ray.ang.ui.base.HelperBaseComponentActivity
@@ -373,10 +373,16 @@ private fun UserAssetItem(
val showEditButton = item.assetUrl.locked != true && item.assetUrl.url != "file"
Row(
modifier = Modifier.fillMaxWidth().padding(8.dp),
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Column(modifier = Modifier.weight(1f).padding(8.dp)) {
Column(
modifier = Modifier
.weight(1f)
.padding(8.dp)
) {
Text(
text = item.assetUrl.remarks,
style = MaterialTheme.typography.bodyLarge,
@@ -54,10 +54,12 @@ class UserAssetUrlActivity : BaseComponentActivity() {
initialRemarks = assetItem.remarks
initialUrl = assetItem.url
}
assetUrlQrcode != null -> {
initialRemarks = assetNameQrcode
initialUrl = assetUrlQrcode
}
else -> {
initialRemarks = ""
initialUrl = ""