summaryrefslogtreecommitdiffhomepage
path: root/android/app/src
diff options
context:
space:
mode:
authorAlbin <albin@mullvad.net>2023-06-12 16:05:02 +0200
committerAlbin <albin@mullvad.net>2023-06-12 16:05:02 +0200
commitae58b4777a3bf3bc19330f3c190897667c5c883b (patch)
tree89c965db6b693e89c7bd4eb31d018891338fbfe6 /android/app/src
parenta2255d0514c9abbd215aab98314624989f91392c (diff)
parent03b068a38623fb4c780f68af5292e89dee84727b (diff)
downloadmullvadvpn-ae58b4777a3bf3bc19330f3c190897667c5c883b.tar.xz
mullvadvpn-ae58b4777a3bf3bc19330f3c190897667c5c883b.zip
Merge branch 'move-account-button-from-settings-to-header-droid-88'
Diffstat (limited to 'android/app/src')
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt15
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AccountFragment.kt21
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/LoginFragment.kt6
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SettingsFragment.kt19
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountCell.kt70
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/HeaderBar.kt11
-rw-r--r--android/app/src/main/res/drawable/icon_account.xml12
-rw-r--r--android/app/src/main/res/layout/account.xml11
-rw-r--r--android/app/src/main/res/layout/header_bar.xml13
-rw-r--r--android/app/src/main/res/layout/settings.xml7
10 files changed, 82 insertions, 103 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt
index ceb67ebc6c..4d72ff3590 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt
@@ -39,6 +39,7 @@ import net.mullvad.mullvadvpn.model.DeviceState
import net.mullvad.mullvadvpn.repository.AccountRepository
import net.mullvad.mullvadvpn.repository.DeviceRepository
import net.mullvad.mullvadvpn.repository.PrivacyDisclaimerRepository
+import net.mullvad.mullvadvpn.ui.fragment.AccountFragment
import net.mullvad.mullvadvpn.ui.fragment.ConnectFragment
import net.mullvad.mullvadvpn.ui.fragment.DeviceRevokedFragment
import net.mullvad.mullvadvpn.ui.fragment.LoadingFragment
@@ -183,6 +184,20 @@ open class MainActivity : FragmentActivity() {
}
}
+ fun openAccount() {
+ supportFragmentManager.beginTransaction().apply {
+ setCustomAnimations(
+ R.anim.fragment_enter_from_bottom,
+ R.anim.do_nothing,
+ R.anim.do_nothing,
+ R.anim.fragment_exit_to_bottom
+ )
+ replace(R.id.main_fragment, AccountFragment())
+ addToBackStack(null)
+ commitAllowingStateLoss()
+ }
+ }
+
fun openSettings() {
supportFragmentManager.beginTransaction().apply {
setCustomAnimations(
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AccountFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AccountFragment.kt
index 09accbc826..06fdb37b79 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AccountFragment.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AccountFragment.kt
@@ -5,6 +5,7 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
@@ -26,8 +27,12 @@ import net.mullvad.mullvadvpn.repository.DeviceRepository
import net.mullvad.mullvadvpn.ui.CollapsibleTitleController
import net.mullvad.mullvadvpn.ui.GroupedPasswordTransformationMethod
import net.mullvad.mullvadvpn.ui.GroupedTransformationMethod
+import net.mullvad.mullvadvpn.ui.NavigationBarPainter
+import net.mullvad.mullvadvpn.ui.StatusBarPainter
import net.mullvad.mullvadvpn.ui.extension.openAccountPageInBrowser
import net.mullvad.mullvadvpn.ui.extension.requireMainActivity
+import net.mullvad.mullvadvpn.ui.paintNavigationBar
+import net.mullvad.mullvadvpn.ui.paintStatusBar
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionState
import net.mullvad.mullvadvpn.ui.serviceconnection.authTokenCache
@@ -45,7 +50,7 @@ import net.mullvad.talpid.tunnel.ErrorStateCause
import org.joda.time.DateTime
import org.koin.android.ext.android.inject
-class AccountFragment : BaseFragment() {
+class AccountFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter {
// Injected dependencies
private val accountRepository: AccountRepository by inject()
@@ -117,7 +122,7 @@ class AccountFragment : BaseFragment() {
): View {
val view = inflater.inflate(R.layout.account, container, false)
- view.findViewById<View>(R.id.back).setOnClickListener {
+ view.findViewById<View>(R.id.close).setOnClickListener {
requireMainActivity().onBackPressed()
}
@@ -157,6 +162,11 @@ class AccountFragment : BaseFragment() {
return view
}
+ override fun onResume() {
+ super.onResume()
+ paintNavigationBar(ContextCompat.getColor(requireContext(), R.color.darkBlue))
+ }
+
override fun onStop() {
jobTracker.cancelAllJobs()
super.onStop()
@@ -178,6 +188,7 @@ class AccountFragment : BaseFragment() {
launchUpdateTextOnExpiryChanges()
launchTunnelStateSubscription()
launchRefreshDeviceStateAfterAnimation()
+ launchPaintStatusBarAfterTransition()
}
}
@@ -227,6 +238,12 @@ class AccountFragment : BaseFragment() {
}
}
+ private fun CoroutineScope.launchPaintStatusBarAfterTransition() = launch {
+ transitionFinishedFlow.collect {
+ paintStatusBar(ContextCompat.getColor(requireContext(), R.color.darkBlue))
+ }
+ }
+
private fun CoroutineScope.launchRefreshDeviceStateAfterAnimation() = launch {
transitionFinishedFlow.collect { deviceRepository.refreshDeviceState() }
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/LoginFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/LoginFragment.kt
index 3168824c92..ba29326b3d 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/LoginFragment.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/LoginFragment.kt
@@ -58,7 +58,11 @@ class LoginFragment : BaseFragment(), NavigationBarPainter {
): View? {
val view = inflater.inflate(R.layout.login, container, false)
- headerBar = view.findViewById(R.id.header_bar)
+ headerBar =
+ view.findViewById<HeaderBar?>(R.id.header_bar).apply {
+ setAccountButtonVisibility(false)
+ }
+
title = view.findViewById(R.id.title)
subtitle = view.findViewById(R.id.subtitle)
loggingInStatus = view.findViewById(R.id.logging_in_status)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SettingsFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SettingsFragment.kt
index 8db85de50d..4ebd2eff38 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SettingsFragment.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SettingsFragment.kt
@@ -13,12 +13,10 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.BuildConfig
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.model.DeviceState
-import net.mullvad.mullvadvpn.repository.AccountRepository
import net.mullvad.mullvadvpn.repository.DeviceRepository
import net.mullvad.mullvadvpn.ui.CollapsibleTitleController
import net.mullvad.mullvadvpn.ui.NavigationBarPainter
@@ -29,7 +27,6 @@ import net.mullvad.mullvadvpn.ui.paintStatusBar
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionState
import net.mullvad.mullvadvpn.ui.serviceconnection.appVersionInfoCache
-import net.mullvad.mullvadvpn.ui.widget.AccountCell
import net.mullvad.mullvadvpn.ui.widget.AppVersionCell
import net.mullvad.mullvadvpn.ui.widget.NavigateCell
import net.mullvad.mullvadvpn.util.JobTracker
@@ -41,11 +38,9 @@ import org.koin.android.ext.android.inject
class SettingsFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter {
// Injected dependencies
- private val accountRepository: AccountRepository by inject()
private val deviceRepository: DeviceRepository by inject()
private val serviceConnectionManager: ServiceConnectionManager by inject()
- private lateinit var accountMenu: AccountCell
private lateinit var appVersionMenu: AppVersionCell
private lateinit var vpnSettingsMenu: View
private lateinit var splitTunnelingMenu: View
@@ -67,11 +62,6 @@ class SettingsFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter
view.findViewById<ImageButton>(R.id.close).setOnClickListener { activity?.onBackPressed() }
- accountMenu =
- view.findViewById<AccountCell>(R.id.account).apply {
- targetFragment = AccountFragment::class
- }
-
vpnSettingsMenu =
view.findViewById<NavigateCell>(R.id.vpn_settings).apply {
targetFragment = VpnSettingsFragment::class
@@ -114,7 +104,6 @@ class SettingsFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter
private fun initializeUiState() {
updateLoggedInStatus(deviceRepository.deviceState.value is DeviceState.LoggedIn)
- accountMenu.accountExpiry = accountRepository.accountExpiryState.value.date()
appVersionMenu.version = BuildConfig.VERSION_NAME
serviceConnectionManager.appVersionInfoCache().let { cache ->
updateVersionInfo(
@@ -141,7 +130,6 @@ class SettingsFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter
repeatOnLifecycle(Lifecycle.State.RESUMED) {
launchPaintStatusBarAfterTransition()
luanchConfigureMenuOnDeviceChanges()
- launchUpdateExpiryTextOnExpiryChanges()
launchVersionInfoSubscription()
}
}
@@ -158,12 +146,6 @@ class SettingsFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter
.collect { device -> updateLoggedInStatus(device is DeviceState.LoggedIn) }
}
- private fun CoroutineScope.launchUpdateExpiryTextOnExpiryChanges() = launch {
- accountRepository.accountExpiryState
- .map { state -> state.date() }
- .collect { expiryDate -> accountMenu.accountExpiry = expiryDate }
- }
-
private fun CoroutineScope.launchVersionInfoSubscription() = launch {
serviceConnectionManager.connectionState
.flatMapLatest { state ->
@@ -184,7 +166,6 @@ class SettingsFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter
View.GONE
}
- accountMenu.visibility = visibility
vpnSettingsMenu.visibility = visibility
splitTunnelingMenu.visibility = visibility
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountCell.kt
deleted file mode 100644
index 4a4acf737a..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountCell.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-package net.mullvad.mullvadvpn.ui.widget
-
-import android.content.Context
-import android.graphics.Typeface
-import android.util.AttributeSet
-import android.util.TypedValue
-import android.view.Gravity
-import android.widget.TextView
-import kotlin.properties.Delegates.observable
-import net.mullvad.mullvadvpn.R
-import net.mullvad.mullvadvpn.util.TimeLeftFormatter
-import org.joda.time.DateTime
-import org.joda.time.Duration
-
-class AccountCell : NavigateCell {
- private val formatter = TimeLeftFormatter(resources)
-
- private val expiredColor = context.getColor(R.color.red)
- private val normalColor = context.getColor(R.color.white60)
-
- private val remainingTimeLabel =
- TextView(context).apply {
- layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0.0f)
- gravity = Gravity.RIGHT
-
- resources.getDimensionPixelSize(R.dimen.cell_inner_spacing).let { padding ->
- setPadding(padding, 0, padding, 0)
- }
-
- setAllCaps(true)
- setTextColor(normalColor)
- setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.dimen.text_small))
- setTypeface(null, Typeface.BOLD)
-
- text = ""
- }
-
- var accountExpiry by
- observable<DateTime?>(null) { _, _, expiry ->
- remainingTimeLabel.apply {
- if (expiry != null) {
- val remainingTime = Duration(DateTime.now(), expiry)
-
- if (remainingTime.isShorterThan(Duration.ZERO)) {
- setText(R.string.out_of_time)
- setTextColor(expiredColor)
- } else {
- setText(formatter.format(expiry, remainingTime))
- setTextColor(normalColor)
- }
- } else {
- text = ""
- }
- }
- }
-
- constructor(context: Context) : super(context)
-
- constructor(context: Context, attributes: AttributeSet) : super(context, attributes)
-
- constructor(
- context: Context,
- attributes: AttributeSet,
- defaultStyleAttribute: Int
- ) : super(context, attributes, defaultStyleAttribute)
-
- init {
- cell.addView(remainingTimeLabel, cell.childCount - 1)
- }
-}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/HeaderBar.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/HeaderBar.kt
index 6f7ca5e8c5..788bc92691 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/HeaderBar.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/HeaderBar.kt
@@ -7,6 +7,7 @@ import android.view.LayoutInflater
import android.view.View
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
import kotlin.properties.Delegates.observable
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.model.TunnelState
@@ -24,6 +25,7 @@ constructor(
) : LinearLayout(context, attributes, defStyleAttr, defStyleRes), StatusBarPainter {
private val container = LayoutInflater.from(context).inflate(R.layout.header_bar, this)
private val settingsButton = findViewById<View>(R.id.settings)
+ private val accountButton = findViewById<View>(R.id.account)
private val disabledColor = ContextCompat.getColor(context, android.R.color.transparent)
private val securedColor = ContextCompat.getColor(context, R.color.green)
@@ -48,6 +50,11 @@ constructor(
gravity = Gravity.CENTER_VERTICAL
orientation = HORIZONTAL
+ accountButton.apply {
+ isEnabled = true
+ setOnClickListener { (context as? MainActivity)?.openAccount() }
+ }
+
settingsButton.apply {
isEnabled = true
setOnClickListener { (context as? MainActivity)?.openSettings() }
@@ -56,6 +63,10 @@ constructor(
tunnelState = null
}
+ fun setAccountButtonVisibility(isVisible: Boolean) {
+ accountButton.isVisible = isVisible
+ }
+
fun setSettingsButtonEnabled(isEnabled: Boolean) {
settingsButton.isEnabled = isEnabled
}
diff --git a/android/app/src/main/res/drawable/icon_account.xml b/android/app/src/main/res/drawable/icon_account.xml
new file mode 100644
index 0000000000..7fe5c11f05
--- /dev/null
+++ b/android/app/src/main/res/drawable/icon_account.xml
@@ -0,0 +1,12 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path android:pathData="M12,24A12,12 0,0 1,3.515 3.515a12,12 0,1 1,16.97 16.97A11.922,11.922 0,0 1,12 24zM12,12.175a12.164,12.164 0,0 0,-2.873 0.348,17.625 17.625,0 0,0 -2.99,1.048A2.85,2.85 0,0 0,5 14.525a2.573,2.573 0,0 0,-0.442 1.512v0.791a1.39,1.39 0,0 0,1.4 1.4h12.1a1.392,1.392 0,0 0,1.4 -1.4v-0.791A2.567,2.567 0,0 0,19 14.525a2.809,2.809 0,0 0,-1.163 -0.954,19.906 19.906,0 0,0 -2.978,-1.036 11.634,11.634 0,0 0,-2.859 -0.36zM12,3.775a3.345,3.345 0,0 0,-3.49 3.491,3.346 3.346,0 0,0 3.49,3.49 3.348,3.348 0,0 0,3.49 -3.49A3.346,3.346 0,0 0,12 3.776z"
+ android:strokeWidth="1"
+ android:fillColor="#FFFFFF"
+ android:fillAlpha="0.8"
+ android:fillType="evenOdd"
+ android:strokeColor="#00000000" />
+</vector>
diff --git a/android/app/src/main/res/layout/account.xml b/android/app/src/main/res/layout/account.xml
index 01a003c883..86af11c504 100644
--- a/android/app/src/main/res/layout/account.xml
+++ b/android/app/src/main/res/layout/account.xml
@@ -14,10 +14,13 @@
android:orientation="vertical">
<FrameLayout android:layout_width="match_parent"
android:layout_height="wrap_content">
- <net.mullvad.mullvadvpn.ui.widget.BackButton android:id="@+id/back"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- mullvad:text="@string/settings" />
+ <ImageButton android:id="@+id/close"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="12dp"
+ android:background="?android:attr/selectableItemBackground"
+ android:src="@drawable/icon_close"
+ android:contentDescription="@string/back" />
<TextView android:id="@+id/collapsed_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/android/app/src/main/res/layout/header_bar.xml b/android/app/src/main/res/layout/header_bar.xml
index 9ca2756626..f040afd9cb 100644
--- a/android/app/src/main/res/layout/header_bar.xml
+++ b/android/app/src/main/res/layout/header_bar.xml
@@ -22,6 +22,16 @@
app:layout_constraintStart_toEndOf="@id/appIcon"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
+ <ImageButton android:id="@+id/account"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingHorizontal="16dp"
+ android:src="@drawable/icon_account"
+ app:layout_constraintEnd_toStartOf="@id/settings"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:contentDescription="@string/settings_account" />
<ImageButton android:id="@+id/settings"
android:layout_width="wrap_content"
android:layout_height="match_parent"
@@ -30,6 +40,7 @@
android:src="@drawable/icon_settings"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent" />
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:contentDescription="@string/settings" />
</androidx.constraintlayout.widget.ConstraintLayout>
</merge>
diff --git a/android/app/src/main/res/layout/settings.xml b/android/app/src/main/res/layout/settings.xml
index 0bd735a887..fe4d75ba99 100644
--- a/android/app/src/main/res/layout/settings.xml
+++ b/android/app/src/main/res/layout/settings.xml
@@ -43,15 +43,10 @@
android:lines="1"
android:text="@string/settings"
style="@style/SettingsExpandedHeader" />
- <net.mullvad.mullvadvpn.ui.widget.AccountCell android:id="@+id/account"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/vertical_space"
- mullvad:text="@string/settings_account" />
<net.mullvad.mullvadvpn.ui.widget.NavigateCell android:id="@+id/vpn_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="1dp"
+ android:layout_marginTop="@dimen/vertical_space"
mullvad:text="@string/settings_vpn" />
<net.mullvad.mullvadvpn.ui.widget.NavigateCell android:id="@+id/split_tunneling"
android:layout_width="match_parent"