Skip to content

Commit

Permalink
Migrate connect screen headerbar to compose
Browse files Browse the repository at this point in the history
  • Loading branch information
Pururun committed Sep 7, 2023
1 parent aec8962 commit ed29c93
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 154 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -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
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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 {
Expand All @@ -62,23 +39,20 @@ 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
)
}
}

return view
}

override fun onResume() {
super.onResume()
paintNavigationBar(ContextCompat.getColor(requireContext(), R.color.blue))
}

private fun openDownloadUrl() {
val intent =
Intent(
Expand All @@ -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(
Expand All @@ -125,4 +87,12 @@ class ConnectFragment : BaseFragment(), NavigationBarPainter {
commitAllowingStateLoss()
}
}

private fun openSettingsView() {
(context as? MainActivity)?.openSettings()
}

private fun openAccountView() {
(context as? MainActivity)?.openAccount()
}
}
14 changes: 0 additions & 14 deletions android/app/src/main/res/layout/connect.xml

This file was deleted.

0 comments on commit ed29c93

Please sign in to comment.