summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
Diffstat (limited to 'android')
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/AccountFragment.kt60
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/ConnectFragment.kt37
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt36
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/OutOfTimeFragment.kt32
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/SettingsFragment.kt58
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/WelcomeFragment.kt49
6 files changed, 168 insertions, 104 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/AccountFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/AccountFragment.kt
index b3e8e9f89b..c648c3f7e6 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/AccountFragment.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/AccountFragment.kt
@@ -5,11 +5,13 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import java.text.DateFormat
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.model.TunnelState
@@ -69,18 +71,6 @@ class AccountFragment : ServiceDependentFragment(OnNoService.GoBack) {
private lateinit var redeemVoucherButton: RedeemVoucherButton
private lateinit var titleController: CollapsibleTitleController
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- lifecycleScope.launch {
- deviceRepository.deviceState
- .flowWithLifecycle(lifecycle, Lifecycle.State.RESUMED)
- .collect { state ->
- accountNumberView.information = state.token()
- deviceNameView.information = state.deviceName()?.capitalizeFirstCharOfEachWord()
- }
- }
- }
-
override fun onSafelyCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -119,16 +109,11 @@ class AccountFragment : ServiceDependentFragment(OnNoService.GoBack) {
return view
}
- override fun onSafelyStart() {
- jobTracker.newUiJob("updateAccountExpiry") {
- accountRepository.accountExpiryState
- .map { state -> state.date() }
- .collect { expiryDate ->
- currentAccountExpiry = expiryDate
- updateAccountExpiry(expiryDate)
- }
- }
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ lifecycleScope.launchUiSubscriptionsOnResume()
+ }
+ override fun onSafelyStart() {
connectionProxy.onUiStateChange.subscribe(this) { uiState ->
jobTracker.newUiJob("updateHasConnectivity") {
hasConnectivity = uiState is TunnelState.Connected ||
@@ -140,7 +125,6 @@ class AccountFragment : ServiceDependentFragment(OnNoService.GoBack) {
}
sitePaymentButton.updateAuthTokenCache(authTokenCache)
- accountRepository.fetchAccountExpiry()
}
override fun onSafelyStop() {
@@ -151,6 +135,36 @@ class AccountFragment : ServiceDependentFragment(OnNoService.GoBack) {
titleController.onDestroy()
}
+ private fun CoroutineScope.launchUiSubscriptionsOnResume() = launch {
+ repeatOnLifecycle(Lifecycle.State.RESUMED) {
+ launchUpdateTextOnDeviceChanges()
+ launchUpdateTextOnExpiryChanges()
+ }
+ }
+
+ private fun CoroutineScope.launchUpdateTextOnDeviceChanges() {
+ launch {
+ deviceRepository.deviceState
+ .collect { state ->
+ accountNumberView.information = state.token()
+ deviceNameView.information =
+ state.deviceName()?.capitalizeFirstCharOfEachWord()
+ }
+ }
+ }
+
+ private fun CoroutineScope.launchUpdateTextOnExpiryChanges() {
+ launch {
+ accountRepository.accountExpiryState
+ .onStart { accountRepository.fetchAccountExpiry() }
+ .map { state -> state.date() }
+ .collect { expiryDate ->
+ currentAccountExpiry = expiryDate
+ updateAccountExpiry(expiryDate)
+ }
+ }
+ }
+
private fun checkForAddedTime() {
currentAccountExpiry?.let { expiry ->
oldAccountExpiry = expiry
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/ConnectFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/ConnectFragment.kt
index 31cf1876f5..31d1c0dd9c 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/ConnectFragment.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/ConnectFragment.kt
@@ -5,9 +5,14 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.model.TunnelState
import net.mullvad.mullvadvpn.ui.notification.AccountExpiryNotification
@@ -89,6 +94,10 @@ class ConnectFragment :
return view
}
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ lifecycleScope.launchUiSubscriptionsOnResume()
+ }
+
override fun onSafelyStart() {
locationInfo.isTunnelInfoExpanded = isTunnelInfoExpanded
@@ -111,17 +120,6 @@ class ConnectFragment :
updateTunnelState(uiState, connectionProxy.state)
}
}
-
- jobTracker.newUiJob("updateAccountExpiry") {
- accountRepository.accountExpiryState
- .map { state -> state.date() }
- .collect { expiryDate ->
- if (expiryDate?.isBeforeNow == true) {
- openOutOfTimeScreen()
- } else if (expiryDate != null)
- scheduleNextAccountExpiryCheck(expiryDate)
- }
- }
}
override fun onSafelyStop() {
@@ -151,6 +149,23 @@ class ConnectFragment :
paintNavigationBar(ContextCompat.getColor(requireContext(), R.color.blue))
}
+ private fun CoroutineScope.launchUiSubscriptionsOnResume() = launch {
+ repeatOnLifecycle(Lifecycle.State.RESUMED) {
+ launchScheduledExpiryCheck()
+ }
+ }
+
+ private fun CoroutineScope.launchScheduledExpiryCheck() = launch {
+ accountRepository.accountExpiryState
+ .map { state -> state.date() }
+ .collect { expiryDate ->
+ if (expiryDate?.isBeforeNow == true) {
+ openOutOfTimeScreen()
+ } else if (expiryDate != null)
+ scheduleNextAccountExpiryCheck(expiryDate)
+ }
+ }
+
private fun updateTunnelState(uiState: TunnelState, realState: TunnelState) {
locationInfo.state = realState
headerBar.tunnelState = realState
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt
index aa146f2984..d0e6fbf2f3 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt
@@ -11,6 +11,7 @@ import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.R
@@ -37,11 +38,6 @@ class LoginFragment :
private lateinit var background: View
private lateinit var headerBar: HeaderBar
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setupLifecycleSubscriptionsToViewModel()
- }
-
override fun onSafelyCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -78,6 +74,10 @@ class LoginFragment :
return view
}
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ lifecycleScope.launchUiSubscriptionsOnResume()
+ }
+
override fun onSafelyStart() {
parentActivity.backButtonHandler = {
if (accountLogin.hasFocus) {
@@ -105,21 +105,23 @@ class LoginFragment :
}
}
- private fun setupLifecycleSubscriptionsToViewModel() {
- lifecycleScope.launch {
- repeatOnLifecycle(Lifecycle.State.RESUMED) {
- launch {
- loginViewModel.accountHistory.collect { history ->
- accountLogin.accountHistory = history.accountToken()
- }
- }
- launch {
- loginViewModel.uiState.collect { uiState -> updateUi(uiState) }
- }
- }
+ private fun CoroutineScope.launchUiSubscriptionsOnResume() = launch {
+ repeatOnLifecycle(Lifecycle.State.RESUMED) {
+ lanuchUpdateAccountHistory()
+ launchUpdateUiOnViewModelStateChanges()
}
}
+ private fun CoroutineScope.lanuchUpdateAccountHistory() = launch {
+ loginViewModel.accountHistory.collect { history ->
+ accountLogin.accountHistory = history.accountToken()
+ }
+ }
+
+ private fun CoroutineScope.launchUpdateUiOnViewModelStateChanges() = launch {
+ loginViewModel.uiState.collect { uiState -> updateUi(uiState) }
+ }
+
private fun updateUi(uiState: LoginViewModel.LoginUiState) {
when (uiState) {
is LoginViewModel.LoginUiState.Default -> {
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/OutOfTimeFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/OutOfTimeFragment.kt
index 02b6f1d059..03aa10c264 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/OutOfTimeFragment.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/OutOfTimeFragment.kt
@@ -5,10 +5,15 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import kotlin.properties.Delegates.observable
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.model.TunnelState
import net.mullvad.mullvadvpn.ui.serviceconnection.AccountRepository
@@ -79,15 +84,11 @@ class OutOfTimeFragment : ServiceDependentFragment(OnNoService.GoToLaunchScreen)
return view
}
- override fun onSafelyStart() {
- jobTracker.newUiJob("updateAccountExpiry") {
- accountRepository.accountExpiryState
- .map { state -> state.date() }
- .collect { expiryDate ->
- checkExpiry(expiryDate)
- }
- }
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ lifecycleScope.launchUiSubscriptionsOnResume()
+ }
+ override fun onSafelyStart() {
jobTracker.newBackgroundJob("pollAccountData") {
while (true) {
accountRepository.fetchAccountExpiry()
@@ -99,7 +100,6 @@ class OutOfTimeFragment : ServiceDependentFragment(OnNoService.GoToLaunchScreen)
}
override fun onSafelyStop() {
- jobTracker.cancelJob("updateAccountExpiry")
jobTracker.cancelJob("pollAccountData")
}
@@ -107,6 +107,20 @@ class OutOfTimeFragment : ServiceDependentFragment(OnNoService.GoToLaunchScreen)
connectionProxy.onStateChange.unsubscribe(this)
}
+ private fun CoroutineScope.launchUiSubscriptionsOnResume() = launch {
+ repeatOnLifecycle(Lifecycle.State.RESUMED) {
+ launchProceedToConnectViewIfExpiryExtended()
+ }
+ }
+
+ private fun CoroutineScope.launchProceedToConnectViewIfExpiryExtended() = launch {
+ accountRepository.accountExpiryState
+ .map { state -> state.date() }
+ .collect { expiryDate ->
+ checkExpiry(expiryDate)
+ }
+ }
+
private fun updateDisconnectButton() {
val state = tunnelState
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/SettingsFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/SettingsFragment.kt
index d9a28a9ad7..e0f619550c 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/SettingsFragment.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/SettingsFragment.kt
@@ -7,10 +7,12 @@ import android.view.ViewGroup
import android.widget.ImageButton
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.model.DeviceState
@@ -49,17 +51,6 @@ class SettingsFragment : ServiceAwareFragment(), StatusBarPainter, NavigationBar
versionInfoCache = null
}
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- lifecycleScope.launch {
- deviceRepository.deviceState
- .flowWithLifecycle(lifecycle, Lifecycle.State.RESUMED)
- .collect { device ->
- updateLoggedInStatus(device is DeviceState.LoggedIn)
- }
- }
- }
-
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -95,12 +86,7 @@ class SettingsFragment : ServiceAwareFragment(), StatusBarPainter, NavigationBar
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- lifecycleScope.launchWhenResumed {
- transitionFinishedFlow.collect {
- paintStatusBar(ContextCompat.getColor(requireContext(), R.color.darkBlue))
- }
- }
+ lifecycleScope.launchUiSubscriptionsOnResume()
}
override fun onResume() {
@@ -129,17 +115,37 @@ class SettingsFragment : ServiceAwareFragment(), StatusBarPainter, NavigationBar
titleController.onDestroy()
}
- private fun configureListeners() {
- jobTracker.newUiJob("updateAccountExpiry") {
- accountRepository.accountExpiryState
- .map { state -> state.date() }
- .collect { expiryDate ->
- accountMenu.accountExpiry = expiryDate
- }
+ private fun CoroutineScope.launchUiSubscriptionsOnResume() = launch {
+ repeatOnLifecycle(Lifecycle.State.RESUMED) {
+ launchPaintStatusBarAfterTransition()
+ luanchConfigureMenuOnDeviceChanges()
+ launchUpdateExpiryTextOnExpiryChanges()
+ }
+ }
+
+ private fun CoroutineScope.launchPaintStatusBarAfterTransition() = launch {
+ transitionFinishedFlow.collect {
+ paintStatusBar(ContextCompat.getColor(requireContext(), R.color.darkBlue))
}
+ }
+
+ private fun CoroutineScope.luanchConfigureMenuOnDeviceChanges() = launch {
+ deviceRepository.deviceState
+ .collect { device ->
+ updateLoggedInStatus(device is DeviceState.LoggedIn)
+ }
+ }
- accountRepository.fetchAccountExpiry()
+ private fun CoroutineScope.launchUpdateExpiryTextOnExpiryChanges() = launch {
+ accountRepository.accountExpiryState
+ .onStart { accountRepository.fetchAccountExpiry() }
+ .map { state -> state.date() }
+ .collect { expiryDate ->
+ accountMenu.accountExpiry = expiryDate
+ }
+ }
+ private fun configureListeners() {
versionInfoCache?.onUpdate = {
jobTracker.newUiJob("updateVersionInfo") {
updateVersionInfo()
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/WelcomeFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/WelcomeFragment.kt
index 7b8978e669..3acf9b3eee 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/WelcomeFragment.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/WelcomeFragment.kt
@@ -9,8 +9,13 @@ import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.model.TunnelState
import net.mullvad.mullvadvpn.ui.serviceconnection.AccountRepository
@@ -65,19 +70,11 @@ class WelcomeFragment : ServiceDependentFragment(OnNoService.GoToLaunchScreen) {
return view
}
- override fun onSafelyStart() {
- jobTracker.newUiJob("updateAccountNumber") {
- deviceRepository.deviceState.collect { state ->
- updateAccountNumber(state.token())
- }
- }
-
- jobTracker.newUiJob("checkAccountExpiry") {
- accountRepository.accountExpiryState.collect {
- checkExpiry(it.date())
- }
- }
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ lifecycleScope.launchUiSubscriptionsOnResume()
+ }
+ override fun onSafelyStart() {
jobTracker.newBackgroundJob("pollAccountData") {
while (true) {
accountRepository.fetchAccountExpiry()
@@ -89,9 +86,27 @@ class WelcomeFragment : ServiceDependentFragment(OnNoService.GoToLaunchScreen) {
}
override fun onSafelyStop() {
- jobTracker.cancelJob("checkAccountExpiry")
jobTracker.cancelJob("pollAccountData")
- jobTracker.cancelJob("updateAccountNumber")
+ }
+
+ private fun CoroutineScope.launchUiSubscriptionsOnResume() = launch {
+ repeatOnLifecycle(Lifecycle.State.RESUMED) {
+ launchUpdateAccountNumberOnDeviceChanges()
+ launchAdvanceToConnectViewOnExpiryExtended()
+ }
+ }
+
+ private fun CoroutineScope.launchUpdateAccountNumberOnDeviceChanges() = launch {
+ deviceRepository.deviceState
+ .collect { state ->
+ updateAccountNumber(state.token())
+ }
+ }
+
+ private fun CoroutineScope.launchAdvanceToConnectViewOnExpiryExtended() = launch {
+ accountRepository.accountExpiryState.collect {
+ checkExpiry(it.date())
+ }
}
private fun updateAccountNumber(rawAccountNumber: String?) {
@@ -99,10 +114,8 @@ class WelcomeFragment : ServiceDependentFragment(OnNoService.GoToLaunchScreen) {
addSpacesToAccountText(account)
}
- jobTracker.newUiJob("updateAccountNumber") {
- accountLabel.text = accountText ?: ""
- accountLabel.setEnabled(accountText != null && accountText.length > 0)
- }
+ accountLabel.text = accountText ?: ""
+ accountLabel.setEnabled(accountText != null && accountText.length > 0)
}
private fun addSpacesToAccountText(account: String): String {