diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/domain/TunnelConfig.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/domain/TunnelConfig.kt index 245a940d..028ebc7f 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/domain/TunnelConfig.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/domain/TunnelConfig.kt @@ -5,6 +5,7 @@ import androidx.room.Entity import androidx.room.Index import androidx.room.PrimaryKey import com.wireguard.config.Config +import com.zaneschepke.wireguardautotunnel.util.extensions.toWgQuickString import java.io.InputStream @Entity(indices = [Index(value = ["name"], unique = true)]) @@ -79,6 +80,12 @@ data class TunnelConfig( } } + fun tunnelConfigFromAmConfig(config: org.amnezia.awg.config.Config, name: String): TunnelConfig { + val amQuick = config.toAwgQuickString(true) + val wgQuick = config.toWgQuickString() + return TunnelConfig(name = name, wgQuick = wgQuick, amQuick = amQuick) + } + const val AM_QUICK_DEFAULT = "" } } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt index 3c2628cc..a9728cee 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt @@ -37,6 +37,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp @@ -68,6 +69,7 @@ import com.zaneschepke.wireguardautotunnel.util.extensions.scaledHeight fun MainScreen(viewModel: MainViewModel = hiltViewModel(), uiState: AppUiState) { val context = LocalContext.current val navController = LocalNavController.current + val clipboard = LocalClipboardManager.current val snackbar = SnackbarController.current var showBottomSheet by remember { mutableStateOf(false) } @@ -201,12 +203,17 @@ fun MainScreen(viewModel: MainViewModel = hiltViewModel(), uiState: AppUiState) ) } }, - ) { + ) { padding -> TunnelImportSheet( showBottomSheet, onDismiss = { showBottomSheet = false }, onFileClick = { tunnelFileImportResultLauncher.launch(Constants.ALLOWED_TV_FILE_TYPES) }, onQrClick = { requestPermissionLauncher.launch(android.Manifest.permission.CAMERA) }, + onClipboardClick = { + clipboard.getText()?.text?.let { + viewModel.onClipboardImport(it) + } + }, onManualImportClick = { navController.navigate( Route.Config(Constants.MANUAL_TUNNEL_CONFIG_ID), @@ -218,7 +225,7 @@ fun MainScreen(viewModel: MainViewModel = hiltViewModel(), uiState: AppUiState) verticalArrangement = Arrangement.spacedBy(5.dp.scaledHeight(), Alignment.Top), modifier = Modifier - .fillMaxSize().padding(it) + .fillMaxSize().padding(padding) .overscroll(ScrollableDefaults.overscrollEffect()) .nestedScroll(nestedScrollConnection), state = rememberLazyListState(0, uiState.tunnels.count()), diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainViewModel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainViewModel.kt index bd3d24be..c6394fe8 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainViewModel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainViewModel.kt @@ -261,4 +261,14 @@ constructor( ), ) } + + fun onClipboardImport(config: String) = viewModelScope.launch(ioDispatcher) { + runCatching { + val amConfig = TunnelConfig.configFromAmQuick(config) + val tunnelConfig = TunnelConfig.tunnelConfigFromAmConfig(amConfig, makeTunnelNameUnique(generateQrCodeDefaultName(config))) + saveTunnel(tunnelConfig) + }.onFailure { + SnackbarController.showMessage(StringValue.StringResource(R.string.error_file_format)) + } + } } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/components/TunnelImportSheet.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/components/TunnelImportSheet.kt index c0cf4586..4007f4a7 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/components/TunnelImportSheet.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/components/TunnelImportSheet.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ContentPasteGo import androidx.compose.material.icons.filled.Create import androidx.compose.material.icons.filled.FileOpen import androidx.compose.material.icons.filled.QrCode @@ -22,9 +23,17 @@ import androidx.compose.ui.unit.dp import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.util.extensions.isRunningOnTv +// TODO refactor this component @OptIn(ExperimentalMaterial3Api::class) @Composable -fun TunnelImportSheet(show: Boolean, onDismiss: () -> Unit, onFileClick: () -> Unit, onQrClick: () -> Unit, onManualImportClick: () -> Unit) { +fun TunnelImportSheet( + show: Boolean, + onDismiss: () -> Unit, + onFileClick: () -> Unit, + onQrClick: () -> Unit, + onManualImportClick: () -> Unit, + onClipboardClick: () -> Unit, +) { val sheetState = rememberModalBottomSheetState() val context = LocalContext.current @@ -77,6 +86,28 @@ fun TunnelImportSheet(show: Boolean, onDismiss: () -> Unit, onFileClick: () -> U modifier = Modifier.padding(10.dp), ) } + HorizontalDivider() + Row( + modifier = + Modifier + .fillMaxWidth() + .clickable { + onDismiss() + onClipboardClick() + } + .padding(10.dp), + ) { + val icon = Icons.Filled.ContentPasteGo + Icon( + icon, + contentDescription = icon.name, + modifier = Modifier.padding(10.dp), + ) + Text( + stringResource(id = R.string.add_from_clipboard), + modifier = Modifier.padding(10.dp), + ) + } } HorizontalDivider() Row( diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/scanner/ScannerScreen.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/scanner/ScannerScreen.kt index c6a9dfdc..ab6da8eb 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/scanner/ScannerScreen.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/scanner/ScannerScreen.kt @@ -9,11 +9,9 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.viewinterop.AndroidView import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.journeyapps.barcodescanner.CompoundBarcodeView import com.zaneschepke.wireguardautotunnel.ui.common.navigation.LocalNavController -@OptIn(ExperimentalPermissionsApi::class) @Composable fun ScannerScreen(viewModel: ScannerViewModel = hiltViewModel()) { val context = LocalContext.current diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/scanner/ScannerViewModel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/scanner/ScannerViewModel.kt index 21b08d00..c39b15fd 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/scanner/ScannerViewModel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/scanner/ScannerViewModel.kt @@ -9,7 +9,6 @@ import com.zaneschepke.wireguardautotunnel.module.IoDispatcher import com.zaneschepke.wireguardautotunnel.ui.common.snackbar.SnackbarController import com.zaneschepke.wireguardautotunnel.util.NumberUtils import com.zaneschepke.wireguardautotunnel.util.StringValue -import com.zaneschepke.wireguardautotunnel.util.extensions.toWgQuickString import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.MutableSharedFlow @@ -45,10 +44,7 @@ constructor( fun onTunnelQrResult(result: String) = viewModelScope.launch(ioDispatcher) { kotlin.runCatching { val amConfig = TunnelConfig.configFromAmQuick(result) - val amQuick = amConfig.toAwgQuickString(true) - val wgQuick = amConfig.toWgQuickString() - val tunnelName = makeTunnelNameUnique(generateQrCodeDefaultName(result)) - val tunnelConfig = TunnelConfig(name = tunnelName, wgQuick = wgQuick, amQuick = amQuick) + val tunnelConfig = TunnelConfig.tunnelConfigFromAmConfig(amConfig, makeTunnelNameUnique(generateQrCodeDefaultName(result))) appDataRepository.tunnels.save(tunnelConfig) _success.emit(true) }.onFailure { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 25e4c071..904803b4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -177,4 +177,5 @@ Enable local logging Configuration change This change requires an app relaunch. Would you like to proceed? + Add from clipboard