fix: logs export bug, export file naming

This commit is contained in:
Zane Schepke
2025-09-26 09:46:30 -04:00
parent acdefd80fa
commit 7c3eabb19b
9 changed files with 79 additions and 29 deletions
@@ -191,7 +191,6 @@ class MainActivity : AppCompatActivity() {
requestingAppMode = Pair(sideEffect.requestingMode, sideEffect.config)
vpnActivity.launch(VpnService.prepare(this@MainActivity))
}
is GlobalSideEffect.ShareFile -> context.launchShareFile(sideEffect.file)
is GlobalSideEffect.Snackbar ->
scope.launch {
snackbar.showSnackbar(sideEffect.message.asString(context))
@@ -14,8 +14,6 @@ sealed class GlobalSideEffect {
data object PopBackStack : GlobalSideEffect()
data class ShareFile(val file: File) : GlobalSideEffect()
data class LaunchUrl(val url: String) : GlobalSideEffect()
data object ConfigChanged : GlobalSideEffect()
@@ -69,7 +69,16 @@ fun LogsScreen(viewModel: LoggerViewModel = hiltViewModel()) {
}
if (showLogsSheet) {
LogsBottomSheet({ viewModel.exportLogs() }, { viewModel.deleteLogs() }) {
LogsBottomSheet(
{ uri ->
viewModel.exportLogs(uri)
showLogsSheet = false
},
{
viewModel.deleteLogs()
showLogsSheet = false
},
) {
showLogsSheet = false
}
}
@@ -1,24 +1,53 @@
package com.zaneschepke.wireguardautotunnel.ui.screens.settings.logs.components
import android.net.Uri
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.FolderZip
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import com.zaneschepke.wireguardautotunnel.BuildConfig
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.ui.common.functions.rememberFileExportLauncherForResult
import com.zaneschepke.wireguardautotunnel.ui.common.sheet.CustomBottomSheet
import com.zaneschepke.wireguardautotunnel.ui.common.sheet.SheetOption
import com.zaneschepke.wireguardautotunnel.util.Constants
import com.zaneschepke.wireguardautotunnel.util.FileUtils
import com.zaneschepke.wireguardautotunnel.util.extensions.hasSAFSupport
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LogsBottomSheet(onExport: () -> Unit, onDelete: () -> Unit, onDismiss: () -> Unit) {
fun LogsBottomSheet(onExport: (file: Uri?) -> Unit, onDelete: () -> Unit, onDismiss: () -> Unit) {
val context = LocalContext.current
val selectedTunnelsExportLauncher =
rememberFileExportLauncherForResult(
mimeType = FileUtils.ZIP_FILE_MIME_TYPE,
onResult = { file ->
if (file != null) {
onExport(file)
} else onDismiss()
},
)
fun handleFileExport() {
if (context.hasSAFSupport(FileUtils.ZIP_FILE_MIME_TYPE)) {
selectedTunnelsExportLauncher.launch(
"${Constants.BASE_LOG_FILE_NAME}_${BuildConfig.VERSION_NAME}_${BuildConfig.FLAVOR}.zip"
)
} else {
onExport(null)
}
}
CustomBottomSheet(
listOf(
SheetOption(
Icons.Outlined.FolderZip,
stringResource(R.string.export_logs),
onClick = onExport,
onClick = { handleFileExport() },
),
SheetOption(
Icons.Outlined.Delete,
@@ -11,9 +11,9 @@ import com.zaneschepke.wireguardautotunnel.domain.enums.ConfigType
import com.zaneschepke.wireguardautotunnel.ui.common.functions.rememberFileExportLauncherForResult
import com.zaneschepke.wireguardautotunnel.ui.common.sheet.CustomBottomSheet
import com.zaneschepke.wireguardautotunnel.ui.common.sheet.SheetOption
import com.zaneschepke.wireguardautotunnel.util.Constants
import com.zaneschepke.wireguardautotunnel.util.FileUtils
import com.zaneschepke.wireguardautotunnel.util.extensions.hasSAFSupport
import java.time.Instant
@Composable
fun ExportTunnelsBottomSheet(
@@ -37,7 +37,12 @@ fun ExportTunnelsBottomSheet(
fun handleFileExport() {
if (context.hasSAFSupport(FileUtils.ZIP_FILE_MIME_TYPE)) {
selectedTunnelsExportLauncher.launch(Constants.DEFAULT_EXPORT_FILE_NAME)
val fileName =
when (exportConfigType) {
ConfigType.AM -> "am_export_${Instant.now().epochSecond}.zip"
ConfigType.WG -> "wg_export_${Instant.now().epochSecond}.zip"
}
selectedTunnelsExportLauncher.launch(fileName)
} else {
onExport(exportConfigType, null)
}
@@ -9,8 +9,6 @@ object Constants {
const val SYSTEM_EXEMPT_SERVICE_TYPE_ID = 1 shl 10
const val SPECIAL_USE_SERVICE_TYPE_ID = 1 shl 30
const val DEFAULT_EXPORT_FILE_NAME = "wgtunnel-export.zip"
const val QR_CODE_NAME_PROPERTY = "# Name ="
const val FDROID_FLAVOR = "fdroid"
@@ -1,7 +1,9 @@
package com.zaneschepke.wireguardautotunnel.viewmodel
import android.net.Uri
import androidx.lifecycle.ViewModel
import com.zaneschepke.logcatter.LogReader
import com.zaneschepke.wireguardautotunnel.BuildConfig
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.domain.repository.AppStateRepository
import com.zaneschepke.wireguardautotunnel.domain.repository.GlobalEffectRepository
@@ -11,7 +13,6 @@ import com.zaneschepke.wireguardautotunnel.util.Constants
import com.zaneschepke.wireguardautotunnel.util.FileUtils
import com.zaneschepke.wireguardautotunnel.util.StringValue
import dagger.hilt.android.lifecycle.HiltViewModel
import java.time.Instant
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
@@ -71,18 +72,30 @@ constructor(
globalEffectRepository.post(globalSideEffect)
}
fun exportLogs() = intent {
fun exportLogs(uri: Uri?) = intent {
val result =
fileUtils.createNewShareFile(
"${Constants.BASE_LOG_FILE_NAME}-${Instant.now().epochSecond}.zip"
"${Constants.BASE_LOG_FILE_NAME}_${BuildConfig.VERSION_NAME}_${BuildConfig.FLAVOR}.zip"
)
result.onSuccess { file -> postSideEffect(GlobalSideEffect.ShareFile(file)) }
result.onFailure { error ->
val message =
error.message?.let { StringValue.DynamicString(it) }
?: StringValue.StringResource(R.string.unknown_error)
postSideEffect(GlobalSideEffect.Toast(message))
val onFailure = { action: Throwable ->
Timber.e(action)
intent {
postSideEffect(
GlobalSideEffect.Toast(
StringValue.StringResource(
R.string.export_failed,
": ${action.localizedMessage}",
)
)
)
}
Unit
}
result.onSuccess { file ->
logReader.zipLogFiles(file.absolutePath)
fileUtils.exportFile(file, uri, FileUtils.ZIP_FILE_MIME_TYPE).onFailure(onFailure)
}
result.onFailure(onFailure)
}
fun deleteLogs() = intent {