Skip to content

Commit

Permalink
Move dialog handling to activity
Browse files Browse the repository at this point in the history
  • Loading branch information
Pururun committed Dec 3, 2024
1 parent d312f47 commit e924b4a
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 55 deletions.
Original file line number Diff line number Diff line change
@@ -1,35 +1,21 @@
package net.mullvad.mullvadvpn.compose.screen

import android.content.Intent
import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTagsAsResourceId
import androidx.navigation.NavHostController
import arrow.core.merge
import co.touchlab.kermit.Logger
import com.ramcosta.composedestinations.DestinationsNavHost
import com.ramcosta.composedestinations.generated.NavGraphs
import com.ramcosta.composedestinations.generated.destinations.NoDaemonDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.rememberNavHostEngine
import com.ramcosta.composedestinations.utils.rememberDestinationsNavigator
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.filter
import net.mullvad.mullvadvpn.compose.util.CreateVpnProfile
import net.mullvad.mullvadvpn.lib.common.constant.KEY_REQUEST_VPN_PROFILE
import net.mullvad.mullvadvpn.lib.common.util.prepareVpnSafe
import net.mullvad.mullvadvpn.lib.model.PrepareError
import net.mullvad.mullvadvpn.lib.model.Prepared
import net.mullvad.mullvadvpn.util.getActivity
import net.mullvad.mullvadvpn.viewmodel.DaemonScreenEvent
import net.mullvad.mullvadvpn.viewmodel.MullvadAppViewModel
import org.koin.androidx.compose.koinViewModel
Expand All @@ -48,27 +34,6 @@ fun MullvadApp() {
onDispose { navHostController.removeOnDestinationChangedListener(mullvadAppViewModel) }
}

// Get intents
val launchVpnPermission =
rememberLauncherForActivityResult(CreateVpnProfile()) { _ -> mullvadAppViewModel.connect() }
val activity = LocalContext.current.getActivity() as ComponentActivity
LaunchedEffect(navHostController) {
activity
.intents()
.filter { it.action == KEY_REQUEST_VPN_PROFILE }
.collect {
val prepareResult = activity.prepareVpnSafe().merge()
when (prepareResult) {
is PrepareError.NotPrepared ->
launchVpnPermission.launch(prepareResult.prepareIntent)
// If legacy or other always on connect at let daemon generate a error state
is PrepareError.OtherLegacyAlwaysOnVpn,
is PrepareError.OtherAlwaysOnApp,
Prepared -> mullvadAppViewModel.connect()
}
}
}

DestinationsNavHost(
modifier = Modifier.semantics { testTagsAsResourceId = true }.fillMaxSize(),
engine = engine,
Expand All @@ -92,14 +57,3 @@ fun MullvadApp() {
}
}
}

private fun ComponentActivity.intents() =
callbackFlow<Intent> {
send(intent)

val listener: (Intent) -> Unit = { trySend(it) }

addOnNewIntentListener(listener)

awaitClose { removeOnNewIntentListener(listener) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,24 @@ import androidx.core.view.WindowCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import arrow.core.merge
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.compose.screen.MullvadApp
import net.mullvad.mullvadvpn.compose.util.CreateVpnProfile
import net.mullvad.mullvadvpn.di.paymentModule
import net.mullvad.mullvadvpn.di.uiModule
import net.mullvad.mullvadvpn.lib.common.constant.KEY_REQUEST_VPN_PROFILE
import net.mullvad.mullvadvpn.lib.common.util.SdkUtils.requestNotificationPermissionIfMissing
import net.mullvad.mullvadvpn.lib.common.util.prepareVpnSafe
import net.mullvad.mullvadvpn.lib.daemon.grpc.GrpcConnectivityState
import net.mullvad.mullvadvpn.lib.daemon.grpc.ManagementService
import net.mullvad.mullvadvpn.lib.intent.IntentProvider
import net.mullvad.mullvadvpn.lib.model.PrepareError
import net.mullvad.mullvadvpn.lib.model.Prepared
import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.repository.PrivacyDisclaimerRepository
import net.mullvad.mullvadvpn.repository.SplashCompleteRepository
Expand All @@ -38,6 +46,8 @@ class MainActivity : ComponentActivity(), AndroidScopeComponent {
// NotificationManager.areNotificationsEnabled is used to check the state rather than
// handling the callback value.
}
private val launchVpnPermission =
registerForActivityResult(CreateVpnProfile()) { _ -> mullvadAppViewModel.connect() }

private val intentProvider by inject<IntentProvider>()
private val mullvadAppViewModel by inject<MullvadAppViewModel>()
Expand Down Expand Up @@ -65,15 +75,14 @@ class MainActivity : ComponentActivity(), AndroidScopeComponent {

super.onCreate(savedInstanceState)

// Needs to be before set content since we want to access the intent in compose
if (savedInstanceState == null) {
intentProvider.setStartIntent(intent)
}
setContent { AppTheme { MullvadApp() } }

// This is to protect against tapjacking attacks
window.decorView.filterTouchesWhenObscured = true

// Needs to be before we start the service, since we need to access the intent there
setUpIntentListener()

// We use lifecycleScope here to get less start service in background exceptions
// Se this article for more information:
// https://medium.com/@lepicekmichal/android-background-service-without-hiccup-501e4479110f
Expand All @@ -100,11 +109,6 @@ class MainActivity : ComponentActivity(), AndroidScopeComponent {
}
}

override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
intentProvider.setStartIntent(intent)
}

fun bindService() {
requestNotificationPermissionIfMissing(requestNotificationPermissionLauncher)
serviceConnectionManager.bind()
Expand All @@ -121,4 +125,38 @@ class MainActivity : ComponentActivity(), AndroidScopeComponent {
lifecycle.removeObserver(mullvadAppViewModel)
super.onDestroy()
}

private fun setUpIntentListener() {
lifecycleScope.launch {
intents().collect {
if (it.action == KEY_REQUEST_VPN_PROFILE) {
handleRequestVpnProfileIntent()
} else {
intentProvider.setStartIntent(it)
}
}
}
}

private fun handleRequestVpnProfileIntent() {
val prepareResult = prepareVpnSafe().merge()
when (prepareResult) {
is PrepareError.NotPrepared -> launchVpnPermission.launch(prepareResult.prepareIntent)
// If legacy or other always on connect at let daemon generate a error state
is PrepareError.OtherLegacyAlwaysOnVpn,
is PrepareError.OtherAlwaysOnApp,
Prepared -> mullvadAppViewModel.connect()
}
}

private fun ComponentActivity.intents() =
callbackFlow<Intent> {
send(intent)

val listener: (Intent) -> Unit = { trySend(it) }

addOnNewIntentListener(listener)

awaitClose { removeOnNewIntentListener(listener) }
}
}

0 comments on commit e924b4a

Please sign in to comment.