diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/AppConfig.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/AppConfig.kt index 92072e16..98eed86d 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/AppConfig.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/AppConfig.kt @@ -9,7 +9,9 @@ object AppConfig { /** Directory names used in the app's file system. */ const val DIR_ASSETS = "assets" - const val DIR_BACKUPS = "backups" + + const val WEBDAV_BACKUP_DIR = "backups" + const val WEBDAV_BACKUP_FILE_NAME = "backup_ng.zip" /** Legacy configuration keys. */ const val ANG_CONFIG = "ang_config" diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/WebDavManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/WebDavManager.kt index 1da3ab48..b520d25d 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/WebDavManager.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/WebDavManager.kt @@ -35,18 +35,18 @@ object WebDavManager { } /** - * Upload a local file to a remote relative path under the configured remoteBasePath. - * The provided `remoteRelativePath` should be relative (e.g. "backup_ng.zip"). + * Upload a local file to a remote file name under the configured remoteBasePath. + * The provided `remoteFileName` should be a file name (e.g. "backup_ng.zip"). * The method will attempt to create parent directories via MKCOL before PUT. * * @param localFile File to upload. - * @param remoteRelativePath Remote path relative to configured remoteBasePath. + * @param remoteFileName Remote file name relative to configured remoteBasePath. * @return true if upload succeeded (HTTP 2xx), false otherwise. */ - suspend fun uploadFile(localFile: File, remoteRelativePath: String): Boolean = withContext(Dispatchers.IO) { + suspend fun uploadFile(localFile: File, remoteFileName: String): Boolean = withContext(Dispatchers.IO) { + val remote = buildRemoteUrl(remoteFileName) try { val cl = client ?: return@withContext false - val remote = buildRemoteUrl(remoteRelativePath) // Ensure parent directories exist val dirPath = remote.substringBeforeLast('/') @@ -67,14 +67,14 @@ object WebDavManager { cl.newCall(req).execute().use { resp -> val success = resp.isSuccessful if (success) { - Log.i(AppConfig.TAG, "WebDAV upload success: $remoteRelativePath") + Log.i(AppConfig.TAG, "WebDAV upload success: $remote") } else { - Log.e(AppConfig.TAG, "WebDAV upload failed: $remoteRelativePath (HTTP ${resp.code})") + Log.e(AppConfig.TAG, "WebDAV upload failed: $remote (HTTP ${resp.code})") } return@withContext success } } catch (e: Exception) { - Log.e(AppConfig.TAG, "WebDAV upload exception: $remoteRelativePath", e) + Log.e(AppConfig.TAG, "WebDAV upload exception: $remote", e) return@withContext false } } @@ -82,18 +82,18 @@ object WebDavManager { /** * Download a remote file (relative to configured remoteBasePath) into a local file. * - * @param remoteRelativePath Remote path relative to configured remoteBasePath. + * @param remoteFileName Remote file name relative to configured remoteBasePath. * @param destFile Local destination file to write to. * @return true if download and write succeeded, false otherwise. */ - suspend fun downloadFile(remoteRelativePath: String, destFile: File): Boolean = withContext(Dispatchers.IO) { + suspend fun downloadFile(remoteFileName: String, destFile: File): Boolean = withContext(Dispatchers.IO) { + val remote = buildRemoteUrl(remoteFileName) try { val cl = client ?: return@withContext false - val remote = buildRemoteUrl(remoteRelativePath) val req = applyAuth(Request.Builder().url(remote).get()).build() cl.newCall(req).execute().use { resp -> if (!resp.isSuccessful) { - Log.e(AppConfig.TAG, "WebDAV download failed: $remoteRelativePath (HTTP ${resp.code})") + Log.e(AppConfig.TAG, "WebDAV download failed: $remote (HTTP ${resp.code})") return@withContext false } @@ -104,29 +104,31 @@ object WebDavManager { } } - Log.i(AppConfig.TAG, "WebDAV download success: $remoteRelativePath") + Log.i(AppConfig.TAG, "WebDAV download success: $remote") return@withContext true } } catch (e: Exception) { - Log.e(AppConfig.TAG, "WebDAV download exception: $remoteRelativePath", e) + Log.e(AppConfig.TAG, "WebDAV download exception: $remote", e) return@withContext false } } /** * Build a full remote URL by combining the configured base URL, the configured - * remote base path and a relative path provided by the caller. + * remote base path and a file name provided by the caller. * * Example: baseUrl="https://example.com/remote.php/dav", remoteBasePath="backups", - * remoteRelativePath="backup_ng.zip" => "https://example.com/remote.php/dav/backups/backup_ng.zip" + * remoteFileName="backup_ng.zip" => "https://example.com/remote.php/dav/backups/backup_ng.zip" * - * @param remoteRelativePath A path relative to the configured remoteBasePath (no leading slash required). + * @param remoteFileName A file name relative to the configured remoteBasePath (no leading slash required). * @return Full URL string used for HTTP operations. */ - private fun buildRemoteUrl(remoteRelativePath: String): String { + private fun buildRemoteUrl(remoteFileName: String): String { val base = cfg?.baseUrl?.trimEnd('/') ?: "" - val basePath = cfg?.remoteBasePath?.trim('/') ?: "" - val rel = remoteRelativePath.trimStart('/') + // Use configured remoteBasePath when not empty; otherwise fallback to AppConfig.WEBDAV_BACKUP_DIR + val basePathConfigured = cfg?.remoteBasePath?.trim('/')?.takeIf { it.isNotEmpty() } + val basePath = basePathConfigured ?: AppConfig.WEBDAV_BACKUP_DIR + val rel = remoteFileName.trimStart('/') return if (basePath.isEmpty()) "$base/$rel" else "$base/$basePath/$rel" } @@ -170,7 +172,7 @@ object WebDavManager { Log.w(AppConfig.TAG, "WebDAV MKCOL $mkUrl returned ${resp.code}") } } - } catch (ignored: Exception) { + } catch (_: Exception) { // best-effort, continue } } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/BackupActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/BackupActivity.kt index ebcb2d1a..c8c406d4 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/BackupActivity.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/BackupActivity.kt @@ -14,6 +14,7 @@ import androidx.core.content.FileProvider import androidx.lifecycle.lifecycleScope import com.tencent.mmkv.MMKV import com.v2ray.ang.AppConfig +import com.v2ray.ang.AppConfig.WEBDAV_BACKUP_FILE_NAME import com.v2ray.ang.BuildConfig import com.v2ray.ang.R import com.v2ray.ang.databinding.ActivityBackupBinding @@ -40,10 +41,6 @@ class BackupActivity : BaseActivity() { resources.getStringArray(R.array.config_backup_options) } - companion object { - private const val BACKUP_FILE_NAME = "backup_ng.zip" - } - private val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> if (isGranted) { @@ -263,7 +260,7 @@ class BackupActivity : BaseActivity() { WebDavManager.init(saved) val ok = try { - WebDavManager.uploadFile(tempFile, BACKUP_FILE_NAME) + WebDavManager.uploadFile(tempFile, WEBDAV_BACKUP_FILE_NAME) } catch (e: Exception) { Log.e(AppConfig.TAG, "WebDAV upload error", e) false @@ -303,7 +300,7 @@ class BackupActivity : BaseActivity() { try { target = File(cacheDir, "download_${System.currentTimeMillis()}.zip") WebDavManager.init(saved) - val ok = WebDavManager.downloadFile(BACKUP_FILE_NAME, target) + val ok = WebDavManager.downloadFile(WEBDAV_BACKUP_FILE_NAME, target) if (!ok) { withContext(Dispatchers.Main) { toastError(R.string.toast_failure) @@ -351,7 +348,7 @@ class BackupActivity : BaseActivity() { val url = dialogBinding.etWebdavUrl.text.toString().trim() val user = dialogBinding.etWebdavUser.text.toString().trim().ifEmpty { null } val pass = dialogBinding.etWebdavPass.text.toString() - val remotePath = dialogBinding.etWebdavRemotePath.text.toString().trim().ifEmpty { "/" } + val remotePath = dialogBinding.etWebdavRemotePath.text.toString().trim().ifEmpty { AppConfig.WEBDAV_BACKUP_DIR } val cfg = WebDavConfig(baseUrl = url, username = user, password = pass, remoteBasePath = remotePath) MmkvManager.encodeWebDavConfig(cfg) toastSuccess(R.string.toast_success) diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/util/Utils.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/util/Utils.kt index 1ae9941f..8b9281c6 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/util/Utils.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/util/Utils.kt @@ -375,24 +375,6 @@ object Utils { } } - /** - * Get the path to the backup directory. - * - * @param context The context to use. - * @return The path to the backup directory. - */ - fun backupPath(context: Context?): String { - if (context == null) return "" - - return try { - context.getExternalFilesDir(AppConfig.DIR_BACKUPS)?.absolutePath - ?: context.getDir(AppConfig.DIR_BACKUPS, 0).absolutePath - } catch (e: Exception) { - Log.e(AppConfig.TAG, "Failed to get backup path", e) - "" - } - } - /** * Get the device ID for XUDP base key. *