summaryrefslogtreecommitdiffhomepage
path: root/android/src
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2019-03-15 19:17:58 +0000
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2019-03-18 17:03:54 +0000
commitcdc6e80d840e11cc75d3daa4929b2d4dc1c42e8b (patch)
tree67b7da2f526b85137c73592e6f5d065881c1a5f9 /android/src
parent6b721524bb91e4078d725b4a23aaa6e9e3ac91c2 (diff)
downloadmullvadvpn-cdc6e80d840e11cc75d3daa4929b2d4dc1c42e8b.tar.xz
mullvadvpn-cdc6e80d840e11cc75d3daa4929b2d4dc1c42e8b.zip
Implement initial relay list
Diffstat (limited to 'android/src')
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/SelectLocationFragment.kt12
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/GetItemResult.kt6
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/Relay.kt3
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCity.kt30
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCountry.kt36
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItem.kt3
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemDividerDecoration.kt23
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemHolder.kt53
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemType.kt7
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayListAdapter.kt168
-rw-r--r--android/src/main/res/drawable/icon_relay_active.xml8
-rw-r--r--android/src/main/res/layout/relay_list_item.xml29
-rw-r--r--android/src/main/res/layout/select_location.xml10
-rw-r--r--android/src/main/res/values/dimensions.xml6
14 files changed, 394 insertions, 0 deletions
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/SelectLocationFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/SelectLocationFragment.kt
index 54c1b1b2e7..71f118410d 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/SelectLocationFragment.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/SelectLocationFragment.kt
@@ -2,11 +2,16 @@ package net.mullvad.mullvadvpn
import android.os.Bundle
import android.support.v4.app.Fragment
+import android.support.v7.widget.LinearLayoutManager
+import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
+import net.mullvad.mullvadvpn.relaylist.RelayItemDividerDecoration
+import net.mullvad.mullvadvpn.relaylist.RelayListAdapter
+
class SelectLocationFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
@@ -19,6 +24,13 @@ class SelectLocationFragment : Fragment() {
activity?.onBackPressed()
}
+ view.findViewById<RecyclerView>(R.id.relay_list).apply {
+ layoutManager = LinearLayoutManager(context!!)
+ adapter = RelayListAdapter()
+
+ addItemDecoration(RelayItemDividerDecoration(context!!))
+ }
+
return view
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/GetItemResult.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/GetItemResult.kt
new file mode 100644
index 0000000000..d443d30cfe
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/GetItemResult.kt
@@ -0,0 +1,6 @@
+package net.mullvad.mullvadvpn.relaylist
+
+sealed class GetItemResult {
+ data class Item(val item: RelayItem) : GetItemResult()
+ data class Count(val count: Int) : GetItemResult()
+}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/Relay.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/Relay.kt
new file mode 100644
index 0000000000..47a17c69d3
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/Relay.kt
@@ -0,0 +1,3 @@
+package net.mullvad.mullvadvpn.relaylist
+
+data class Relay(val hostname: String)
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCity.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCity.kt
new file mode 100644
index 0000000000..5ccd78bde9
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCity.kt
@@ -0,0 +1,30 @@
+package net.mullvad.mullvadvpn.relaylist
+
+class RelayCity(val city: String, val relays: List<Relay>, var expanded: Boolean) {
+ fun getItem(position: Int): GetItemResult {
+ if (position == 0) {
+ return GetItemResult.Item(RelayItem(RelayItemType.City, city))
+ }
+
+ if (!expanded) {
+ return GetItemResult.Count(1)
+ }
+
+ val offset = position - 1
+ val relayCount = relays.size
+
+ if (offset >= relayCount) {
+ return GetItemResult.Count(1 + relayCount)
+ } else {
+ return GetItemResult.Item(RelayItem(RelayItemType.Relay, relays[offset].hostname))
+ }
+ }
+
+ fun getItemCount(): Int {
+ if (expanded) {
+ return 1 + relays.size
+ } else {
+ return 1
+ }
+ }
+}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCountry.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCountry.kt
new file mode 100644
index 0000000000..6f54f50518
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayCountry.kt
@@ -0,0 +1,36 @@
+package net.mullvad.mullvadvpn.relaylist
+
+class RelayCountry(val country: String, val cities: List<RelayCity>, var expanded: Boolean) {
+ fun getItem(position: Int): GetItemResult {
+ if (position == 0) {
+ return GetItemResult.Item(RelayItem(RelayItemType.Country, country))
+ }
+
+ var itemCount = 1
+ var remaining = position - 1
+
+ if (expanded) {
+ for (city in cities) {
+ val itemOrCount = city.getItem(remaining)
+
+ when (itemOrCount) {
+ is GetItemResult.Item -> return itemOrCount
+ is GetItemResult.Count -> {
+ remaining -= itemOrCount.count
+ itemCount += itemOrCount.count
+ }
+ }
+ }
+ }
+
+ return GetItemResult.Count(itemCount)
+ }
+
+ fun getItemCount(): Int {
+ if (expanded) {
+ return 1 + cities.map { city -> city.getItemCount() }.sum()
+ } else {
+ return 1
+ }
+ }
+}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItem.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItem.kt
new file mode 100644
index 0000000000..4814df43db
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItem.kt
@@ -0,0 +1,3 @@
+package net.mullvad.mullvadvpn.relaylist
+
+data class RelayItem(val type: RelayItemType, val name: String)
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemDividerDecoration.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemDividerDecoration.kt
new file mode 100644
index 0000000000..01e66e63ab
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemDividerDecoration.kt
@@ -0,0 +1,23 @@
+package net.mullvad.mullvadvpn.relaylist
+
+import android.content.Context
+import android.graphics.Rect
+import android.support.v7.widget.RecyclerView
+import android.support.v7.widget.RecyclerView.ItemDecoration
+import android.support.v7.widget.RecyclerView.State
+import android.view.View
+
+import net.mullvad.mullvadvpn.R
+
+class RelayItemDividerDecoration(private val context: Context) : ItemDecoration() {
+ private val dividerHeight = context.resources.getDimensionPixelSize(R.dimen.relay_list_divider)
+
+ override fun getItemOffsets(offsets: Rect, view: View, parent: RecyclerView, state: State) {
+ val position = parent.getChildAdapterPosition(view)
+ val lastItem = parent.adapter!!.itemCount - 1
+
+ if (position != lastItem) {
+ offsets.bottom = dividerHeight
+ }
+ }
+}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemHolder.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemHolder.kt
new file mode 100644
index 0000000000..4934b55c4f
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemHolder.kt
@@ -0,0 +1,53 @@
+package net.mullvad.mullvadvpn.relaylist
+
+import android.support.v7.widget.RecyclerView.ViewHolder
+import android.view.View
+import android.widget.TextView
+
+import net.mullvad.mullvadvpn.R
+
+class RelayItemHolder(private val view: View) : ViewHolder(view) {
+ private val name: TextView = view.findViewById(R.id.name)
+
+ private val countryColor = view.context.getColor(R.color.blue)
+ private val cityColor = view.context.getColor(R.color.blue40)
+ private val relayColor = view.context.getColor(R.color.blue20)
+
+ private val countryPadding = view.resources.getDimensionPixelSize(R.dimen.country_row_padding)
+ private val cityPadding = view.resources.getDimensionPixelSize(R.dimen.city_row_padding)
+ private val relayPadding = view.resources.getDimensionPixelSize(R.dimen.relay_row_padding)
+
+ var item: RelayItem? = null
+ set(value) {
+ field = value
+ updateView()
+ }
+
+ private fun updateView() {
+ val item = this.item
+
+ if (item != null) {
+ name.text = item.name
+
+ when (item.type) {
+ RelayItemType.Country -> setViewStyle(countryColor, countryPadding)
+ RelayItemType.City -> setViewStyle(cityColor, cityPadding)
+ RelayItemType.Relay -> setViewStyle(relayColor, relayPadding)
+ }
+ } else {
+ name.text = ""
+ }
+ }
+
+ private fun setViewStyle(backgroundColor: Int, padding: Int) {
+ val paddingLeft = padding
+ val paddingTop = view.paddingTop
+ val paddingRight = view.paddingRight
+ val paddingBottom = view.paddingBottom
+
+ view.apply {
+ setBackgroundColor(backgroundColor)
+ setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom)
+ }
+ }
+}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemType.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemType.kt
new file mode 100644
index 0000000000..cdbd58b291
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemType.kt
@@ -0,0 +1,7 @@
+package net.mullvad.mullvadvpn.relaylist
+
+enum class RelayItemType {
+ Country,
+ City,
+ Relay,
+}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayListAdapter.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayListAdapter.kt
new file mode 100644
index 0000000000..5efa8f5990
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayListAdapter.kt
@@ -0,0 +1,168 @@
+package net.mullvad.mullvadvpn.relaylist
+
+import android.support.v7.widget.RecyclerView.Adapter
+import android.view.LayoutInflater
+import android.view.ViewGroup
+
+import net.mullvad.mullvadvpn.R
+
+class RelayListAdapter : Adapter<RelayItemHolder>() {
+ private val relayList = fakeRelayList
+
+ override fun onCreateViewHolder(parentView: ViewGroup, type: Int): RelayItemHolder {
+ val inflater = LayoutInflater.from(parentView.context)
+ val view = inflater.inflate(R.layout.relay_list_item, parentView, false)
+
+ return RelayItemHolder(view)
+ }
+
+ override fun onBindViewHolder(holder: RelayItemHolder, position: Int) {
+ var remaining = position
+
+ for (country in relayList) {
+ val itemOrCount = country.getItem(remaining)
+
+ when (itemOrCount) {
+ is GetItemResult.Item -> {
+ holder.item = itemOrCount.item
+ return
+ }
+ is GetItemResult.Count -> remaining -= itemOrCount.count
+ }
+ }
+ }
+
+ override fun getItemCount(): Int {
+ return relayList.map { country -> country.getItemCount() }.sum()
+ }
+}
+
+val fakeRelayList = listOf(
+ RelayCountry(
+ "Australia",
+ listOf(
+ RelayCity(
+ "Brisbane",
+ listOf(Relay("au-bne-001")),
+ false
+ ),
+ RelayCity(
+ "Melbourne",
+ listOf(Relay("au-mel-002"), Relay("au-mel-003"), Relay("au-mel-004")),
+ false
+ ),
+ RelayCity(
+ "Perth",
+ listOf(Relay("au-per-001")),
+ false
+ ),
+ RelayCity(
+ "Sydney",
+ listOf(
+ Relay("au1-wireguard"),
+ Relay("au-syd-001"),
+ Relay("au-syd-002"),
+ Relay("au-mel-003")
+ ),
+ false
+ )
+ ),
+ false
+ ),
+ RelayCountry(
+ "South Africa",
+ listOf(
+ RelayCity(
+ "Johannesburg",
+ listOf(Relay("za-jnb-001")),
+ false
+ )
+ ),
+ false
+ ),
+ RelayCountry(
+ "Sweden",
+ listOf(
+ RelayCity(
+ "Gothenburg",
+ listOf(
+ Relay("se3-wireguard"),
+ Relay("se5-wireguard"),
+ Relay("se-got-001"),
+ Relay("se-got-002"),
+ Relay("se-got-003"),
+ Relay("se-got-004"),
+ Relay("se-got-005"),
+ Relay("se-got-006"),
+ Relay("se-got-007")
+ ),
+ false
+ ),
+ RelayCity(
+ "Helsingborg",
+ listOf(
+ Relay("se-hel-001"),
+ Relay("se-hel-002"),
+ Relay("se-hel-003"),
+ Relay("se-hel-004"),
+ Relay("se-hel-007"),
+ Relay("se-hel-008")
+ ),
+ false
+ ),
+ RelayCity(
+ "Malmö",
+ listOf(
+ Relay("se4-wireguard"),
+ Relay("se-mma-001"),
+ Relay("se-mma-002"),
+ Relay("se-mma-003"),
+ Relay("se-mma-004"),
+ Relay("se-mma-005"),
+ Relay("se-mma-006"),
+ Relay("se-mma-007"),
+ Relay("se-mma-008"),
+ Relay("se-mma-009"),
+ Relay("se-mma-010")
+ ),
+ false
+ ),
+ RelayCity(
+ "Stockholm",
+ listOf(
+ Relay("se2-wireguard"),
+ Relay("se6-wireguard"),
+ Relay("se7-wireguard"),
+ Relay("se8-wireguard"),
+ Relay("se-sto-001"),
+ Relay("se-sto-002"),
+ Relay("se-sto-003"),
+ Relay("se-sto-004"),
+ Relay("se-sto-005"),
+ Relay("se-sto-006"),
+ Relay("se-sto-007"),
+ Relay("se-sto-008"),
+ Relay("se-sto-009"),
+ Relay("se-sto-010"),
+ Relay("se-sto-011"),
+ Relay("se-sto-012"),
+ Relay("se-sto-013"),
+ Relay("se-sto-014"),
+ Relay("se-sto-015"),
+ Relay("se-sto-016"),
+ Relay("se-sto-017"),
+ Relay("se-sto-018"),
+ Relay("se-sto-019"),
+ Relay("se-sto-020"),
+ Relay("se-sto-021"),
+ Relay("se-sto-022"),
+ Relay("se-sto-023"),
+ Relay("se-sto-024"),
+ Relay("se-sto-025")
+ ),
+ false
+ )
+ ),
+ false
+ )
+)
diff --git a/android/src/main/res/drawable/icon_relay_active.xml b/android/src/main/res/drawable/icon_relay_active.xml
new file mode 100644
index 0000000000..f6e70521f8
--- /dev/null
+++ b/android/src/main/res/drawable/icon_relay_active.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval"
+ >
+ <solid android:color="@color/green"/>
+ <size android:width="16dp" android:height="16dp"/>
+</shape>
diff --git a/android/src/main/res/layout/relay_list_item.xml b/android/src/main/res/layout/relay_list_item.xml
new file mode 100644
index 0000000000..16561ca0ec
--- /dev/null
+++ b/android/src/main/res/layout/relay_list_item.xml
@@ -0,0 +1,29 @@
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/main_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/country_row_padding"
+ android:paddingRight="24dp"
+ android:paddingVertical="16dp"
+ android:background="@color/blue"
+ android:orientation="horizontal"
+ android:gravity="center"
+ >
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:src="@drawable/icon_relay_active"
+ />
+ <TextView android:id="@+id/name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginHorizontal="8dp"
+ android:textColor="@color/white"
+ android:textSize="20sp"
+ android:textStyle="bold"
+ android:text=""
+ />
+</LinearLayout>
diff --git a/android/src/main/res/layout/select_location.xml b/android/src/main/res/layout/select_location.xml
index 0835c36dc3..a372b32a9f 100644
--- a/android/src/main/res/layout/select_location.xml
+++ b/android/src/main/res/layout/select_location.xml
@@ -11,6 +11,7 @@
<ImageButton android:id="@+id/close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_weight="0"
android:layout_margin="12dp"
android:background="?android:attr/selectableItemBackground"
android:src="@drawable/icon_close"
@@ -18,6 +19,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_weight="0"
android:layout_marginVertical="4dp"
android:layout_marginHorizontal="24dp"
android:textColor="@color/white"
@@ -28,9 +30,17 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_weight="0"
android:layout_marginHorizontal="24dp"
+ android:layout_marginBottom="24dp"
android:textColor="@color/white60"
android:textSize="13sp"
android:text="@string/select_location_description"
/>
+ <android.support.v7.widget.RecyclerView android:id="@+id/relay_list"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ />
</LinearLayout>
diff --git a/android/src/main/res/values/dimensions.xml b/android/src/main/res/values/dimensions.xml
new file mode 100644
index 0000000000..379843b2bf
--- /dev/null
+++ b/android/src/main/res/values/dimensions.xml
@@ -0,0 +1,6 @@
+<resources>
+ <dimen name="country_row_padding">20dp</dimen>
+ <dimen name="city_row_padding">40dp</dimen>
+ <dimen name="relay_row_padding">60dp</dimen>
+ <dimen name="relay_list_divider">1dp</dimen>
+</resources>