Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions V2rayNG/app/src/main/java/com/v2ray/ang/core/CoreConfigManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.text.TextUtils
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
import com.v2ray.ang.dto.ConfigResult
import com.v2ray.ang.dto.CoreConfigContext
import com.v2ray.ang.dto.V2rayConfig
Expand Down Expand Up @@ -34,7 +35,11 @@ object CoreConfigManager {
fun getV2rayConfig(context: Context, guid: String): ConfigResult {
try {
val configContext = CoreConfigContextBuilder.build(context, guid)
?: return ConfigResult(status = false, guid = guid, errorMessage = "Failed to build config context")
?: return ConfigResult(
status = false,
guid = guid,
errorMessage = context.getString(R.string.core_error_build_config_context)
)
if (configContext.isCustom) {
return buildV2rayCustomConfig(configContext)
}
Expand All @@ -44,7 +49,10 @@ object CoreConfigManager {
return ConfigResult(
status = false,
guid = guid,
errorMessage = "Failed to get V2ray config: ${e.message ?: e.javaClass.simpleName}"
errorMessage = context.getString(
R.string.core_error_get_config_detail,
e.message ?: e.javaClass.simpleName
)
)
}
}
Expand All @@ -57,7 +65,11 @@ object CoreConfigManager {
fun getV2rayConfig4Speedtest(context: Context, guid: String): ConfigResult {
try {
val configContext = CoreConfigContextBuilder.build(context, guid)
?: return ConfigResult(status = false, guid = guid, errorMessage = "Failed to build config context")
?: return ConfigResult(
status = false,
guid = guid,
errorMessage = context.getString(R.string.core_error_build_config_context)
)
if (configContext.isCustom) {
return buildV2rayCustomConfig(configContext)
}
Expand All @@ -70,7 +82,10 @@ object CoreConfigManager {
return ConfigResult(
status = false,
guid = guid,
errorMessage = "Failed to get V2ray config for speedtest: ${e.message ?: e.javaClass.simpleName}"
errorMessage = context.getString(
R.string.core_error_get_speedtest_config_detail,
e.message ?: e.javaClass.simpleName
)
)
}
}
Expand All @@ -81,7 +96,11 @@ object CoreConfigManager {
private fun buildV2rayCustomConfig(configContext: CoreConfigContext): ConfigResult {
val context = configContext.context
val raw = MmkvManager.decodeServerRaw(configContext.guid)
?: return ConfigResult(status = false, guid = configContext.guid, errorMessage = "Custom config is empty")
?: return ConfigResult(
status = false,
guid = configContext.guid,
errorMessage = context.getString(R.string.core_error_custom_config_empty)
)
val result = ConfigResult(true, configContext.guid, raw)

val json = JsonUtil.parseString(raw)?.takeIf { it.isJsonObject }?.asJsonObject ?: return result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ object CoreNativeManager {
*
* @return Version string of the V2Ray core
*/
fun getLibVersion(): String {
fun getLibVersion(): String? {
return try {
Libv2ray.checkVersionX()
} catch (e: Exception) {
LogUtil.e(AppConfig.TAG, "Failed to check V2Ray version", e)
"Unknown"
null
}
}

Expand Down
18 changes: 11 additions & 7 deletions V2rayNG/app/src/main/java/com/v2ray/ang/core/CoreServiceManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,16 @@ object CoreServiceManager {

@Throws(Exception::class)
private fun launchCore(service: Service, vpnInterface: ParcelFileDescriptor?, isReload: Boolean = false) {
val guid = MmkvManager.getSelectServer() ?: error("No server selected")
val config = MmkvManager.decodeServerConfig(guid) ?: error("Failed to decode server config")
val guid = MmkvManager.getSelectServer()

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我认为 core 里面这些字符串不应该处理。
因为这些有部分是会写入logcat ,这样会导致 log 中出现非英文内容; 且提示了给用户,用户也看不明白。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can separate user-visible error text and Logcat error text? See the new commit.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

看到了。
完全没有必要做的这样复杂,用户无需知道这么详细的错误信息;应该直接在最后提示启动失败,然后去查看日志,因为日志中才会有完整的内容。

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

另外,这种单例和服务代码中,尽量还是不引入 string ,原来已有的地方也要考虑移除掉。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

另外,这种单例和服务代码中,尽量还是不引入 string ,原来已有的地方也要考虑移除掉。

Got it. I'll see what is left in terms of localization tomorrow. Looks like part 3 won't add anything. I'll probably just clean up unused strings added in part 2, and compile it to see how everything fits. Then we can call localization audit complete.

?: error(service.getString(R.string.core_error_no_server_selected))
val config = MmkvManager.decodeServerConfig(guid)
?: error(service.getString(R.string.core_error_decode_server_config))

LogUtil.i(AppConfig.TAG, "StartCore-Manager: Starting core loop for ${config.remarks}")
val result = CoreConfigManager.getV2rayConfig(service, guid)
LogUtil.d(AppConfig.TAG, result.content)
if (!result.status) {
error(result.errorMessage.ifBlank { "Failed to get V2Ray config" })
error(result.errorMessage.ifBlank { service.getString(R.string.core_error_get_config) })
}

currentConfig = config
Expand All @@ -149,7 +151,7 @@ object CoreServiceManager {
coreController.startLoop(result.content, tunFd)

if (!isRunning()) {
error("Core failed to start")
error(service.getString(R.string.core_error_start))
}

if (browserDialer != null) {
Expand Down Expand Up @@ -321,14 +323,16 @@ object CoreServiceManager {
time = coreController.measureDelay(SettingsManager.getDelayTestUrl())
} catch (e: Exception) {
LogUtil.e(AppConfig.TAG, "StartCore-Manager: Failed to measure delay", e)
errorStr = e.message?.substringAfter("\":") ?: "empty message"
errorStr = e.message?.substringAfter("\":")
?: service.getString(R.string.connection_test_empty_message)
}
if (time == -1L) {
try {
time = coreController.measureDelay(SettingsManager.getDelayTestUrl(true))
} catch (e: Exception) {
LogUtil.e(AppConfig.TAG, "StartCore-Manager: Failed to measure delay", e)
errorStr = e.message?.substringAfter("\":") ?: "empty message"
errorStr = e.message?.substringAfter("\":")
?: service.getString(R.string.connection_test_empty_message)
}
}

Expand All @@ -341,7 +345,7 @@ object CoreServiceManager {

// Only fetch IP info if the delay test was successful
if (time >= 0) {
SpeedtestManager.getRemoteIPInfo()?.let { ip ->
SpeedtestManager.getRemoteIPInfo(service.getString(R.string.value_unknown))?.let { ip ->
MessageHelper.sendMsg2UI(service, AppConfig.MSG_MEASURE_DELAY_SUCCESS, "$result\n$ip")
}
}
Expand Down
13 changes: 8 additions & 5 deletions V2rayNG/app/src/main/java/com/v2ray/ang/enums/PermissionType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package com.v2ray.ang.enums
import android.Manifest
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import com.v2ray.ang.R

/**
* Permission types used in the app, handling API level differences.
Expand All @@ -28,12 +30,13 @@ enum class PermissionType {
/** Return the actual Android permission string */
abstract fun getPermission(): String

/** Return a human-readable label for the permission */
fun getLabel(): String {
/** Return the string resource for the human-readable permission label. */
@StringRes
fun getLabelRes(): Int {
return when (this) {
CAMERA -> "Camera"
POST_NOTIFICATIONS -> "Notification"
ACCESS_LOCAL_NETWORK -> "Local Network"
CAMERA -> R.string.permission_camera
POST_NOTIFICATIONS -> R.string.permission_notification
ACCESS_LOCAL_NETWORK -> R.string.permission_local_network
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ object SpeedtestManager {
return -1
}

fun getRemoteIPInfo(): String? {
fun getRemoteIPInfo(unknownLabel: String): String? {
val url = MmkvManager.decodeSettingsString(AppConfig.PREF_IP_API_URL)
.takeIf { !it.isNullOrBlank() } ?: AppConfig.IP_API_URL

Expand Down Expand Up @@ -81,6 +81,6 @@ object SpeedtestManager {
ipInfo.location?.country_code
).firstOrNull { !it.isNullOrBlank() }

return "(${country ?: "unknown"}) ${ip ?: "unknown"}"
return "(${country ?: unknownLabel}) ${ip ?: unknownLabel}"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ class PermissionHelper(private val activity: ComponentActivity) {
if (isGranted) {
onGranted()
} else {
val message = "${activity.getString(R.string.toast_permission_denied)} ${permissionType.getLabel()}"
val message = activity.getString(
R.string.toast_permission_denied_for,
activity.getString(permissionType.getLabelRes())
)
activity.toast(message)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class SubscriptionUpdateService : Service() {
showNotification(
context = this,
titleResId = R.string.title_pref_auto_update_subscription,
content = "Updating ${subItem.remarks}"
content = getString(R.string.subscription_update_updating, subItem.remarks)
)

if (forcedUpdate || MmkvManager.decodeSettingsBool(AppConfig.PREF_UPDATE_SUBSCRIPTION, false)) {
Expand Down Expand Up @@ -184,7 +184,7 @@ class SubscriptionUpdateService : Service() {
private fun handleWorkerEvent(event: RealPingEvent, remarks: String, onWorkerDone: () -> Unit) {
when (event) {
is RealPingEvent.Progress -> {
val text = "${event.text} in $remarks"
val text = getString(R.string.subscription_update_progress, event.text, remarks)
showNotification(
context = this,
titleResId = R.string.title_real_ping_all_server,
Expand Down
3 changes: 2 additions & 1 deletion V2rayNG/app/src/main/java/com/v2ray/ang/ui/AboutActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ fun AboutScreen(onBackClick: () -> Unit) {
val context = LocalContext.current
var showOssDialog by remember { mutableStateOf(false) }

val versionText = "v${BuildConfig.VERSION_NAME} (${CoreNativeManager.getLibVersion()})"
val libVersion = CoreNativeManager.getLibVersion() ?: stringResource(R.string.value_unknown)
val versionText = "v${BuildConfig.VERSION_NAME} ($libVersion)"
val appIdText = BuildConfig.APPLICATION_ID

Scaffold(
Expand Down
13 changes: 9 additions & 4 deletions V2rayNG/app/src/main/java/com/v2ray/ang/ui/ScannerActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,9 @@ fun ScannerScreen(
if (isScanning) R.drawable.ic_stop_24dp
else R.drawable.ic_scan_24dp
),
contentDescription = if (isScanning) "stop scan" else "start scan"
contentDescription = stringResource(
if (isScanning) R.string.acc_stop_scanner else R.string.acc_start_scanner
)
)
}
if (isScanning && hasTorch) {
Expand All @@ -194,14 +196,17 @@ fun ScannerScreen(
if (torchEnabled) R.drawable.ic_flash_on_24dp
else R.drawable.ic_flash_off_24dp
),
contentDescription = "Torch"
contentDescription = stringResource(
if (torchEnabled) R.string.acc_turn_torch_off
else R.string.acc_turn_torch_on
)
)
}
}
IconButton(onClick = onSelectPhoto) {
Icon(
painterResource(R.drawable.ic_image_24dp),
contentDescription = "select image"
contentDescription = stringResource(R.string.acc_select_image)
)
}
}
Expand Down Expand Up @@ -245,7 +250,7 @@ private fun ScannerIdlePlaceholder(onStartClick: () -> Unit) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Icon(
painter = painterResource(R.drawable.ic_scan_24dp),
contentDescription = "Start Scanner",
contentDescription = stringResource(R.string.acc_start_scanner),
modifier = Modifier.size(80.dp),
tint = MaterialTheme.colorScheme.primary
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ fun AppPickerScreen(
IconButton(onClick = { showSearch = true }) {
Icon(
painterResource(R.drawable.ic_search_24dp),
contentDescription = stringResource(R.string.menu_item_search)
contentDescription = stringResource(R.string.acc_search)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ fun CheckUpdateScreen(
val showUpdateDialog by viewModel.showUpdateDialog.collectAsStateWithLifecycle()
val updateResult by viewModel.updateResult.collectAsStateWithLifecycle()

val versionText = "v${BuildConfig.VERSION_NAME} (${CoreNativeManager.getLibVersion()})"
val libVersion = CoreNativeManager.getLibVersion() ?: stringResource(R.string.value_unknown)
val versionText = "v${BuildConfig.VERSION_NAME} ($libVersion)"

Scaffold(
contentWindowInsets = ScaffoldDefaults.contentWindowInsets,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.style.TextOverflow
Expand Down Expand Up @@ -91,7 +92,7 @@ fun AppTopBar(
IconButton(onClick = if (isSearchActive) onSearchClose else onBackClick) {
Icon(
painter = painterResource(R.drawable.ic_arrow_back_24dp),
contentDescription = "Back"
contentDescription = stringResource(R.string.acc_back)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ fun QRCodeDialog(
text = {
Image(
bitmap = bitmap.asImageBitmap(),
contentDescription = stringResource(R.string.title_qr_code),
contentDescription = stringResource(R.string.acc_qr_code),
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,28 +159,28 @@ fun LogcatScreen(
IconButton(onClick = { showSearch = true }) {
Icon(
painterResource(R.drawable.ic_search_24dp),
contentDescription = "filter"
contentDescription = stringResource(R.string.acc_search)
)
}
}
IconButton(onClick = { viewModel.copyLogcat() }) {
Icon(
painterResource(R.drawable.ic_copy),
contentDescription = stringResource(R.string.logcat_copy)
contentDescription = stringResource(R.string.acc_copy_log)
)
}
IconButton(onClick = { onShareLogcat() }) {
Icon(
painterResource(R.drawable.ic_share_24dp),
contentDescription = stringResource(R.string.logcat_share)
contentDescription = stringResource(R.string.acc_share_log)
)
}
IconButton(onClick = {
scope.launch(Dispatchers.IO) { viewModel.clearLogcat() }
}) {
Icon(
painterResource(R.drawable.ic_delete_24dp),
contentDescription = stringResource(R.string.logcat_clear)
contentDescription = stringResource(R.string.acc_clear_log)
)
}
}
Expand All @@ -192,7 +192,7 @@ fun LogcatScreen(
}) {
Icon(
painterResource(R.drawable.ic_restore_24dp),
contentDescription = stringResource(R.string.pull_down_to_refresh)
contentDescription = stringResource(R.string.acc_refresh)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.v2ray.ang.R
import com.v2ray.ang.ui.compose.AppDivider
Expand Down Expand Up @@ -75,7 +76,9 @@ fun MainBottomBar(
Icon(
painter = if (isRunning) painterResource(R.drawable.ic_stop_24dp)
else painterResource(R.drawable.ic_play_24dp),
contentDescription = if (isRunning) "Stop" else "Start",
contentDescription = stringResource(
if (isRunning) R.string.acc_stop else R.string.acc_start
),
tint = Color.White,
modifier = Modifier.size(24.dp)
)
Expand Down
Loading