fix: email launch and tunnel import mobile

This commit is contained in:
Zane Schepke 2024-10-13 23:03:59 -04:00
parent e11f0f794a
commit 7fdd95ea51
10 changed files with 36 additions and 79 deletions

View File

@ -133,8 +133,6 @@ android {
packaging { resources { excludes += "/META-INF/{AL2.0,LGPL2.1}" } }
}
val generalImplementation by configurations
dependencies {
implementation(project(":logcatter"))

View File

@ -60,6 +60,7 @@ import com.zaneschepke.wireguardautotunnel.ui.screens.support.SupportScreen
import com.zaneschepke.wireguardautotunnel.ui.screens.support.logs.LogsScreen
import com.zaneschepke.wireguardautotunnel.ui.theme.WireguardAutoTunnelTheme
import com.zaneschepke.wireguardautotunnel.util.Constants
import com.zaneschepke.wireguardautotunnel.util.extensions.requestAutoTunnelTileServiceUpdate
import com.zaneschepke.wireguardautotunnel.util.extensions.requestTunnelTileServiceStateUpdate
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@ -103,6 +104,12 @@ class MainActivity : AppCompatActivity() {
context.requestTunnelTileServiceStateUpdate()
}
with(appUiState.settings) {
LaunchedEffect(isAutoTunnelPaused, isAutoTunnelEnabled) {
this@MainActivity.requestAutoTunnelTileServiceUpdate()
}
}
CompositionLocalProvider(LocalNavController provides navController) {
SnackbarControllerProvider { host ->
WireguardAutoTunnelTheme {

View File

@ -10,6 +10,7 @@ import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable
import com.zaneschepke.wireguardautotunnel.util.Constants
import com.zaneschepke.wireguardautotunnel.util.extensions.isRunningOnTv
@Composable
fun rememberFileImportLauncherForResult(onNoFileExplorer: () -> Unit, onData: (data: Uri) -> Unit): ManagedActivityResultLauncher<String, Uri?> {
@ -17,7 +18,11 @@ fun rememberFileImportLauncherForResult(onNoFileExplorer: () -> Unit, onData: (d
object : ActivityResultContracts.GetContent() {
override fun createIntent(context: Context, input: String): Intent {
val intent = super.createIntent(context, input).apply {
type = Constants.ALLOWED_FILE_TYPES
type = if (context.isRunningOnTv()) {
Constants.ALLOWED_TV_FILE_TYPES
} else {
Constants.ALL_FILE_TYPES
}
}
/* AndroidTV now comes with stubs that do nothing but display a Toast less helpful than

View File

@ -31,7 +31,6 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
@ -181,7 +180,7 @@ fun MainScreen(viewModel: MainViewModel = hiltViewModel(), uiState: AppUiState,
TunnelImportSheet(
showBottomSheet,
onDismiss = { showBottomSheet = false },
onFileClick = { tunnelFileImportResultLauncher.launch(Constants.ALLOWED_FILE_TYPES) },
onFileClick = { tunnelFileImportResultLauncher.launch(Constants.ALLOWED_TV_FILE_TYPES) },
onQrClick = { launchQrScanner() },
onManualImportClick = {
navController.navigate(

View File

@ -37,8 +37,11 @@ fun TunnelStatisticsRow(statistics: TunnelStatistics?, tunnelConfig: TunnelConfi
val peerTxMB = NumberUtils.bytesToMB(peerTx).toThreeDecimalPlaceString()
val peerRxMB = NumberUtils.bytesToMB(peerRx).toThreeDecimalPlaceString()
val handshake = statistics?.peerStats(it.publicKey)?.latestHandshakeEpochMillis?.let {
if(it == 0L) stringResource(R.string.never) else
"${NumberUtils.getSecondsBetweenTimestampAndNow(it)} ${stringResource(R.string.sec)}"
if (it == 0L) {
stringResource(R.string.never)
} else {
"${NumberUtils.getSecondsBetweenTimestampAndNow(it)} ${stringResource(R.string.sec)}"
}
} ?: stringResource(R.string.never)
Column(
verticalArrangement = Arrangement.spacedBy(10.dp),

View File

@ -22,7 +22,7 @@ fun PinLockScreen(appViewModel: AppViewModel) {
PinLock(
title = { pinExists ->
Text(
color = MaterialTheme.colorScheme.onSecondary,
color = MaterialTheme.colorScheme.onSurface,
text =
if (pinExists) {
stringResource(id = R.string.enter_pin)
@ -33,7 +33,8 @@ fun PinLockScreen(appViewModel: AppViewModel) {
},
)
},
color = MaterialTheme.colorScheme.secondary,
backgroundColor = MaterialTheme.colorScheme.surface,
textColor = MaterialTheme.colorScheme.onSurface,
onPinCorrect = {
// pin is correct, navigate or hide pin lock
if (context.isRunningOnTv()) {

View File

@ -13,11 +13,11 @@ object Constants {
const val URI_CONTENT_SCHEME = "content"
const val TEXT_MIME_TYPE = "text/plain"
const val ZIP_FILE_MIME_TYPE = "application/zip"
const val ALLOWED_FILE_TYPES = "${TEXT_MIME_TYPE}|${ZIP_FILE_MIME_TYPE}"
const val ALLOWED_TV_FILE_TYPES = "${TEXT_MIME_TYPE}|${ZIP_FILE_MIME_TYPE}"
const val ALL_FILE_TYPES = "*/*"
const val GOOGLE_TV_EXPLORER_STUB = "com.google.android.tv.frameworkpackagestubs"
const val ANDROID_TV_EXPLORER_STUB = "com.android.tv.frameworkpackagestubs"
const val VPN_SETTINGS_PACKAGE = "android.net.vpn.SETTINGS"
const val EMAIL_MIME_TYPE = "plain/text"
const val SYSTEM_EXEMPT_SERVICE_TYPE_ID = 1024
const val SUBSCRIPTION_TIMEOUT = 5_000L

View File

@ -12,8 +12,6 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.OutputStream
import java.time.Instant
import java.util.zip.ZipEntry
@ -23,23 +21,6 @@ class FileUtils(
private val context: Context,
private val ioDispatcher: CoroutineDispatcher,
) {
suspend fun readBytesFromFile(file: File): ByteArray {
return withContext(ioDispatcher) {
FileInputStream(file).use {
it.readBytes()
}
}
}
suspend fun readTextFromFileName(fileName: String): String {
return withContext(ioDispatcher) {
context.assets.open(fileName).use { stream ->
stream.bufferedReader(Charsets.UTF_8).use {
it.readText()
}
}
}
}
fun createWgFiles(tunnels: TunnelConfigs): List<File> {
return tunnels.map { config ->
@ -61,43 +42,6 @@ class FileUtils(
}
}
suspend fun saveByteArrayToDownloads(content: ByteArray, fileName: String): Result<Unit> {
return withContext(ioDispatcher) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val contentValues =
ContentValues().apply {
put(MediaColumns.DISPLAY_NAME, fileName)
put(MediaColumns.MIME_TYPE, Constants.TEXT_MIME_TYPE)
put(MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
}
val resolver = context.contentResolver
val uri =
resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)
if (uri != null) {
resolver.openOutputStream(uri).use { output ->
output?.write(content)
}
}
} else {
val target =
File(
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS,
),
fileName,
)
FileOutputStream(target).use { output ->
output.write(content)
}
}
Result.success(Unit)
} catch (e: Exception) {
Result.failure(e)
}
}
}
suspend fun saveFilesToZip(files: List<File>): Result<Unit> {
return withContext(ioDispatcher) {
try {
@ -124,7 +68,7 @@ class FileUtils(
}
// TODO issue with android 9
private fun createDownloadsFileOutputStream(fileName: String, mimeType: String = Constants.ALLOWED_FILE_TYPES): OutputStream? {
private fun createDownloadsFileOutputStream(fileName: String, mimeType: String = Constants.ALL_FILE_TYPES): OutputStream? {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val resolver = context.contentResolver
val contentValues =

View File

@ -44,21 +44,21 @@ fun Context.showToast(resId: Int) {
).show()
}
fun Context.launchSupportEmail(): Result<Unit> {
return runCatching {
val intent =
Intent(Intent.ACTION_SENDTO).apply {
type = Constants.EMAIL_MIME_TYPE
putExtra(Intent.EXTRA_EMAIL, arrayOf(getString(R.string.my_email)))
putExtra(Intent.EXTRA_SUBJECT, getString(R.string.email_subject))
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
fun Context.launchSupportEmail() {
val intent =
Intent(Intent.ACTION_SENDTO).apply {
data = Uri.parse("mailto:")
putExtra(Intent.EXTRA_EMAIL, arrayOf(getString(R.string.my_email)))
putExtra(Intent.EXTRA_SUBJECT, getString(R.string.email_subject))
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(
Intent.createChooser(intent, getString(R.string.email_chooser)).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
},
)
}.onFailure {
} else {
showToast(R.string.no_email_detected)
}
}

View File

@ -17,7 +17,7 @@ kotlinx-serialization-json = "1.7.3"
lifecycle-runtime-compose = "2.8.6"
material3 = "1.3.0"
navigationCompose = "2.8.2"
pinLockCompose = "1.0.3"
pinLockCompose = "1.0.4"
roomVersion = "2.6.1"
timber = "5.0.1"
tunnel = "1.2.1"