diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2020-10-19 10:01:05 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2020-10-19 10:01:05 -0300 |
| commit | a702afabaee292e92a80a1d6c0a75f80f2babb8d (patch) | |
| tree | d853e5951b9fc4768f7e4605002d3823df607fe3 | |
| parent | 8ad9aa6fdd743cbcd6ea97d837243cd4d9cb0e46 (diff) | |
| parent | 62050280478d255e03e20dc1fdd54d707d4751f8 (diff) | |
| download | mullvadvpn-a702afabaee292e92a80a1d6c0a75f80f2babb8d.tar.xz mullvadvpn-a702afabaee292e92a80a1d6c0a75f80f2babb8d.zip | |
Merge branch 'improve-keyboard-navigation'
27 files changed, 236 insertions, 104 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index e12122a24a..31c589782e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,8 +33,10 @@ Line wrap the file at 100 chars. Th - Remove WireGuard keys during uninstallation after the firewall is unlocked. #### Android -- Removed the Quit button. +- Remove the Quit button. - Add button to remove account and WireGuard key from history in the login screen. +- Improve navigation in the app using a keyboard, so that touchless devices (like TVs) can be used + more smoothly. ### Fixed - Fix missing map animation after selecting a new location in the desktop app. diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemHolder.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemHolder.kt index e375bf2113..a215930194 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemHolder.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemHolder.kt @@ -2,6 +2,7 @@ package net.mullvad.mullvadvpn.relaylist import android.support.v7.widget.RecyclerView.ViewHolder import android.view.View +import android.view.ViewGroup.MarginLayoutParams import android.widget.ImageButton import android.widget.ImageView import android.widget.TextView @@ -14,6 +15,8 @@ class RelayItemHolder( ) : ViewHolder(view) { private val name: TextView = view.findViewById(R.id.name) private val chevron: ImageButton = view.findViewById(R.id.chevron) + private val clickArea: View = view.findViewById(R.id.click_area) + private val relayStatus: View = view.findViewById(R.id.status) private val relayActive: ImageView = view.findViewById(R.id.relay_active) private val selectedIcon: View = view.findViewById(R.id.selected) @@ -42,7 +45,7 @@ class RelayItemHolder( init { chevron.setOnClickListener { toggle() } - view.setOnClickListener { adapter.selectItem(item, this) } + clickArea.setOnClickListener { adapter.selectItem(item, this) } } private fun updateView() { @@ -71,7 +74,7 @@ class RelayItemHolder( } } - view.setEnabled(item.active) + clickArea.setEnabled(item.active) when (item.type) { RelayItemType.Country -> setViewStyle(countryColor, countryPadding) @@ -98,19 +101,17 @@ class RelayItemHolder( private fun setViewStyle(rowColor: Int, padding: Int) { var backgroundColor = rowColor - val paddingLeft = padding - val paddingTop = view.paddingTop - val paddingRight = view.paddingRight - val paddingBottom = view.paddingBottom if (selected) { backgroundColor = selectedColor } - view.apply { - setBackgroundColor(backgroundColor) - setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom) + (relayStatus.layoutParams as? MarginLayoutParams)?.let { parameters -> + parameters.leftMargin = padding + relayStatus.layoutParams = parameters } + + view.setBackgroundColor(backgroundColor) } private fun toggle() { 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 f4b2ea0f7c..c84961fc53 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt @@ -31,6 +31,7 @@ class LoginFragment : ServiceDependentFragment(OnNoService.GoToLaunchScreen) { private lateinit var loginFailStatus: View private lateinit var accountLogin: AccountLogin private lateinit var scrollArea: ScrollView + private lateinit var background: View private val loggedIn = CompletableDeferred<LoginResult>() @@ -57,8 +58,8 @@ class LoginFragment : ServiceDependentFragment(OnNoService.GoToLaunchScreen) { scrollArea = view.findViewById(R.id.scroll_area) - view.findViewById<View>(R.id.contents).setOnClickListener { - accountLogin.clearFocus() + background = view.findViewById<View>(R.id.contents).apply { + setOnClickListener { requestFocus() } } scrollToShow(accountLogin) @@ -124,6 +125,8 @@ class LoginFragment : ServiceDependentFragment(OnNoService.GoToLaunchScreen) { loginFailStatus.visibility = View.GONE loggedInStatus.visibility = View.GONE + background.requestFocus() + accountLogin.state = LoginState.InProgress scrollToShow(loggingInStatus) diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryAdapter.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryAdapter.kt index 6e88a2d9a1..737e4a3859 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryAdapter.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryAdapter.kt @@ -20,6 +20,7 @@ class AccountHistoryAdapter : Adapter<AccountHistoryHolder>() { var onSelectEntry: ((String) -> Unit)? = null var onRemoveEntry: ((String) -> Unit)? = null + var onChildFocusChanged: ((String, Boolean) -> Unit)? = null override fun onCreateViewHolder(parentView: ViewGroup, type: Int): AccountHistoryHolder { val inflater = LayoutInflater.from(parentView.context) @@ -28,6 +29,7 @@ class AccountHistoryAdapter : Adapter<AccountHistoryHolder>() { return AccountHistoryHolder(view, formatter).apply { onSelect = { account -> onSelectEntry?.invoke(account) } onRemove = { account -> onRemoveEntry?.invoke(account) } + onFocusChanged = { account, hasFocus -> onChildFocusChanged?.invoke(account, hasFocus) } } } diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryHolder.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryHolder.kt index e91897af4b..e0e911467b 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryHolder.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryHolder.kt @@ -19,14 +19,27 @@ class AccountHistoryHolder( var onSelect: ((String) -> Unit)? = null var onRemove: ((String) -> Unit)? = null + var onFocusChanged: ((String, Boolean) -> Unit)? = null init { - view.setOnClickListener { - onSelect?.invoke(accountToken) + view.findViewById<View>(R.id.remove).apply { + setOnClickListener { + onRemove?.invoke(accountToken) + } + + setOnFocusChangeListener { _, hasFocus -> + onFocusChanged?.invoke(accountToken, hasFocus) + } } - view.findViewById<View>(R.id.remove).setOnClickListener { - onRemove?.invoke(accountToken) + label.apply { + setOnClickListener { + onSelect?.invoke(accountToken) + } + + setOnFocusChangeListener { _, hasFocus -> + onFocusChanged?.invoke(accountToken, hasFocus) + } } } } 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 3cc2935c21..9052a2e63e 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 @@ -17,12 +17,17 @@ import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.ui.ListItemDividerDecoration import net.mullvad.mullvadvpn.ui.LoginState import net.mullvad.mullvadvpn.ui.widget.AccountLoginBorder.BorderState +import net.mullvad.mullvadvpn.util.Debouncer class AccountLogin : RelativeLayout { companion object { private val MAX_ACCOUNT_HISTORY_ENTRIES = 3 } + private val focusDebouncer = Debouncer(false).apply { + listener = { hasFocus -> focused = hasFocus } + } + private val container = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE).let { service -> val inflater = service as LayoutInflater @@ -36,6 +41,7 @@ class AccountLogin : RelativeLayout { private val historyAdapter = AccountHistoryAdapter().apply { onSelectEntry = { account -> input.loginWith(account) } + onChildFocusChanged = { _, hasFocus -> focusDebouncer.rawValue = hasFocus } } private val dividerHeight = resources.getDimensionPixelSize(R.dimen.account_history_divider) @@ -70,7 +76,7 @@ class AccountLogin : RelativeLayout { } } - private var inputHasFocus by observable(false) { _, _, hasFocus -> + private var focused by observable(false) { _, _, hasFocus -> updateBorder() shouldShowAccountHistory = hasFocus @@ -137,7 +143,7 @@ class AccountLogin : RelativeLayout { input.apply { onFocusChanged.subscribe(this) { hasFocus -> - inputHasFocus = hasFocus + focusDebouncer.rawValue = hasFocus } onTextChanged.subscribe(this) { _ -> @@ -173,7 +179,7 @@ class AccountLogin : RelativeLayout { private fun updateBorder() { if (state == LoginState.Failure) { border.borderState = BorderState.ERROR - } else if (inputHasFocus) { + } else if (focused) { border.borderState = BorderState.FOCUSED } else { border.borderState = BorderState.UNFOCUSED diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/BackButton.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/BackButton.kt index b0ae6024ec..b0833fd49d 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/BackButton.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/BackButton.kt @@ -40,6 +40,7 @@ class BackButton : LinearLayout { } init { + setFocusable(true) isClickable = true gravity = Gravity.CENTER_VERTICAL or Gravity.LEFT orientation = HORIZONTAL diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Cell.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Cell.kt index cb87408251..a533b5e758 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Cell.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Cell.kt @@ -43,6 +43,7 @@ open class Cell : LinearLayout { val leftPadding = resources.getDimensionPixelSize(R.dimen.cell_left_padding) val rightPadding = resources.getDimensionPixelSize(R.dimen.cell_right_padding) + setFocusable(true) isClickable = true gravity = Gravity.CENTER orientation = HORIZONTAL diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/InformationView.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/InformationView.kt index 59b5154fb8..d80506a5dd 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/InformationView.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/InformationView.kt @@ -7,6 +7,7 @@ import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout import android.widget.TextView +import kotlin.properties.Delegates.observable import net.mullvad.mullvadvpn.R open class InformationView : LinearLayout { @@ -27,7 +28,7 @@ open class InformationView : LinearLayout { } } - private val container = + private val container: View = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE).let { service -> val inflater = service as LayoutInflater @@ -41,55 +42,23 @@ open class InformationView : LinearLayout { private val informationDisplay: TextView = findViewById(R.id.information_display) private val spinner: View = findViewById(R.id.spinner) - var displayFormatter: ((String) -> String)? = null - set(value) { - field = value - updateStatus() - } - - var shouldEnable = false - set(value) { - field = value - updateEnabled() - } - - var error: String? = null - set(value) { - field = value - updateStatus() - } - - var errorColor = context.getColor(R.color.red) - set(value) { - field = value - updateStatus() - } + var error by observable<String?>(null) { _, _, _ -> updateStatus() } + var information by observable<String?>(null) { _, _, _ -> updateStatus() } - var information: String? = null - set(value) { - field = value - updateStatus() - } + var errorColor by observable(context.getColor(R.color.red)) { _, _, _ -> updateStatus() } + var informationColor by observable(context.getColor(R.color.white)) { _, _, _ -> + updateStatus() + } - var informationColor = context.getColor(R.color.white) - set(value) { - field = value - updateStatus() - } + var displayFormatter by observable<((String) -> String)?>(null) { _, _, _ -> updateStatus() } + var maxLength by observable(0) { _, _, _ -> updateStatus() } + var whenMissing by observable(WhenMissing.Nothing) { _, _, _ -> updateStatus() } - var maxLength = 0 - set(value) { - field = value - updateStatus() - } + var shouldEnable by observable(false) { _, _, _ -> updateEnabled() } - var whenMissing = WhenMissing.Nothing - set(value) { - field = value - updateStatus() - } - - var onClick: (() -> Unit)? = null + var onClick by observable<(() -> Unit)?>(null) { _, _, callback -> + container.setFocusable(callback != null) + } constructor(context: Context) : super(context) {} diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/MtuCell.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/MtuCell.kt index eb1463cd45..94ddc2838e 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/MtuCell.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/MtuCell.kt @@ -66,8 +66,11 @@ class MtuCell : Cell { ) {} init { - cell.setEnabled(false) - cell.addView(input) + cell.apply { + setEnabled(false) + setFocusable(false) + addView(input) + } footer?.text = context.getString(R.string.wireguard_mtu_footer, MIN_MTU_VALUE, MAX_MTU_VALUE) diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/util/Debouncer.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/util/Debouncer.kt new file mode 100644 index 0000000000..7afb4c508f --- /dev/null +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/util/Debouncer.kt @@ -0,0 +1,39 @@ +package net.mullvad.mullvadvpn.util + +import kotlin.properties.Delegates.observable +import kotlinx.coroutines.delay + +// Helper to filter out bursts of events so that only the latest event in an interval is notified. +// +// An interval of zero means that it will only debounce events that are sent before the job is +// started. If the events are coming from the UI thread, this means that this class will only send +// the last event received before the UI thread finishes its current task. +// +// This can be used for example to filter out focus events coming from different views. Android will +// first send a "focus lost" event from a view followed by a "focus gained" event from another view. +// If the only thing the listener is interested in is if any of a set of views has focus, this class +// can be used to debounce focus events from the set of views to obtain an event that represents a +// change from when the set contains a focused view to when the set contains no focused views (and +// an event for the reverse situation). +class Debouncer<T>(initialValue: T, val intervalInMs: Long = 0) { + private val jobTracker = JobTracker() + + var listener: ((T) -> Unit)? = null + + var debouncedValue = initialValue + private set + + var rawValue by observable(initialValue) { _, oldValue, newValue -> + if (newValue != oldValue) { + jobTracker.cancelJob("notifyNewValue") + + if (newValue != debouncedValue) { + jobTracker.newUiJob("notifyNewValue") { + delay(intervalInMs) + listener?.invoke(newValue) + debouncedValue = newValue + } + } + } + } +} diff --git a/android/src/main/res/drawable/app_list_item_background.xml b/android/src/main/res/drawable/app_list_item_background.xml index 9cde2e4032..a55c1e6d01 100644 --- a/android/src/main/res/drawable/app_list_item_background.xml +++ b/android/src/main/res/drawable/app_list_item_background.xml @@ -1,10 +1,17 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="false"> + <item android:state_pressed="false" + android:state_focused="false"> <shape android:shape="rectangle"> <solid android:color="@color/blue40" /> </shape> </item> + <item android:state_pressed="false" + android:state_focused="true"> + <shape android:shape="rectangle"> + <solid android:color="@color/blue80" /> + </shape> + </item> <item android:state_pressed="true"> <shape android:shape="rectangle"> <solid android:color="@color/blue60" /> diff --git a/android/src/main/res/drawable/blue_button_background.xml b/android/src/main/res/drawable/blue_button_background.xml index 44f0406e46..e87b080bee 100644 --- a/android/src/main/res/drawable/blue_button_background.xml +++ b/android/src/main/res/drawable/blue_button_background.xml @@ -1,11 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="false"> + <item android:state_pressed="false" + android:state_focused="false"> <shape android:shape="rectangle"> <corners android:radius="4dp" /> <solid android:color="@color/blue80" /> </shape> </item> + <item android:state_pressed="false" + android:state_focused="true"> + <shape android:shape="rectangle"> + <corners android:radius="4dp" /> + <solid android:color="@color/blue40" /> + </shape> + </item> <item android:state_pressed="true"> <shape android:shape="rectangle"> <corners android:radius="4dp" /> diff --git a/android/src/main/res/drawable/cell_button_background.xml b/android/src/main/res/drawable/cell_button_background.xml index e00f49464d..857a8386e1 100644 --- a/android/src/main/res/drawable/cell_button_background.xml +++ b/android/src/main/res/drawable/cell_button_background.xml @@ -1,10 +1,17 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="false"> + <item android:state_pressed="false" + android:state_focused="false"> <shape android:shape="rectangle"> <solid android:color="@color/blue" /> </shape> </item> + <item android:state_pressed="false" + android:state_focused="true"> + <shape android:shape="rectangle"> + <solid android:color="@color/blue60" /> + </shape> + </item> <item android:state_pressed="true"> <shape android:shape="rectangle"> <solid android:color="@color/blue80" /> diff --git a/android/src/main/res/drawable/green_button_background.xml b/android/src/main/res/drawable/green_button_background.xml index 275f4fc3cb..b2a50d5678 100644 --- a/android/src/main/res/drawable/green_button_background.xml +++ b/android/src/main/res/drawable/green_button_background.xml @@ -1,11 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="false"> + <item android:state_pressed="false" + android:state_focused="false"> <shape android:shape="rectangle"> <corners android:radius="4dp" /> <solid android:color="@color/green" /> </shape> </item> + <item android:state_pressed="false" + android:state_focused="true"> + <shape android:shape="rectangle"> + <corners android:radius="4dp" /> + <solid android:color="@color/green80" /> + </shape> + </item> <item android:state_pressed="true"> <shape android:shape="rectangle"> <corners android:radius="4dp" /> diff --git a/android/src/main/res/drawable/red_button_background.xml b/android/src/main/res/drawable/red_button_background.xml index 69f16f298f..e41121638f 100644 --- a/android/src/main/res/drawable/red_button_background.xml +++ b/android/src/main/res/drawable/red_button_background.xml @@ -1,11 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="false"> + <item android:state_pressed="false" + android:state_focused="false"> <shape android:shape="rectangle"> <corners android:radius="4dp" /> <solid android:color="@color/red" /> </shape> </item> + <item android:state_pressed="false" + android:state_focused="true"> + <shape android:shape="rectangle"> + <corners android:radius="4dp" /> + <solid android:color="@color/red80" /> + </shape> + </item> <item android:state_pressed="true"> <shape android:shape="rectangle"> <corners android:radius="4dp" /> diff --git a/android/src/main/res/drawable/transparent_red_button_background.xml b/android/src/main/res/drawable/transparent_red_button_background.xml index e284fb9bfb..84a3a77c38 100644 --- a/android/src/main/res/drawable/transparent_red_button_background.xml +++ b/android/src/main/res/drawable/transparent_red_button_background.xml @@ -1,11 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="false"> + <item android:state_pressed="false" + android:state_focused="false"> <shape android:shape="rectangle"> <corners android:radius="4dp" /> <solid android:color="@color/red60" /> </shape> </item> + <item android:state_pressed="false" + android:state_focused="true"> + <shape android:shape="rectangle"> + <corners android:radius="4dp" /> + <solid android:color="@color/red95" /> + </shape> + </item> <item android:state_pressed="true"> <shape android:shape="rectangle"> <corners android:radius="4dp" /> diff --git a/android/src/main/res/drawable/transparent_red_left_half_button_background.xml b/android/src/main/res/drawable/transparent_red_left_half_button_background.xml index 1102ec771b..dab41c1f57 100644 --- a/android/src/main/res/drawable/transparent_red_left_half_button_background.xml +++ b/android/src/main/res/drawable/transparent_red_left_half_button_background.xml @@ -1,12 +1,21 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="false"> + <item android:state_pressed="false" + android:state_focused="false"> <shape android:shape="rectangle"> <corners android:topLeftRadius="4dp" android:bottomLeftRadius="4dp" /> <solid android:color="@color/red60" /> </shape> </item> + <item android:state_pressed="false" + android:state_focused="true"> + <shape android:shape="rectangle"> + <corners android:topLeftRadius="4dp" + android:bottomLeftRadius="4dp" /> + <solid android:color="@color/red95" /> + </shape> + </item> <item android:state_pressed="true"> <shape android:shape="rectangle"> <corners android:topLeftRadius="4dp" diff --git a/android/src/main/res/drawable/transparent_red_right_half_button_background.xml b/android/src/main/res/drawable/transparent_red_right_half_button_background.xml index 0c31d5f429..f23bde9841 100644 --- a/android/src/main/res/drawable/transparent_red_right_half_button_background.xml +++ b/android/src/main/res/drawable/transparent_red_right_half_button_background.xml @@ -1,12 +1,21 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="false"> + <item android:state_pressed="false" + android:state_focused="false"> <shape android:shape="rectangle"> <corners android:topRightRadius="4dp" android:bottomRightRadius="4dp" /> <solid android:color="@color/red60" /> </shape> </item> + <item android:state_pressed="false" + android:state_focused="true"> + <shape android:shape="rectangle"> + <corners android:topRightRadius="4dp" + android:bottomRightRadius="4dp" /> + <solid android:color="@color/red95" /> + </shape> + </item> <item android:state_pressed="true"> <shape android:shape="rectangle"> <corners android:topRightRadius="4dp" diff --git a/android/src/main/res/drawable/white20_button_background.xml b/android/src/main/res/drawable/white20_button_background.xml index 8a2601fdf8..f52c7cf182 100644 --- a/android/src/main/res/drawable/white20_button_background.xml +++ b/android/src/main/res/drawable/white20_button_background.xml @@ -1,11 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="false"> + <item android:state_pressed="false" + android:state_focused="false"> <shape android:shape="rectangle"> <corners android:radius="4dp" /> <solid android:color="@color/white20" /> </shape> </item> + <item android:state_pressed="false" + android:state_focused="true"> + <shape android:shape="rectangle"> + <corners android:radius="4dp" /> + <solid android:color="@color/white60" /> + </shape> + </item> <item android:state_pressed="true"> <shape android:shape="rectangle"> <corners android:radius="4dp" /> diff --git a/android/src/main/res/layout/account_history_entry.xml b/android/src/main/res/layout/account_history_entry.xml index d410b5138c..746de82d3c 100644 --- a/android/src/main/res/layout/account_history_entry.xml +++ b/android/src/main/res/layout/account_history_entry.xml @@ -4,6 +4,7 @@ <TextView android:id="@+id/label" android:layout_width="match_parent" android:layout_height="match_parent" + android:focusable="true" android:background="@drawable/account_history_entry_background" android:paddingHorizontal="12dp" android:gravity="center_vertical" diff --git a/android/src/main/res/layout/app_list_item.xml b/android/src/main/res/layout/app_list_item.xml index c705db1085..eebfccf88e 100644 --- a/android/src/main/res/layout/app_list_item.xml +++ b/android/src/main/res/layout/app_list_item.xml @@ -5,7 +5,8 @@ android:background="@drawable/app_list_item_background" android:orientation="horizontal" android:gravity="center" - android:clickable="true"> + android:clickable="true" + android:focusable="true"> <ProgressBar android:id="@+id/loading" android:layout_width="@dimen/app_list_item_icon_size" android:layout_height="@dimen/app_list_item_icon_size" diff --git a/android/src/main/res/layout/connect.xml b/android/src/main/res/layout/connect.xml index 7fd06fd4bc..254dd05442 100644 --- a/android/src/main/res/layout/connect.xml +++ b/android/src/main/res/layout/connect.xml @@ -73,6 +73,7 @@ android:paddingHorizontal="@dimen/side_margin" android:gravity="bottom" android:clickable="true" + android:focusable="true" android:background="?android:attr/selectableItemBackground"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" diff --git a/android/src/main/res/layout/notification_banner.xml b/android/src/main/res/layout/notification_banner.xml index abd28193d8..3fb5ef4d10 100644 --- a/android/src/main/res/layout/notification_banner.xml +++ b/android/src/main/res/layout/notification_banner.xml @@ -4,6 +4,7 @@ android:paddingVertical="8dp" android:paddingLeft="16dp" android:paddingRight="12dp" + android:focusable="true" android:background="?android:attr/selectableItemBackground"> <RelativeLayout android:id="@+id/notification_status_container" android:layout_width="wrap_content" diff --git a/android/src/main/res/layout/relay_list_item.xml b/android/src/main/res/layout/relay_list_item.xml index c8af318778..e0b084901c 100644 --- a/android/src/main/res/layout/relay_list_item.xml +++ b/android/src/main/res/layout/relay_list_item.xml @@ -1,34 +1,48 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingLeft="@dimen/country_row_padding" android:background="@color/blue" - android:orientation="horizontal" - android:gravity="center"> - <FrameLayout android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="0"> - <ImageView android:id="@+id/relay_active" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:src="@drawable/icon_relay_active" /> - <ImageView android:id="@+id/selected" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:src="@drawable/icon_tick" - android:visibility="invisible" /> - </FrameLayout> - <TextView android:id="@+id/name" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - android:layout_marginHorizontal="8dp" - android:layout_marginVertical="14dp" - android:textColor="@color/white" - android:textSize="@dimen/text_medium_plus" - android:textStyle="bold" - android:text="" /> + android:orientation="horizontal"> + <RelativeLayout android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_weight="1"> + <View android:id="@+id/click_area" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_alignParentLeft="true" + android:layout_alignParentRight="true" + android:focusable="true" + android:clickable="true" + android:background="?android:attr/selectableItemBackground" /> + <FrameLayout android:id="@+id/status" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + android:layout_centerVertical="true" + android:layout_marginLeft="@dimen/country_row_padding"> + <ImageView android:id="@+id/relay_active" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:src="@drawable/icon_relay_active" /> + <ImageView android:id="@+id/selected" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/icon_tick" + android:visibility="invisible" /> + </FrameLayout> + <TextView android:id="@+id/name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginHorizontal="8dp" + android:layout_marginVertical="14dp" + android:layout_alignParentRight="true" + android:layout_toRightOf="@id/status" + android:textColor="@color/white" + android:textSize="@dimen/text_medium_plus" + android:textStyle="bold" + android:text="" /> + </RelativeLayout> <ImageButton android:id="@+id/chevron" android:layout_width="wrap_content" android:layout_height="match_parent" diff --git a/android/src/main/res/layout/welcome.xml b/android/src/main/res/layout/welcome.xml index 43348fd11d..e1c887ab96 100644 --- a/android/src/main/res/layout/welcome.xml +++ b/android/src/main/res/layout/welcome.xml @@ -35,6 +35,7 @@ android:paddingHorizontal="@dimen/side_margin" android:paddingVertical="11dp" android:clickable="true" + android:focusable="true" android:background="?android:attr/selectableItemBackground" android:textColor="@color/white" android:textSize="@dimen/text_big" diff --git a/android/src/main/res/values/colors.xml b/android/src/main/res/values/colors.xml index bc18d267f5..23d4ff564f 100644 --- a/android/src/main/res/values/colors.xml +++ b/android/src/main/res/values/colors.xml @@ -14,6 +14,7 @@ <color name="white10">#1AFFFFFF</color> <color name="green">#44AD4D</color> <color name="green90">#E644AD4D</color> + <color name="green80">#CC44AD4D</color> <color name="red">#FFE34039</color> <color name="red95">#F2E34039</color> <color name="red80">#CCE34039</color> |
