summaryrefslogtreecommitdiffhomepage
path: root/android/src
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2020-09-21 12:47:43 -0300
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2020-09-21 12:47:43 -0300
commite8d6ab89a0d366af194ce252f9f4588d2014611c (patch)
tree1fd8bbbc72d5a27ba12a13bf10a20a3265d2dabe /android/src
parent81732d99c82fbf7279a843a2764f87b41ac54528 (diff)
parentaae401cca90e418a6d820b00af0c83143e8c646d (diff)
downloadmullvadvpn-e8d6ab89a0d366af194ce252f9f4588d2014611c.tar.xz
mullvadvpn-e8d6ab89a0d366af194ce252f9f4588d2014611c.zip
Merge branch 'change-account-history-animation'
Diffstat (limited to 'android/src')
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt4
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountLogin.kt117
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountLoginBorder.kt14
-rw-r--r--android/src/main/res/drawable/account_history_background.xml18
-rw-r--r--android/src/main/res/drawable/account_history_entry_background.xml20
-rw-r--r--android/src/main/res/layout/account_history_entry.xml14
-rw-r--r--android/src/main/res/layout/account_login.xml22
-rw-r--r--android/src/main/res/layout/login.xml10
-rw-r--r--android/src/main/res/values/dimensions.xml2
9 files changed, 136 insertions, 85 deletions
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt
index 0deaff3ed8..85f2da5e61 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt
@@ -55,6 +55,10 @@ class LoginFragment : ServiceDependentFragment(OnNoService.GoToLaunchScreen) {
scrollArea = view.findViewById(R.id.scroll_area)
+ view.findViewById<View>(R.id.contents).setOnClickListener {
+ accountLogin.clearFocus()
+ }
+
fetchHistory()
scrollToShow(accountLogin)
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountLogin.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountLogin.kt
index c2acd6a924..131d9c0c65 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountLogin.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountLogin.kt
@@ -1,9 +1,14 @@
package net.mullvad.mullvadvpn.ui.widget
+import android.animation.ValueAnimator
+import android.app.Activity
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
+import android.view.View.OnLayoutChangeListener
+import android.view.ViewGroup.MarginLayoutParams
+import android.view.inputmethod.InputMethodManager
import android.widget.ArrayAdapter
import android.widget.ListView
import android.widget.RelativeLayout
@@ -24,40 +29,68 @@ class AccountLogin : RelativeLayout {
private val accountHistoryList: ListView = container.findViewById(R.id.history)
private val input: AccountInput = container.findViewById(R.id.input)
- private var shouldShowAccountHistory = false
- set(value) {
- synchronized(this) {
- field = value
- updateAccountHistory()
- }
+ private val dividerHeight = resources.getDimensionPixelSize(R.dimen.account_history_divider)
+ private val historyEntryHeight =
+ resources.getDimensionPixelSize(R.dimen.account_history_entry_height)
+
+ private val historyAnimation = ValueAnimator.ofInt(0, 0).apply {
+ addUpdateListener { animation ->
+ updateHeight(animation.animatedValue as Int)
+ }
+
+ duration = 350
+ }
+
+ private val expandedHeight: Int
+ get() = collapsedHeight + historyHeight
+
+ private var historyHeight by observable(0) { _, oldHistoryHeight, newHistoryHeight ->
+ if (newHistoryHeight != oldHistoryHeight) {
+ historyAnimation.setIntValues(collapsedHeight, expandedHeight)
+ reposition()
+ }
+ }
+
+ private var collapsedHeight by observable(0) { _, oldCollapsedHeight, newCollapsedHeight ->
+ if (newCollapsedHeight != oldCollapsedHeight) {
+ historyAnimation.setIntValues(newCollapsedHeight, expandedHeight)
+ reposition()
}
+ }
private var inputHasFocus by observable(false) { _, _, hasFocus ->
updateBorder()
+ shouldShowAccountHistory = hasFocus
- if (hasFocus) {
- shouldShowAccountHistory = true
+ if (!hasFocus) {
+ hideKeyboard()
}
}
- var accountHistory: ArrayList<String>? = null
- set(value) {
- synchronized(this) {
- field = value
- updateAccountHistory()
+ private var shouldShowAccountHistory by observable(false) { _, isShown, show ->
+ if (isShown != show) {
+ if (show) {
+ historyAnimation.start()
+ } else {
+ historyAnimation.reverse()
}
}
+ }
+
+ var accountHistory by observable<ArrayList<String>?>(null) { _, _, history ->
+ val entryCount = history?.size ?: 0
+
+ historyHeight = entryCount * (historyEntryHeight + dividerHeight)
+ updateAccountHistory()
+ }
var state: LoginState by observable(LoginState.Initial) { _, _, newState ->
input.loginState = newState
updateBorder()
- when (newState) {
- LoginState.Initial -> {}
- LoginState.InProgress -> loggingInState()
- LoginState.Success -> successState()
- LoginState.Failure -> {}
+ if (newState == LoginState.Success) {
+ visibility = View.INVISIBLE
}
}
@@ -81,6 +114,8 @@ class AccountLogin : RelativeLayout {
}
init {
+ border.elevation = elevation + 0.1f
+
input.apply {
onFocusChanged.subscribe(this) { hasFocus ->
inputHasFocus = hasFocus
@@ -91,6 +126,12 @@ class AccountLogin : RelativeLayout {
state = LoginState.Initial
}
}
+
+ addOnLayoutChangeListener(
+ OnLayoutChangeListener { _, _, top, _, bottom, _, _, _, _ ->
+ collapsedHeight = bottom - top
+ }
+ )
}
}
@@ -99,14 +140,6 @@ class AccountLogin : RelativeLayout {
input.onTextChanged.unsubscribe(this)
}
- private fun loggingInState() {
- accountHistoryList.visibility = View.INVISIBLE
- }
-
- private fun successState() {
- visibility = View.INVISIBLE
- }
-
private fun updateAccountHistory() {
accountHistory?.let { history ->
accountHistoryList.apply {
@@ -123,12 +156,6 @@ class AccountLogin : RelativeLayout {
input.loginWith(history[idx])
}
}
-
- if (shouldShowAccountHistory && accountHistoryList.visibility != View.VISIBLE) {
- accountHistoryList.visibility = View.VISIBLE
- accountHistoryList.translationY = -accountHistoryList.height.toFloat()
- accountHistoryList.animate().translationY(0.0F).setDuration(350).start()
- }
}
}
@@ -141,4 +168,30 @@ class AccountLogin : RelativeLayout {
border.borderState = BorderState.UNFOCUSED
}
}
+
+ private fun updateHeight(height: Int) {
+ val layoutParams = container.layoutParams as MarginLayoutParams
+
+ layoutParams.height = height
+ layoutParams.bottomMargin = expandedHeight - height
+
+ container.layoutParams = layoutParams
+ }
+
+ private fun reposition() {
+ historyAnimation.end()
+
+ if (shouldShowAccountHistory) {
+ updateHeight(expandedHeight)
+ } else {
+ updateHeight(collapsedHeight)
+ }
+ }
+
+ private fun hideKeyboard() {
+ val inputManagerId = Activity.INPUT_METHOD_SERVICE
+ val inputManager = context.getSystemService(inputManagerId) as InputMethodManager
+
+ inputManager.hideSoftInputFromWindow(windowToken, 0)
+ }
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountLoginBorder.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountLoginBorder.kt
index ee29ef9be0..e5ee732e08 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountLoginBorder.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountLoginBorder.kt
@@ -72,20 +72,6 @@ class AccountLoginBorder : RelativeLayout {
}
}
- init {
- val borderElevation = elevation + 0.1f
-
- topLeftCorner.elevation = borderElevation
- topRightCorner.elevation = borderElevation
- bottomLeftCorner.elevation = borderElevation
- bottomRightCorner.elevation = borderElevation
-
- topBorder.elevation = borderElevation
- leftBorder.elevation = borderElevation
- rightBorder.elevation = borderElevation
- bottomBorder.elevation = borderElevation
- }
-
constructor(context: Context) : super(context) {}
constructor(context: Context, attributes: AttributeSet) : super(context, attributes) {}
diff --git a/android/src/main/res/drawable/account_history_background.xml b/android/src/main/res/drawable/account_history_background.xml
deleted file mode 100644
index 596eb2d43d..0000000000
--- a/android/src/main/res/drawable/account_history_background.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item>
- <shape xmlns:android="http://schemas.android.com/apk/res/android">
- <corners android:radius="@dimen/account_login_corner_radius" />
- <solid android:color="@color/darkBlue" />
- </shape>
- </item>
- <item android:top="0dp"
- android:right="1dp"
- android:bottom="1dp"
- android:left="1dp">
- <shape xmlns:android="http://schemas.android.com/apk/res/android">
- <corners android:radius="@dimen/account_login_corner_radius" />
- <solid android:color="@color/white" />
- </shape>
- </item>
-</layer-list>
diff --git a/android/src/main/res/drawable/account_history_entry_background.xml b/android/src/main/res/drawable/account_history_entry_background.xml
new file mode 100644
index 0000000000..ea25d2b72a
--- /dev/null
+++ b/android/src/main/res/drawable/account_history_entry_background.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <item android:state_pressed="false"
+ android:state_focused="false">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/white60" />
+ </shape>
+ </item>
+ <item android:state_pressed="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/white40" />
+ </shape>
+ </item>
+ <item android:state_focused="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/white40" />
+ </shape>
+ </item>
+</selector>
diff --git a/android/src/main/res/layout/account_history_entry.xml b/android/src/main/res/layout/account_history_entry.xml
index 1860a96262..440cce957d 100644
--- a/android/src/main/res/layout/account_history_entry.xml
+++ b/android/src/main/res/layout/account_history_entry.xml
@@ -1,12 +1,14 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/account_history_entry_height"
android:orientation="vertical">
<TextView android:id="@+id/account_history_entry_text_view"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:textColor="@color/blue"
- android:padding="10dip"
- android:textSize="@dimen/text_medium"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/account_history_entry_background"
+ android:paddingHorizontal="12dp"
+ android:gravity="center_vertical"
+ android:textColor="@color/blue80"
+ android:textSize="@dimen/text_medium_plus"
android:textStyle="bold" />
</LinearLayout>
diff --git a/android/src/main/res/layout/account_login.xml b/android/src/main/res/layout/account_login.xml
index b64a52d6e6..43d76c89e6 100644
--- a/android/src/main/res/layout/account_login.xml
+++ b/android/src/main/res/layout/account_login.xml
@@ -1,20 +1,18 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<net.mullvad.mullvadvpn.ui.widget.AccountLoginBorder android:id="@+id/border"
android:layout_width="match_parent"
- android:layout_height="48dp"
- android:layout_alignParentTop="true">
- <net.mullvad.mullvadvpn.ui.widget.AccountInput android:id="@+id/input"
- android:layout_width="match_parent"
- android:layout_height="48dp"
- android:layout_alignParentTop="true"
- android:orientation="horizontal" />
- </net.mullvad.mullvadvpn.ui.widget.AccountLoginBorder>
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentBottom="true" />
+ <net.mullvad.mullvadvpn.ui.widget.AccountInput android:id="@+id/input"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:layout_alignParentTop="true"
+ android:orientation="horizontal" />
<ListView android:id="@+id/history"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/border"
+ android:layout_below="@id/input"
android:divider="@drawable/account_history_list_divider"
- android:dividerHeight="1dp"
- android:visibility="invisible"
- android:background="@drawable/account_history_background" />
+ android:dividerHeight="@dimen/account_history_divider" />
</merge>
diff --git a/android/src/main/res/layout/login.xml b/android/src/main/res/layout/login.xml
index 4510d0c627..0f34a409c6 100644
--- a/android/src/main/res/layout/login.xml
+++ b/android/src/main/res/layout/login.xml
@@ -4,9 +4,13 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
- <LinearLayout android:layout_width="match_parent"
+ <LinearLayout android:id="@+id/contents"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:descendantFocusability="beforeDescendants">
<net.mullvad.mullvadvpn.ui.widget.HeaderBar android:id="@+id/header_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
@@ -66,7 +70,7 @@
android:text="@string/login_description" />
<net.mullvad.mullvadvpn.ui.widget.AccountLogin android:id="@+id/account_login"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="@dimen/account_history_entry_height" />
<Space android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3" />
diff --git a/android/src/main/res/values/dimensions.xml b/android/src/main/res/values/dimensions.xml
index 692fba86e4..235c3d94b3 100644
--- a/android/src/main/res/values/dimensions.xml
+++ b/android/src/main/res/values/dimensions.xml
@@ -6,6 +6,8 @@
<dimen name="dialog_margin">14dp</dimen>
<dimen name="account_login_corner_radius">4dp</dimen>
<dimen name="account_login_border_width">2dp</dimen>
+ <dimen name="account_history_divider">1dp</dimen>
+ <dimen name="account_history_entry_height">48dp</dimen>
<dimen name="edit_text_corner_radius">4dp</dimen>
<dimen name="button_height">44dp</dimen>
<dimen name="cell_switch_border_radius">16dp</dimen>