Skip to content

Commit

Permalink
Migrate all navigation to compose navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
Rawa committed Nov 6, 2023
1 parent 46ff968 commit 1f7e719
Show file tree
Hide file tree
Showing 38 changed files with 909 additions and 355 deletions.
6 changes: 4 additions & 2 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ plugins {
id(Dependencies.Plugin.playPublisherId)
id(Dependencies.Plugin.kotlinAndroidId)
id(Dependencies.Plugin.kotlinParcelizeId)
id(Dependencies.Plugin.ksp) version Versions.Plugin.ksp
}

val repoRootPath = rootProject.projectDir.absoluteFile.parentFile.absolutePath
Expand Down Expand Up @@ -176,8 +177,7 @@ android {

val enableInAppVersionNotifications =
gradleLocalProperties(rootProject.projectDir)
.getProperty("ENABLE_IN_APP_VERSION_NOTIFICATIONS")
?: "true"
.getProperty("ENABLE_IN_APP_VERSION_NOTIFICATIONS") ?: "true"

buildConfigField(
"boolean",
Expand Down Expand Up @@ -316,6 +316,8 @@ dependencies {
implementation(Dependencies.Compose.uiController)
implementation(Dependencies.Compose.ui)
implementation(Dependencies.Compose.uiUtil)
implementation(Dependencies.Compose.destinations)
ksp("io.github.raamcosta.compose-destinations:ksp:1.9.54")
implementation(Dependencies.jodaTime)
implementation(Dependencies.Koin.core)
implementation(Dependencies.Koin.android)
Expand Down
92 changes: 54 additions & 38 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,42 +1,54 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-feature android:name="android.hardware.touchscreen"
android:required="false" />
<uses-feature android:name="android.hardware.faketouch"
android:required="false" />
<uses-feature android:name="android.hardware.screen.portrait"
android:required="false" />
<uses-feature android:name="android.hardware.screen.landscape"
android:required="false" />
<uses-feature android:name="android.software.leanback"
android:required="false" />
<application android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher"
android:theme="@style/AppTheme"
android:extractNativeLibs="true"
android:allowBackup="false"
android:banner="@drawable/banner"
android:name=".MullvadApplication"
tools:ignore="GoogleAppIndexingWarning">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />

<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
<uses-feature
android:name="android.hardware.faketouch"
android:required="false" />
<uses-feature
android:name="android.hardware.screen.portrait"
android:required="false" />
<uses-feature
android:name="android.hardware.screen.landscape"
android:required="false" />
<uses-feature
android:name="android.software.leanback"
android:required="false" />

<application
android:name=".MullvadApplication"
android:allowBackup="false"
android:banner="@drawable/banner"
android:extractNativeLibs="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<!--
MainActivity
Must be exported in order to be launchable.
-->
<activity android:name="net.mullvad.mullvadvpn.ui.MainActivity"
android:exported="true"
android:label="@string/app_name"
android:launchMode="singleTask"
android:configChanges="orientation|screenSize|screenLayout"
android:screenOrientation="locked"
android:windowSoftInputMode="adjustPan">
<activity
android:name="net.mullvad.mullvadvpn.ui.MainActivity"
android:configChanges="orientation|screenSize|screenLayout"
android:exported="true"
android:label="@string/app_name"
android:launchMode="singleTask"
android:screenOrientation="locked"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
Expand All @@ -50,11 +62,14 @@
however as it's protected by the bind vpn permission
(android.permission.BIND_VPN_SERVICE) it's protected against third party apps/services.
-->
<service android:name="net.mullvad.mullvadvpn.service.MullvadVpnService"
android:exported="true"
android:permission="android.permission.BIND_VPN_SERVICE"
android:process=":mullvadvpn_daemon"
android:stopWithTask="false">
<service
android:name="net.mullvad.mullvadvpn.service.MullvadVpnService"
android:exported="true"
android:permission="android.permission.BIND_VPN_SERVICE"
android:foregroundServiceType="systemExempted"
android:process=":mullvadvpn_daemon"
android:stopWithTask="false">

<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
Expand All @@ -73,12 +88,13 @@
Tile services must be exported and protected by the bind tile permission
(android.permission.BIND_QUICK_SETTINGS_TILE).
-->
<service android:name="net.mullvad.mullvadvpn.tile.MullvadTileService"
android:exported="true"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:label="@string/toggle_vpn"
android:icon="@drawable/small_logo_black"
android:process=":mullvadvpn_tile">
<service
android:name="net.mullvad.mullvadvpn.tile.MullvadTileService"
android:exported="true"
android:icon="@drawable/small_logo_black"
android:label="@string/toggle_vpn"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:process=":mullvadvpn_tile">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:OptIn(ExperimentalMaterial3Api::class)

package net.mullvad.mullvadvpn.compose.screen

import androidx.compose.animation.animateContentSize
Expand All @@ -15,6 +17,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand All @@ -26,6 +29,9 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.popUpTo
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
Expand All @@ -39,6 +45,9 @@ import net.mullvad.mullvadvpn.compose.component.MissingPolicy
import net.mullvad.mullvadvpn.compose.component.NavigateBackDownIconButton
import net.mullvad.mullvadvpn.compose.component.ScaffoldWithMediumTopBar
import net.mullvad.mullvadvpn.compose.dialog.DeviceNameInfoDialog
import net.mullvad.mullvadvpn.compose.screen.destinations.LoginDestination
import net.mullvad.mullvadvpn.compose.screen.destinations.RedeemVoucherDestination
import net.mullvad.mullvadvpn.compose.transitions.SlideInFromBottomTransition
import net.mullvad.mullvadvpn.compose.util.SecureScreenWhileInView
import net.mullvad.mullvadvpn.constant.IS_PLAY_BUILD
import net.mullvad.mullvadvpn.lib.common.util.openAccountPageInBrowser
Expand All @@ -48,6 +57,7 @@ import net.mullvad.mullvadvpn.util.toExpiryDateString
import net.mullvad.mullvadvpn.viewmodel.AccountUiState
import net.mullvad.mullvadvpn.viewmodel.AccountViewModel
import org.joda.time.DateTime
import org.koin.androidx.compose.koinViewModel

@OptIn(ExperimentalMaterial3Api::class)
@Preview
Expand All @@ -67,6 +77,28 @@ private fun PreviewAccountScreen() {
}
}

@Destination(style = SlideInFromBottomTransition::class)
@Composable
fun Account(navigator: DestinationsNavigator) {
val vm = koinViewModel<AccountViewModel>()
val state by vm.uiState.collectAsState()

AccountScreen(
uiState = state,
uiSideEffect = vm.uiSideEffect,
enterTransitionEndAction = vm.enterTransitionEndAction,
onRedeemVoucherClick = { navigator.navigate(RedeemVoucherDestination) },
onManageAccountClick = vm::onManageAccountClick,
onLogoutClick = vm::onLogoutClick,
navigateToLogin = {
navigator.navigate(LoginDestination(null)) {
popUpTo(NavGraphs.root) { inclusive = true }
}
},
onBackClick = { navigator.navigateUp() }
)
}

@ExperimentalMaterial3Api
@Composable
fun AccountScreen(
Expand All @@ -76,6 +108,7 @@ fun AccountScreen(
onRedeemVoucherClick: () -> Unit = {},
onManageAccountClick: () -> Unit = {},
onLogoutClick: () -> Unit = {},
navigateToLogin: () -> Unit = {},
onBackClick: () -> Unit = {}
) {
// This will enable SECURE_FLAG while this screen is visible to preview screenshot
Expand All @@ -97,9 +130,12 @@ fun AccountScreen(

LaunchedEffect(Unit) {
uiSideEffect.collect { uiSideEffect ->
if (uiSideEffect is AccountViewModel.UiSideEffect.OpenAccountManagementPageInBrowser) {
context.openAccountPageInBrowser(uiSideEffect.token)
when (uiSideEffect) {
AccountViewModel.UiSideEffect.NavigateToLogin -> navigateToLogin()
is AccountViewModel.UiSideEffect.OpenAccountManagementPageInBrowser ->
context.openAccountPageInBrowser(uiSideEffect.token)
}
if (uiSideEffect is AccountViewModel.UiSideEffect.OpenAccountManagementPageInBrowser) {}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.mullvad.mullvadvpn.compose.screen

import android.content.Intent
import android.net.Uri
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
Expand All @@ -16,6 +18,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.remember
Expand All @@ -27,6 +30,9 @@ import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.popUpTo
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
Expand All @@ -38,6 +44,10 @@ import net.mullvad.mullvadvpn.compose.component.LocationInfo
import net.mullvad.mullvadvpn.compose.component.ScaffoldWithTopBarAndDeviceName
import net.mullvad.mullvadvpn.compose.component.drawVerticalScrollbar
import net.mullvad.mullvadvpn.compose.component.notificationbanner.NotificationBanner
import net.mullvad.mullvadvpn.compose.screen.destinations.AccountDestination
import net.mullvad.mullvadvpn.compose.screen.destinations.OutOfTimeDestination
import net.mullvad.mullvadvpn.compose.screen.destinations.SelectLocationDestination
import net.mullvad.mullvadvpn.compose.screen.destinations.SettingsDestination
import net.mullvad.mullvadvpn.compose.state.ConnectUiState
import net.mullvad.mullvadvpn.compose.test.CIRCULAR_PROGRESS_INDICATOR
import net.mullvad.mullvadvpn.compose.test.CONNECT_BUTTON_TEST_TAG
Expand All @@ -51,8 +61,10 @@ import net.mullvad.mullvadvpn.lib.theme.Dimens
import net.mullvad.mullvadvpn.lib.theme.color.AlphaScrollbar
import net.mullvad.mullvadvpn.lib.theme.color.AlphaTopBar
import net.mullvad.mullvadvpn.model.TunnelState
import net.mullvad.mullvadvpn.util.appendHideNavOnPlayBuild
import net.mullvad.mullvadvpn.viewmodel.ConnectViewModel
import net.mullvad.talpid.tunnel.ActionAfterDisconnect
import org.koin.androidx.compose.koinViewModel

private const val CONNECT_BUTTON_THROTTLE_MILLIS = 1000

Expand All @@ -68,6 +80,48 @@ private fun PreviewConnectScreen() {
}
}

@Destination
@Composable
fun Connect(navigator: DestinationsNavigator) {
val connectViewModel: ConnectViewModel = koinViewModel()

val state = connectViewModel.uiState.collectAsState().value

val context = LocalContext.current
// val drawNavbar = _setNavigationBar.collectAsState()
ConnectScreen(
uiState = state,
uiSideEffect = connectViewModel.uiSideEffect,
// drawNavigationBar = drawNavbar.value,
onDisconnectClick = connectViewModel::onDisconnectClick,
onReconnectClick = connectViewModel::onReconnectClick,
onConnectClick = connectViewModel::onConnectClick,
onCancelClick = connectViewModel::onCancelClick,
onSwitchLocationClick = { navigator.navigate(SelectLocationDestination) },
onToggleTunnelInfo = connectViewModel::toggleTunnelInfoExpansion,
onUpdateVersionClick = {
val intent =
Intent(
Intent.ACTION_VIEW,
Uri.parse(
context.getString(R.string.download_url).appendHideNavOnPlayBuild()
)
)
.apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK }
context.startActivity(intent)
},
onManageAccountClick = connectViewModel::onManageAccountClick,
onOpenOutOfTimeScreen = {
navigator.navigate(OutOfTimeDestination) {
popUpTo(NavGraphs.root) { inclusive = true }
}
},
onSettingsClick = { navigator.navigate(SettingsDestination) },
onAccountClick = { navigator.navigate(AccountDestination) },
onDismissNewDeviceClick = connectViewModel::dismissNewDeviceNotification,
)
}

@Composable
fun ConnectScreen(
uiState: ConnectUiState,
Expand Down
Loading

0 comments on commit 1f7e719

Please sign in to comment.