summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
authorJonatan Rhodin <jonatan.rhodin@mullvad.net>2023-09-07 13:49:22 +0200
committerJonatan Rhodin <jonatan.rhodin@mullvad.net>2023-09-07 13:49:22 +0200
commit827a84c9287705e30487f2f53b360e05dc418f54 (patch)
tree8861ee6dfc6499ba76a0b993ab6de7a8620b25c5 /android
parentaec8962f16c7d0bdb6b6af4d5e6577aed2b4a575 (diff)
parented29c932534155ad1de9d27c6d91a0184f635497 (diff)
downloadmullvadvpn-827a84c9287705e30487f2f53b360e05dc418f54.tar.xz
mullvadvpn-827a84c9287705e30487f2f53b360e05dc418f54.zip
Merge branch 'migrate-headerbar-to-compose-droid-192'
Diffstat (limited to 'android')
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt6
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt218
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/ConnectFragment.kt58
-rw-r--r--android/app/src/main/res/layout/connect.xml14
4 files changed, 142 insertions, 154 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt
index 2cfe0c65d9..b04c23d817 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt
@@ -37,8 +37,10 @@ fun ScaffoldWithTopBar(
content: @Composable (PaddingValues) -> Unit,
) {
val systemUiController = rememberSystemUiController()
- systemUiController.setStatusBarColor(statusBarColor)
- systemUiController.setNavigationBarColor(navigationBarColor)
+ LaunchedEffect(key1 = statusBarColor, key2 = navigationBarColor) {
+ systemUiController.setStatusBarColor(statusBarColor)
+ systemUiController.setNavigationBarColor(navigationBarColor)
+ }
Scaffold(
topBar = {
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt
index ac9ea5cf1c..d250a5467e 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt
@@ -35,6 +35,7 @@ import net.mullvad.mullvadvpn.compose.button.SwitchLocationButton
import net.mullvad.mullvadvpn.compose.component.ConnectionStatusText
import net.mullvad.mullvadvpn.compose.component.LocationInfo
import net.mullvad.mullvadvpn.compose.component.Notification
+import net.mullvad.mullvadvpn.compose.component.ScaffoldWithTopBar
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
@@ -43,6 +44,7 @@ import net.mullvad.mullvadvpn.compose.test.RECONNECT_BUTTON_TEST_TAG
import net.mullvad.mullvadvpn.compose.test.SCROLLABLE_COLUMN_TEST_TAG
import net.mullvad.mullvadvpn.compose.test.SELECT_LOCATION_BUTTON_TEST_TAG
import net.mullvad.mullvadvpn.lib.common.util.openAccountPageInBrowser
+import net.mullvad.mullvadvpn.lib.theme.AlphaTopBar
import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.lib.theme.Dimens
import net.mullvad.mullvadvpn.model.TunnelState
@@ -75,7 +77,9 @@ fun ConnectScreen(
onToggleTunnelInfo: () -> Unit = {},
onUpdateVersionClick: () -> Unit = {},
onManageAccountClick: () -> Unit = {},
- onOpenOutOfTimeScreen: () -> Unit = {}
+ onOpenOutOfTimeScreen: () -> Unit = {},
+ onSettingsClick: () -> Unit = {},
+ onAccountClick: () -> Unit = {}
) {
val context = LocalContext.current
LaunchedEffect(key1 = Unit) {
@@ -102,104 +106,130 @@ fun ConnectScreen(
}
}
- Column(
- verticalArrangement = Arrangement.Bottom,
- horizontalAlignment = Alignment.Start,
- modifier =
- Modifier.background(color = MaterialTheme.colorScheme.primary)
- .fillMaxHeight()
- .verticalScroll(scrollState)
- .padding(bottom = Dimens.screenVerticalMargin)
- .testTag(SCROLLABLE_COLUMN_TEST_TAG)
+ ScaffoldWithTopBar(
+ topBarColor =
+ if (uiState.tunnelUiState.isSecured()) {
+ MaterialTheme.colorScheme.inversePrimary
+ } else {
+ MaterialTheme.colorScheme.error
+ },
+ statusBarColor =
+ if (uiState.tunnelUiState.isSecured()) {
+ MaterialTheme.colorScheme.inversePrimary
+ } else {
+ MaterialTheme.colorScheme.error
+ },
+ navigationBarColor = MaterialTheme.colorScheme.primary,
+ iconTintColor =
+ if (uiState.tunnelUiState.isSecured()) {
+ MaterialTheme.colorScheme.onPrimary
+ } else {
+ MaterialTheme.colorScheme.onError
+ }
+ .copy(alpha = AlphaTopBar),
+ onSettingsClicked = onSettingsClick,
+ onAccountClicked = onAccountClick
) {
- Notification(
- connectNotificationState = uiState.connectNotificationState,
- onClickUpdateVersion = onUpdateVersionClick,
- onClickShowAccount = onManageAccountClick
- )
- Spacer(modifier = Modifier.weight(1f))
- if (
- uiState.tunnelRealState is TunnelState.Connecting ||
- (uiState.tunnelRealState is TunnelState.Disconnecting &&
- uiState.tunnelRealState.actionAfterDisconnect ==
- ActionAfterDisconnect.Reconnect)
+ Column(
+ verticalArrangement = Arrangement.Bottom,
+ horizontalAlignment = Alignment.Start,
+ modifier =
+ Modifier.padding(it)
+ .background(color = MaterialTheme.colorScheme.primary)
+ .fillMaxHeight()
+ .verticalScroll(scrollState)
+ .padding(bottom = Dimens.screenVerticalMargin)
+ .testTag(SCROLLABLE_COLUMN_TEST_TAG)
) {
- CircularProgressIndicator(
+ Notification(
+ connectNotificationState = uiState.connectNotificationState,
+ onClickUpdateVersion = onUpdateVersionClick,
+ onClickShowAccount = onManageAccountClick
+ )
+ Spacer(modifier = Modifier.weight(1f))
+ if (
+ uiState.tunnelRealState is TunnelState.Connecting ||
+ (uiState.tunnelRealState is TunnelState.Disconnecting &&
+ uiState.tunnelRealState.actionAfterDisconnect ==
+ ActionAfterDisconnect.Reconnect)
+ ) {
+ CircularProgressIndicator(
+ color = MaterialTheme.colorScheme.onPrimary,
+ modifier =
+ Modifier.padding(
+ start = Dimens.sideMargin,
+ end = Dimens.sideMargin,
+ top = Dimens.mediumPadding
+ )
+ .size(
+ width = Dimens.progressIndicatorSize,
+ height = Dimens.progressIndicatorSize
+ )
+ .align(Alignment.CenterHorizontally)
+ .testTag(CIRCULAR_PROGRESS_INDICATOR)
+ )
+ }
+ Spacer(modifier = Modifier.height(Dimens.mediumPadding))
+ ConnectionStatusText(
+ state = uiState.tunnelRealState,
+ modifier = Modifier.padding(horizontal = Dimens.sideMargin)
+ )
+ Text(
+ text = uiState.location?.country ?: "",
+ style = MaterialTheme.typography.headlineLarge,
color = MaterialTheme.colorScheme.onPrimary,
+ modifier = Modifier.padding(horizontal = Dimens.sideMargin)
+ )
+ Text(
+ text = uiState.location?.city ?: "",
+ style = MaterialTheme.typography.headlineLarge,
+ color = MaterialTheme.colorScheme.onPrimary,
+ modifier = Modifier.padding(horizontal = Dimens.sideMargin)
+ )
+ LocationInfo(
+ onToggleTunnelInfo = onToggleTunnelInfo,
+ isVisible =
+ uiState.tunnelRealState != TunnelState.Disconnected &&
+ uiState.location?.hostname != null,
+ isExpanded = uiState.isTunnelInfoExpanded,
+ location = uiState.location,
+ inAddress = uiState.inAddress,
+ outAddress = uiState.outAddress,
modifier =
- Modifier.padding(
- start = Dimens.sideMargin,
- end = Dimens.sideMargin,
- top = Dimens.mediumPadding
- )
- .size(
- width = Dimens.progressIndicatorSize,
- height = Dimens.progressIndicatorSize
- )
- .align(Alignment.CenterHorizontally)
- .testTag(CIRCULAR_PROGRESS_INDICATOR)
+ Modifier.fillMaxWidth()
+ .padding(horizontal = Dimens.sideMargin)
+ .testTag(LOCATION_INFO_TEST_TAG)
+ )
+ Spacer(modifier = Modifier.height(Dimens.buttonSeparation))
+ SwitchLocationButton(
+ modifier =
+ Modifier.fillMaxWidth()
+ .height(Dimens.selectLocationButtonHeight)
+ .padding(horizontal = Dimens.sideMargin)
+ .testTag(SELECT_LOCATION_BUTTON_TEST_TAG),
+ onClick = onSwitchLocationClick,
+ showChevron = uiState.showLocation,
+ text =
+ if (uiState.showLocation) {
+ uiState.relayLocation?.locationName ?: ""
+ } else {
+ stringResource(id = R.string.switch_location)
+ }
+ )
+ Spacer(modifier = Modifier.height(Dimens.buttonSeparation))
+ ConnectionButton(
+ state = uiState.tunnelUiState,
+ modifier =
+ Modifier.fillMaxWidth()
+ .height(Dimens.connectButtonHeight)
+ .padding(horizontal = Dimens.sideMargin)
+ .testTag(CONNECT_BUTTON_TEST_TAG),
+ disconnectClick = onDisconnectClick,
+ reconnectClick = { handleThrottledAction(onReconnectClick) },
+ cancelClick = onCancelClick,
+ connectClick = { handleThrottledAction(onConnectClick) },
+ reconnectButtonTestTag = RECONNECT_BUTTON_TEST_TAG
)
}
- Spacer(modifier = Modifier.height(Dimens.mediumPadding))
- ConnectionStatusText(
- state = uiState.tunnelRealState,
- modifier = Modifier.padding(horizontal = Dimens.sideMargin)
- )
- Text(
- text = uiState.location?.country ?: "",
- style = MaterialTheme.typography.headlineLarge,
- color = MaterialTheme.colorScheme.onPrimary,
- modifier = Modifier.padding(horizontal = Dimens.sideMargin)
- )
- Text(
- text = uiState.location?.city ?: "",
- style = MaterialTheme.typography.headlineLarge,
- color = MaterialTheme.colorScheme.onPrimary,
- modifier = Modifier.padding(horizontal = Dimens.sideMargin)
- )
- LocationInfo(
- onToggleTunnelInfo = onToggleTunnelInfo,
- isVisible =
- uiState.tunnelRealState != TunnelState.Disconnected &&
- uiState.location?.hostname != null,
- isExpanded = uiState.isTunnelInfoExpanded,
- location = uiState.location,
- inAddress = uiState.inAddress,
- outAddress = uiState.outAddress,
- modifier =
- Modifier.fillMaxWidth()
- .padding(horizontal = Dimens.sideMargin)
- .testTag(LOCATION_INFO_TEST_TAG)
- )
- Spacer(modifier = Modifier.height(Dimens.buttonSeparation))
- SwitchLocationButton(
- modifier =
- Modifier.fillMaxWidth()
- .height(Dimens.selectLocationButtonHeight)
- .padding(horizontal = Dimens.sideMargin)
- .testTag(SELECT_LOCATION_BUTTON_TEST_TAG),
- onClick = onSwitchLocationClick,
- showChevron = uiState.showLocation,
- text =
- if (uiState.showLocation) {
- uiState.relayLocation?.locationName ?: ""
- } else {
- stringResource(id = R.string.switch_location)
- }
- )
- Spacer(modifier = Modifier.height(Dimens.buttonSeparation))
- ConnectionButton(
- state = uiState.tunnelUiState,
- modifier =
- Modifier.fillMaxWidth()
- .height(Dimens.connectButtonHeight)
- .padding(horizontal = Dimens.sideMargin)
- .testTag(CONNECT_BUTTON_TEST_TAG),
- disconnectClick = onDisconnectClick,
- reconnectClick = { handleThrottledAction(onReconnectClick) },
- cancelClick = onCancelClick,
- connectClick = { handleThrottledAction(onConnectClick) },
- reconnectButtonTestTag = RECONNECT_BUTTON_TEST_TAG
- )
}
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/ConnectFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/ConnectFragment.kt
index d83941e4de..7592be144b 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/ConnectFragment.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/ConnectFragment.kt
@@ -8,21 +8,12 @@ import android.view.View
import android.view.ViewGroup
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.platform.ComposeView
-import androidx.core.content.ContextCompat
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.lifecycleScope
-import androidx.lifecycle.repeatOnLifecycle
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.screen.ConnectScreen
-import net.mullvad.mullvadvpn.lib.common.util.JobTracker
import net.mullvad.mullvadvpn.lib.common.util.appendHideNavOnReleaseBuild
import net.mullvad.mullvadvpn.lib.theme.AppTheme
-import net.mullvad.mullvadvpn.model.TunnelState
+import net.mullvad.mullvadvpn.ui.MainActivity
import net.mullvad.mullvadvpn.ui.NavigationBarPainter
-import net.mullvad.mullvadvpn.ui.paintNavigationBar
-import net.mullvad.mullvadvpn.ui.widget.HeaderBar
import net.mullvad.mullvadvpn.viewmodel.ConnectViewModel
import org.koin.androidx.viewmodel.ext.android.viewModel
@@ -31,26 +22,12 @@ class ConnectFragment : BaseFragment(), NavigationBarPainter {
// Injected dependencies
private val connectViewModel: ConnectViewModel by viewModel()
- private lateinit var headerBar: HeaderBar
-
- @Deprecated("Refactor code to instead rely on Lifecycle.") private val jobTracker = JobTracker()
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- lifecycleScope.launchUiSubscriptionsOnResume()
- }
-
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
- val view = inflater.inflate(R.layout.connect, container, false)
-
- headerBar =
- view.findViewById<HeaderBar>(R.id.header_bar).apply {
- tunnelState = connectViewModel.uiState.value.tunnelUiState
- }
+ val view = inflater.inflate(R.layout.fragment_compose, container, false)
view.findViewById<ComposeView>(R.id.compose_view).setContent {
AppTheme {
@@ -62,11 +39,13 @@ class ConnectFragment : BaseFragment(), NavigationBarPainter {
onReconnectClick = connectViewModel::onReconnectClick,
onConnectClick = connectViewModel::onConnectClick,
onCancelClick = connectViewModel::onCancelClick,
- onSwitchLocationClick = { openSwitchLocationScreen() },
+ onSwitchLocationClick = ::openSwitchLocationScreen,
onToggleTunnelInfo = connectViewModel::toggleTunnelInfoExpansion,
onUpdateVersionClick = { openDownloadUrl() },
onManageAccountClick = connectViewModel::onManageAccountClick,
- onOpenOutOfTimeScreen = ::openOutOfTimeScreen
+ onOpenOutOfTimeScreen = ::openOutOfTimeScreen,
+ onSettingsClick = ::openSettingsView,
+ onAccountClick = ::openAccountView
)
}
}
@@ -74,11 +53,6 @@ class ConnectFragment : BaseFragment(), NavigationBarPainter {
return view
}
- override fun onResume() {
- super.onResume()
- paintNavigationBar(ContextCompat.getColor(requireContext(), R.color.blue))
- }
-
private fun openDownloadUrl() {
val intent =
Intent(
@@ -93,18 +67,6 @@ class ConnectFragment : BaseFragment(), NavigationBarPainter {
requireContext().startActivity(intent)
}
- private fun CoroutineScope.launchUiSubscriptionsOnResume() = launch {
- repeatOnLifecycle(Lifecycle.State.RESUMED) { launchViewModelSubscription() }
- }
-
- private fun CoroutineScope.launchViewModelSubscription() = launch {
- connectViewModel.uiState.collect { uiState -> updateTunnelState(uiState.tunnelRealState) }
- }
-
- private fun updateTunnelState(realState: TunnelState) {
- headerBar.tunnelState = realState
- }
-
private fun openSwitchLocationScreen() {
parentFragmentManager.beginTransaction().apply {
setCustomAnimations(
@@ -125,4 +87,12 @@ class ConnectFragment : BaseFragment(), NavigationBarPainter {
commitAllowingStateLoss()
}
}
+
+ private fun openSettingsView() {
+ (context as? MainActivity)?.openSettings()
+ }
+
+ private fun openAccountView() {
+ (context as? MainActivity)?.openAccount()
+ }
}
diff --git a/android/app/src/main/res/layout/connect.xml b/android/app/src/main/res/layout/connect.xml
deleted file mode 100644
index 7c0267d903..0000000000
--- a/android/app/src/main/res/layout/connect.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:orientation="vertical">
- <net.mullvad.mullvadvpn.ui.widget.HeaderBar android:id="@+id/header_bar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:elevation="0.5dp" />
- <androidx.compose.ui.platform.ComposeView android:id="@+id/compose_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- app:layout_behavior="net.mullvad.mullvadvpn.ui.UnderNotificationBannerBehavior" />
-</LinearLayout>