summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountManagementButton.kt21
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Cell.kt131
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CellSwitch.kt235
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CopyableInformationView.kt70
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CustomItemAnimator.kt43
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CustomRecyclerView.kt61
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/InformationView.kt200
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/ToggleCell.kt46
-rw-r--r--android/app/src/main/res/layout/account.xml88
-rw-r--r--android/app/src/main/res/layout/account_buttons.xml15
-rw-r--r--android/app/src/main/res/layout/information_view.xml64
11 files changed, 0 insertions, 974 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountManagementButton.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountManagementButton.kt
deleted file mode 100644
index e9b7d170d7..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountManagementButton.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package net.mullvad.mullvadvpn.ui.widget
-
-import android.content.Context
-import android.util.AttributeSet
-import net.mullvad.mullvadvpn.R
-
-class AccountManagementButton : UrlButton {
- 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 {
- label = context.getString(R.string.manage_account)
- }
-}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Cell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Cell.kt
deleted file mode 100644
index b78c9bc14c..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Cell.kt
+++ /dev/null
@@ -1,131 +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.LinearLayout
-import android.widget.TextView
-import net.mullvad.mullvadvpn.R
-
-open class Cell : LinearLayout {
- private val label =
- TextView(context).apply {
- val rightPadding = resources.getDimensionPixelSize(R.dimen.cell_inner_spacing)
- val verticalPadding =
- resources.getDimensionPixelSize(R.dimen.cell_label_vertical_padding)
-
- layoutParams = LayoutParams(0, LayoutParams.WRAP_CONTENT, 1.0f)
- setPadding(0, verticalPadding, rightPadding, verticalPadding)
-
- setTextColor(context.getColor(R.color.white))
- setTextSize(
- TypedValue.COMPLEX_UNIT_PX,
- resources.getDimension(R.dimen.text_medium_plus)
- )
- setTypeface(null, Typeface.BOLD)
- }
-
- protected var footer: TextView? = null
- set(value) {
- field =
- value?.apply {
- val horizontalPadding =
- resources.getDimensionPixelSize(R.dimen.cell_footer_horizontal_padding)
- val topPadding =
- resources.getDimensionPixelSize(R.dimen.cell_footer_top_padding)
-
- layoutParams =
- LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
- setPadding(horizontalPadding, topPadding, horizontalPadding, 0)
-
- setTextColor(context.getColor(R.color.white60))
- setTextSize(
- TypedValue.COMPLEX_UNIT_PX,
- resources.getDimension(R.dimen.text_small)
- )
- }
- }
-
- protected var cell: LinearLayout = this
- set(value) {
- field =
- value.apply {
- val height = resources.getDimensionPixelSize(R.dimen.cell_height)
- 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
- minimumHeight = height
-
- setBackgroundResource(R.drawable.cell_button_background)
- setPadding(leftPadding, 0, rightPadding, 0)
-
- addView(label)
-
- setOnClickListener { onClickListener?.invoke() }
- }
- }
-
- var onClickListener: (() -> Unit)? = null
-
- @JvmOverloads
- constructor(
- context: Context,
- attributes: AttributeSet? = null,
- defaultStyleAttribute: Int = 0,
- defaultStyleResource: Int = 0,
- footer: TextView? = null
- ) : super(context, attributes, defaultStyleAttribute, defaultStyleResource) {
- this.footer = footer
- loadAttributes(attributes)
- }
-
- private fun loadAttributes(attributes: AttributeSet?) {
- context.theme.obtainStyledAttributes(attributes, R.styleable.TextAttribute, 0, 0).apply {
- try {
- label.text = getString(R.styleable.TextAttribute_text) ?: ""
- } finally {
- recycle()
- }
- }
-
- context.theme.obtainStyledAttributes(attributes, R.styleable.Cell, 0, 0).apply {
- try {
- getString(R.styleable.Cell_footer)?.let { footerText ->
- if (footer == null) {
- footer = TextView(context)
- }
-
- footer?.text = footerText
- }
- } finally {
- recycle()
- }
- }
-
- setUp()
- }
-
- private fun setUp() {
- if (footer != null) {
- cell =
- LinearLayout(context).apply {
- layoutParams =
- LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
- }
-
- isClickable = false
- orientation = VERTICAL
-
- addView(cell)
- addView(footer)
- } else {
- cell = this
- }
- }
-}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CellSwitch.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CellSwitch.kt
deleted file mode 100644
index 8c2312044a..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CellSwitch.kt
+++ /dev/null
@@ -1,235 +0,0 @@
-package net.mullvad.mullvadvpn.ui.widget
-
-import android.animation.ValueAnimator
-import android.content.Context
-import android.graphics.Paint.Style
-import android.graphics.drawable.ShapeDrawable
-import android.graphics.drawable.shapes.OvalShape
-import android.util.AttributeSet
-import android.view.GestureDetector
-import android.view.GestureDetector.OnGestureListener
-import android.view.Gravity
-import android.view.MotionEvent
-import android.widget.ImageView
-import android.widget.LinearLayout
-import kotlin.properties.Delegates.observable
-import net.mullvad.mullvadvpn.R
-
-class CellSwitch : LinearLayout {
- enum class State {
- ON,
- OFF
- }
-
- var state by
- observable(State.OFF) { _, oldState, newState ->
- animateToState()
-
- if (oldState != newState) {
- listener?.invoke(newState)
- }
- }
-
- var listener: ((State) -> Unit)? = null
-
- private val onColor = context.getColor(R.color.green)
- private val offColor = context.getColor(R.color.red)
-
- private val knobSize = resources.getDimensionPixelSize(R.dimen.cell_switch_knob_size)
- private val knobImage =
- ShapeDrawable(OvalShape()).apply {
- paint.apply {
- color = offColor
- style = Style.FILL
- }
-
- intrinsicWidth = knobSize
- intrinsicHeight = knobSize
- }
-
- private val knobView = ImageView(context).apply { setImageDrawable(knobImage) }
-
- private val knobAnimationDuration = 200L
- private val knobMaxTranslation =
- resources.getDimensionPixelOffset(R.dimen.cell_switch_knob_max_translation).toFloat()
-
- private val knobPosition: Float
- get() = knobView.translationX / knobMaxTranslation
-
- private var animationIsReversed = false
-
- private val positionAnimation =
- ValueAnimator.ofFloat(0f, knobMaxTranslation).apply {
- addUpdateListener { animation ->
- knobView.translationX = animation.animatedValue as Float
- }
-
- duration = knobAnimationDuration
- }
-
- private val colorAnimation =
- ValueAnimator.ofArgb(offColor, onColor).apply {
- addUpdateListener { animation ->
- knobImage.paint.color = animation.animatedValue as Int
- knobImage.invalidateSelf()
- }
-
- duration = knobAnimationDuration
- }
-
- private val gestureListener =
- object : OnGestureListener {
- private var isScrolling: Boolean = false
- private var scrollPosition: Float = 0f
-
- override fun onDown(event: MotionEvent): Boolean {
- scrollPosition = knobView.translationX
- return true
- }
-
- override fun onFling(
- downEvent: MotionEvent,
- upEvent: MotionEvent,
- velocityX: Float,
- velocityY: Float
- ): Boolean {
- if (velocityX > 0f) {
- state = State.ON
- } else if (velocityX < 0f) {
- state = State.OFF
- }
-
- return true
- }
-
- override fun onLongPress(event: MotionEvent) {}
-
- override fun onScroll(
- downEvent: MotionEvent,
- moveEvent: MotionEvent,
- distanceX: Float,
- distanceY: Float
- ): Boolean {
- isScrolling = true
- scrollPosition -= distanceX
-
- var fraction = scrollPosition / knobMaxTranslation
- val playTime = (fraction * knobAnimationDuration).toLong()
-
- colorAnimation.pause()
- positionAnimation.pause()
-
- colorAnimation.currentPlayTime = playTime
- positionAnimation.currentPlayTime = playTime
-
- return true
- }
-
- override fun onShowPress(event: MotionEvent) {}
-
- override fun onSingleTapUp(event: MotionEvent): Boolean {
- when (state) {
- State.ON -> state = State.OFF
- State.OFF -> state = State.ON
- }
-
- return true
- }
-
- fun onUp(): Boolean {
- if (!isScrolling) {
- return false
- }
-
- if (knobPosition <= 0.5f) {
- state = State.OFF
- } else {
- state = State.ON
- }
-
- isScrolling = false
- scrollPosition = 0f
-
- return true
- }
- }
-
- private val gestureDetector = GestureDetector(context, gestureListener)
-
- 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 {
- setBackground(resources.getDrawable(R.drawable.cell_switch_background, null))
- addView(
- knobView,
- LinearLayout.LayoutParams(knobSize, knobSize).apply {
- gravity = Gravity.CENTER_VERTICAL
- leftMargin = resources.getDimensionPixelSize(R.dimen.cell_switch_knob_margin)
- }
- )
- }
-
- override fun onTouchEvent(event: MotionEvent): Boolean {
- if (gestureDetector.onTouchEvent(event)) {
- return true
- } else if (event.actionMasked == MotionEvent.ACTION_UP) {
- return gestureListener.onUp()
- }
-
- return super.onTouchEvent(event)
- }
-
- fun toggle() {
- when (state) {
- State.ON -> state = State.OFF
- State.OFF -> state = State.ON
- }
- }
-
- fun forcefullySetState(newState: State) {
- when (newState) {
- State.ON -> {
- knobView.translationX = knobMaxTranslation
- knobImage.paint.color = onColor
- }
- State.OFF -> {
- knobView.translationX = 0f
- knobImage.paint.color = offColor
- }
- }
-
- state = newState
- }
-
- private fun animateToState() {
- var playTime = (knobPosition * knobAnimationDuration).toLong()
-
- when (state) {
- State.ON -> {
- animationIsReversed = false
- colorAnimation.start()
- positionAnimation.start()
- }
- State.OFF -> {
- if (!animationIsReversed || !colorAnimation.isRunning()) {
- animationIsReversed = true
- colorAnimation.reverse()
- positionAnimation.reverse()
- }
-
- playTime = knobAnimationDuration - playTime
- }
- }
-
- colorAnimation.currentPlayTime = playTime
- positionAnimation.currentPlayTime = playTime
- }
-}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CopyableInformationView.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CopyableInformationView.kt
deleted file mode 100644
index dabc1fb218..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CopyableInformationView.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-package net.mullvad.mullvadvpn.ui.widget
-
-import android.content.ClipData
-import android.content.ClipboardManager
-import android.content.Context
-import android.util.AttributeSet
-import android.view.View
-import android.widget.ImageButton
-import android.widget.Toast
-import net.mullvad.mullvadvpn.R
-
-class CopyableInformationView : InformationView {
- var clipboardLabel: String? = null
-
- var copiedToast: String? = null
-
- constructor(context: Context) : super(context) {}
-
- constructor(context: Context, attributes: AttributeSet) : super(context, attributes) {
- loadAttributes(attributes)
- }
-
- constructor(
- context: Context,
- attributes: AttributeSet,
- defaultStyleAttribute: Int
- ) : super(context, attributes, defaultStyleAttribute) {
- loadAttributes(attributes)
- }
-
- constructor(
- context: Context,
- attributes: AttributeSet,
- defaultStyleAttribute: Int,
- defaultStyleResource: Int
- ) : super(context, attributes, defaultStyleAttribute, defaultStyleResource) {
- loadAttributes(attributes)
- }
-
- init {
- findViewById<ImageButton>(R.id.copy_button).apply {
- visibility = View.VISIBLE
- setOnClickListener { copyToClipboard() }
- }
- shouldEnable = false
- }
-
- private fun loadAttributes(attributes: AttributeSet) {
- val styleableId = R.styleable.CopyableInformationView
-
- context.theme.obtainStyledAttributes(attributes, styleableId, 0, 0).apply {
- try {
- clipboardLabel = getString(R.styleable.CopyableInformationView_clipboardLabel)
- copiedToast = getString(R.styleable.CopyableInformationView_copiedToast)
- } finally {
- recycle()
- }
- }
- }
-
- private fun copyToClipboard() {
- val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
- val clipData = ClipData.newPlainText(clipboardLabel, information)
- val toastMessage = copiedToast ?: context.getString(R.string.copied_to_clipboard)
-
- clipboard.setPrimaryClip(clipData)
-
- Toast.makeText(context, toastMessage, Toast.LENGTH_SHORT).show()
- }
-}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CustomItemAnimator.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CustomItemAnimator.kt
deleted file mode 100644
index ef8caf7e7c..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CustomItemAnimator.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package net.mullvad.mullvadvpn.ui.widget
-
-import androidx.recyclerview.widget.DefaultItemAnimator
-import androidx.recyclerview.widget.RecyclerView.LayoutManager
-import androidx.recyclerview.widget.RecyclerView.ViewHolder
-import kotlin.math.round
-
-class CustomItemAnimator : DefaultItemAnimator() {
- var layoutManager: LayoutManager? = null
-
- var onMove: ((Int, Int) -> Unit)? = null
-
- override fun animateMove(
- holder: ViewHolder,
- fromX: Int,
- fromY: Int,
- toX: Int,
- toY: Int
- ): Boolean {
- if (super.animateMove(holder, fromX, fromY, toX, toY)) {
- var view = holder.itemView
-
- if (view == layoutManager?.getChildAt(0)) {
- var translationX = view.translationX
- var translationY = view.translationY
-
- view.animate().setUpdateListener { _ ->
- val deltaX = round(translationX - view.translationX)
- val deltaY = round(translationY - view.translationY)
-
- onMove?.invoke(deltaX.toInt(), deltaY.toInt())
-
- translationX -= deltaX
- translationY -= deltaY
- }
- }
-
- return true
- } else {
- return false
- }
- }
-}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CustomRecyclerView.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CustomRecyclerView.kt
deleted file mode 100644
index 902f6c6acb..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/CustomRecyclerView.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-package net.mullvad.mullvadvpn.ui.widget
-
-import android.content.Context
-import android.util.AttributeSet
-import androidx.recyclerview.widget.RecyclerView
-import net.mullvad.mullvadvpn.util.ListenableScrollableView
-
-class CustomRecyclerView : RecyclerView, ListenableScrollableView {
- private val customItemAnimator = CustomItemAnimator()
-
- override var horizontalScrollOffset = 0
- override var verticalScrollOffset = 0
-
- override var onScrollListener: ((Int, Int, Int, Int) -> Unit)? = null
-
- 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 {
- itemAnimator =
- customItemAnimator.apply {
- onMove = { horizontalDelta, verticalDelta ->
- dispatchScrollEvent(horizontalDelta, verticalDelta)
- }
- }
- }
-
- override fun setLayoutManager(layoutManager: LayoutManager?) {
- super.setLayoutManager(layoutManager)
-
- customItemAnimator.layoutManager = layoutManager
- }
-
- override fun onScrolled(horizontalDelta: Int, verticalDelta: Int) {
- super.onScrolled(horizontalDelta, verticalDelta)
-
- dispatchScrollEvent(horizontalDelta, verticalDelta)
- }
-
- private fun dispatchScrollEvent(horizontalDelta: Int, verticalDelta: Int) {
- val oldHorizontalScrollOffset = horizontalScrollOffset
- val oldVerticalScrollOffset = verticalScrollOffset
-
- horizontalScrollOffset += horizontalDelta
- verticalScrollOffset += verticalDelta
-
- onScrollListener?.invoke(
- horizontalScrollOffset,
- verticalScrollOffset,
- oldHorizontalScrollOffset,
- oldVerticalScrollOffset
- )
- }
-}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/InformationView.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/InformationView.kt
deleted file mode 100644
index b7547a8761..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/InformationView.kt
+++ /dev/null
@@ -1,200 +0,0 @@
-package net.mullvad.mullvadvpn.ui.widget
-
-import android.content.Context
-import android.text.method.TransformationMethod
-import android.util.AttributeSet
-import android.util.TypedValue
-import android.view.LayoutInflater
-import android.view.View
-import android.widget.LinearLayout
-import android.widget.TextView
-import androidx.appcompat.content.res.AppCompatResources
-import kotlin.properties.Delegates.observable
-import net.mullvad.mullvadvpn.R
-
-open class InformationView : LinearLayout {
- enum class WhenMissing {
- Nothing,
- Hide,
- ShowSpinner;
-
- companion object {
- internal fun fromCode(code: Int): WhenMissing {
- when (code) {
- 0 -> return Nothing
- 1 -> return Hide
- 2 -> return ShowSpinner
- else -> throw Exception("Invalid whenMissing attribute value")
- }
- }
- }
- }
-
- private val container: View =
- context.getSystemService(Context.LAYOUT_INFLATER_SERVICE).let { service ->
- val inflater = service as LayoutInflater
-
- inflater.inflate(R.layout.information_view, this).apply {
- setOnClickListener { onClick?.invoke() }
- setEnabled(false)
- }
- }
-
- private val description: TextView = findViewById(R.id.description)
- private val informationDisplay: TextView = findViewById(R.id.information_display)
- private val spinner: View = findViewById(R.id.spinner)
- private val toggleMaskingButton: View = findViewById(R.id.toggle_masking_button)
-
- var error by observable<String?>(null) { _, _, _ -> updateStatus() }
- var information by observable<String?>(null) { _, _, _ -> updateStatus() }
-
- var errorColor by observable(context.getColor(R.color.red)) { _, _, _ -> updateStatus() }
- var informationColor by
- observable(context.getColor(R.color.white)) { _, _, _ -> updateStatus() }
-
- var maxLength by observable(0) { _, _, _ -> updateStatus() }
- var whenMissing by observable(WhenMissing.Nothing) { _, _, _ -> updateStatus() }
-
- var shouldEnable by observable(false) { _, _, _ -> updateEnabled() }
-
- var onClick by
- observable<(() -> Unit)?>(null) { _, _, callback ->
- container.setFocusable(callback != null)
- }
-
- sealed class Masking {
- object None : Masking()
- data class Hide(val transformationMethod: TransformationMethod) : Masking()
- data class Show(val transformationMethod: TransformationMethod) : Masking()
- }
-
- var informationState by
- observable<Masking>(Masking.None) { _, _, newState ->
- when (newState) {
- is Masking.Hide -> {
- informationDisplay.transformationMethod = newState.transformationMethod
-
- toggleMaskingButton.apply {
- visibility = VISIBLE
- contentDescription = context.getString(R.string.show_account_number)
- background = AppCompatResources.getDrawable(context, R.drawable.icon_show)
- }
- }
- is Masking.Show -> {
- informationDisplay.transformationMethod = newState.transformationMethod
-
- toggleMaskingButton.apply {
- visibility = VISIBLE
- contentDescription = context.getString(R.string.hide_account_number)
- background = AppCompatResources.getDrawable(context, R.drawable.icon_hide)
- }
- }
- is Masking.None -> {
- informationDisplay.transformationMethod = null
- toggleMaskingButton.visibility = INVISIBLE
- }
- }
-
- updateStatus()
- }
-
- var onToggleMaskingClicked by
- observable<(() -> Unit)?>(null) { _, _, callback ->
- toggleMaskingButton.setOnClickListener { callback?.invoke() }
- }
-
- constructor(context: Context) : super(context) {}
-
- constructor(context: Context, attributes: AttributeSet) : super(context, attributes) {
- loadAttributes(attributes)
- }
-
- constructor(
- context: Context,
- attributes: AttributeSet,
- defaultStyleAttribute: Int
- ) : super(context, attributes, defaultStyleAttribute) {
- loadAttributes(attributes)
- }
-
- constructor(
- context: Context,
- attributes: AttributeSet,
- defaultStyleAttribute: Int,
- defaultStyleResource: Int
- ) : super(context, attributes, defaultStyleAttribute, defaultStyleResource) {
- loadAttributes(attributes)
- }
-
- init {
- val backgroundResource = TypedValue()
-
- context.theme.resolveAttribute(
- android.R.attr.selectableItemBackground,
- backgroundResource,
- true
- )
-
- orientation = VERTICAL
- setBackgroundResource(backgroundResource.resourceId)
- }
-
- private fun loadAttributes(attributes: AttributeSet) {
- val styleableId = R.styleable.InformationView
-
- context.theme.obtainStyledAttributes(attributes, styleableId, 0, 0).apply {
- try {
- description.text = getString(R.styleable.InformationView_description) ?: ""
-
- errorColor = getInteger(R.styleable.InformationView_errorColor, errorColor)
- maxLength = getInteger(R.styleable.InformationView_maxLength, 0)
-
- informationColor =
- getInteger(R.styleable.InformationView_informationColor, informationColor)
-
- whenMissing =
- WhenMissing.fromCode(getInteger(R.styleable.InformationView_whenMissing, 0))
- } finally {
- recycle()
- }
- }
- }
-
- private fun updateStatus() {
- val information = this.information
- val hasText = information != null || error != null
-
- if (error != null) {
- informationDisplay.setTextColor(errorColor)
- informationDisplay.text = error
- } else if (information != null) {
- informationDisplay.setTextColor(informationColor)
-
- if (maxLength == 0 || information.length <= maxLength) {
- informationDisplay.text = information
- } else {
- informationDisplay.text = information.substring(0, maxLength) + "..."
- }
- }
-
- if (whenMissing == WhenMissing.Hide && !hasText) {
- visibility = INVISIBLE
- } else {
- visibility = VISIBLE
- }
-
- if (whenMissing == WhenMissing.ShowSpinner && !hasText) {
- spinner.visibility = VISIBLE
- informationDisplay.visibility = INVISIBLE
- } else {
- spinner.visibility = INVISIBLE
- informationDisplay.visibility = VISIBLE
- }
-
- updateEnabled()
- }
-
- private fun updateEnabled() {
- setEnabled(shouldEnable && error == null && information != null)
- }
-}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/ToggleCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/ToggleCell.kt
deleted file mode 100644
index f47347539f..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/ToggleCell.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-package net.mullvad.mullvadvpn.ui.widget
-
-import android.content.Context
-import android.util.AttributeSet
-
-class ToggleCell : Cell {
- private val toggle =
- CellSwitch(context).apply {
- layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0.0f)
- }
-
- var state
- get() = toggle.state
- set(value) {
- toggle.state = value
- }
-
- var listener
- get() = toggle.listener
- set(value) {
- toggle.listener = value
- }
-
- 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 {
- onClickListener = { toggle() }
- cell.addView(toggle)
- }
-
- fun toggle() {
- toggle.toggle()
- }
-
- fun forcefullySetState(state: CellSwitch.State) {
- toggle.forcefullySetState(state)
- }
-}
diff --git a/android/app/src/main/res/layout/account.xml b/android/app/src/main/res/layout/account.xml
deleted file mode 100644
index 8d896b2223..0000000000
--- a/android/app/src/main/res/layout/account.xml
+++ /dev/null
@@ -1,88 +0,0 @@
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:mullvad="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/darkBlue"
- android:gravity="start">
- <TextView android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/settings_account"
- style="@style/SettingsCollapsedHeader" />
- <LinearLayout android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <FrameLayout android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <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"
- android:layout_marginHorizontal="4dp"
- android:layout_gravity="center"
- android:text="@string/settings_account"
- style="@style/SettingsCollapsedHeader" />
- </FrameLayout>
- <net.mullvad.mullvadvpn.ui.widget.ListenableScrollView android:id="@+id/scroll_area"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fillViewport="true">
- <LinearLayout android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginTop="2dp"
- android:orientation="vertical">
- <TextView android:id="@+id/expanded_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/half_vertical_space"
- android:layout_marginHorizontal="@dimen/side_margin"
- android:lines="1"
- android:text="@string/settings_account"
- style="@style/SettingsExpandedHeader" />
- <net.mullvad.mullvadvpn.ui.widget.InformationView android:id="@+id/device_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingHorizontal="@dimen/side_margin"
- android:paddingVertical="@dimen/half_vertical_space"
- mullvad:description="@string/device_name"
- mullvad:whenMissing="showSpinner" />
- <net.mullvad.mullvadvpn.ui.widget.CopyableInformationView android:id="@+id/account_number"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingHorizontal="@dimen/side_margin"
- android:paddingVertical="@dimen/half_vertical_space"
- mullvad:clipboardLabel="@string/mullvad_account_number"
- mullvad:copiedToast="@string/copied_mullvad_account_number"
- mullvad:description="@string/account_number"
- mullvad:whenMissing="showSpinner"
- android:descendantFocusability="afterDescendants" />
- <net.mullvad.mullvadvpn.ui.widget.InformationView android:id="@+id/account_expiry"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/half_vertical_space"
- android:paddingHorizontal="@dimen/side_margin"
- android:paddingVertical="@dimen/half_vertical_space"
- mullvad:description="@string/paid_until"
- mullvad:whenMissing="showSpinner" />
- <Space android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1" />
- <include layout="@layout/account_buttons" />
- <net.mullvad.mullvadvpn.ui.widget.Button android:id="@+id/logout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/side_margin"
- android:layout_marginTop="@dimen/button_separation"
- android:layout_marginBottom="@dimen/screen_vertical_margin"
- mullvad:text="@string/log_out"
- mullvad:buttonColor="red" />
- </LinearLayout>
- </net.mullvad.mullvadvpn.ui.widget.ListenableScrollView>
- </LinearLayout>
-</FrameLayout>
diff --git a/android/app/src/main/res/layout/account_buttons.xml b/android/app/src/main/res/layout/account_buttons.xml
deleted file mode 100644
index 13d7883995..0000000000
--- a/android/app/src/main/res/layout/account_buttons.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<merge xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:mullvad="http://schemas.android.com/apk/res-auto">
- <net.mullvad.mullvadvpn.ui.widget.AccountManagementButton android:id="@+id/account_management"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/side_margin"
- mullvad:buttonColor="green" />
- <net.mullvad.mullvadvpn.ui.widget.RedeemVoucherButton android:id="@+id/redeem_voucher"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/button_separation"
- android:layout_marginHorizontal="@dimen/side_margin"
- mullvad:buttonColor="green"
- mullvad:text="@string/redeem_voucher" />
-</merge>
diff --git a/android/app/src/main/res/layout/information_view.xml b/android/app/src/main/res/layout/information_view.xml
deleted file mode 100644
index eb94d7542b..0000000000
--- a/android/app/src/main/res/layout/information_view.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <TextView android:id="@+id/description"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=""
- android:textColor="@color/white60"
- android:textSize="@dimen/text_small"
- android:textStyle="bold"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintStart_toStartOf="parent" />
- <TextView android:id="@+id/information_display"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:text=""
- android:textColor="@color/white"
- android:textStyle="bold"
- android:maxLines="1"
- android:autoSizeTextType="uniform"
- android:autoSizeMinTextSize="8dp"
- android:layout_marginTop="9dp"
- android:layout_marginEnd="@dimen/information_action_margin"
- app:layout_constraintTop_toBottomOf="@id/description"
- app:layout_constraintStart_toStartOf="parent" />
- <ProgressBar android:id="@+id/spinner"
- android:layout_width="@dimen/information_icon_size"
- android:layout_height="@dimen/information_icon_size"
- android:indeterminate="true"
- android:indeterminateDrawable="@drawable/icon_spinner"
- android:indeterminateDuration="600"
- android:indeterminateOnly="true"
- android:visibility="visible"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/description"
- app:layout_constraintBottom_toBottomOf="parent"
- android:layout_alignEnd="@id/copy_button" />
- <ImageButton android:id="@+id/toggle_masking_button"
- android:layout_width="@dimen/information_icon_size"
- android:layout_height="@dimen/information_icon_size"
- android:background="@drawable/icon_show"
- android:visibility="invisible"
- android:focusable="true"
- android:contentDescription="@string/show_account_number"
- android:layout_marginEnd="@dimen/information_action_margin"
- app:layout_constraintTop_toTopOf="@id/information_display"
- app:layout_constraintBottom_toBottomOf="@id/information_display"
- app:layout_constraintEnd_toStartOf="@id/copy_button" />
- <ImageButton android:id="@+id/copy_button"
- android:layout_width="@dimen/information_icon_size"
- android:layout_height="@dimen/information_icon_size"
- android:background="@drawable/icon_copy"
- android:visibility="invisible"
- android:clickable="true"
- android:focusable="true"
- android:contentDescription="@string/copy_account_number"
- app:layout_constraintTop_toTopOf="@id/information_display"
- app:layout_constraintBottom_toBottomOf="@id/information_display"
- app:layout_constraintEnd_toEndOf="parent" />
- </androidx.constraintlayout.widget.ConstraintLayout>
-</merge>