summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
authorDavid Göransson <david.goransson90@gmail.com>2023-09-27 14:01:11 +0200
committerDavid Göransson <david.goransson90@gmail.com>2023-10-04 09:19:41 +0200
commitc6141f82e5d49ff8220b927deb322b4af8fd6608 (patch)
tree703bc4cbf2bfa0f9e780387af401d08a4cebbc6d /android
parente3ed0ac859542dfe048b4434c84b2b356ea560d4 (diff)
downloadmullvadvpn-c6141f82e5d49ff8220b927deb322b4af8fd6608.tar.xz
mullvadvpn-c6141f82e5d49ff8220b927deb322b4af8fd6608.zip
Align behaviour with design
Diffstat (limited to 'android')
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ReportProblemNoEmailDialog.kt50
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ReportProblemStateDialog.kt130
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ReportProblemScreen.kt5
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ViewLogsScreen.kt5
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/MinLoadingConstant.kt3
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/TimingConstant.kt4
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/CollapsibleTitleController.kt219
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/ListItemDividerDecoration.kt16
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/ProblemReportFragment.kt4
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/EditTextExt.kt15
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModel.kt6
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ViewLogsViewModel.kt3
-rw-r--r--android/app/src/main/res/layout/confirm_no_email.xml31
-rw-r--r--android/app/src/main/res/layout/problem_report.xml163
-rw-r--r--android/app/src/main/res/layout/view_logs.xml38
-rw-r--r--android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt3
16 files changed, 113 insertions, 582 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ReportProblemNoEmailDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ReportProblemNoEmailDialog.kt
index ff9b658211..cdfb5989e1 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ReportProblemNoEmailDialog.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ReportProblemNoEmailDialog.kt
@@ -3,32 +3,31 @@ package net.mullvad.mullvadvpn.compose.dialog
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.size
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.colorResource
-import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.button.ActionButton
+import net.mullvad.mullvadvpn.lib.theme.AppTheme
+import net.mullvad.mullvadvpn.lib.theme.Dimens
@Preview
@Composable
private fun PreviewReportProblemNoEmailDialog() {
- ReportProblemNoEmailDialog(
- onDismiss = {},
- onConfirm = {},
- )
+ AppTheme {
+ ReportProblemNoEmailDialog(
+ onDismiss = {},
+ onConfirm = {},
+ )
+ }
}
@Composable
@@ -42,17 +41,16 @@ fun ReportProblemNoEmailDialog(onDismiss: () -> Unit, onConfirm: () -> Unit) {
) {
Image(
painter = painterResource(id = R.drawable.icon_alert),
- contentDescription = "Remove",
- modifier = Modifier.width(50.dp).height(50.dp)
+ contentDescription = null,
+ modifier = Modifier.size(Dimens.dialogIconSize)
)
}
},
text = {
Text(
text = stringResource(id = R.string.confirm_no_email),
- color = colorResource(id = R.color.white),
- fontSize = dimensionResource(id = R.dimen.text_small).value.sp,
- modifier = Modifier.fillMaxWidth()
+ modifier = Modifier.fillMaxWidth(),
+ style = MaterialTheme.typography.bodySmall
)
},
dismissButton = {
@@ -60,27 +58,25 @@ fun ReportProblemNoEmailDialog(onDismiss: () -> Unit, onConfirm: () -> Unit) {
modifier = Modifier.fillMaxWidth(),
colors =
ButtonDefaults.buttonColors(
- containerColor = colorResource(id = R.color.red),
- contentColor = Color.White
+ containerColor = MaterialTheme.colorScheme.error,
+ contentColor = MaterialTheme.colorScheme.onError,
),
onClick = onConfirm,
- ) {
- Text(text = stringResource(id = R.string.send_anyway), fontSize = 18.sp)
- }
+ text = stringResource(id = R.string.send_anyway)
+ )
},
confirmButton = {
ActionButton(
modifier = Modifier.fillMaxWidth(),
colors =
ButtonDefaults.buttonColors(
- containerColor = colorResource(id = R.color.blue),
- contentColor = Color.White
+ containerColor = MaterialTheme.colorScheme.primary,
+ contentColor = MaterialTheme.colorScheme.onPrimary,
),
onClick = { onDismiss() },
- ) {
- Text(text = stringResource(id = R.string.back), fontSize = 18.sp)
- }
+ text = stringResource(id = R.string.back)
+ )
},
- containerColor = colorResource(id = R.color.darkBlue)
+ containerColor = MaterialTheme.colorScheme.background
)
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ReportProblemStateDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ReportProblemStateDialog.kt
index 6a63423399..a7b9182aea 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ReportProblemStateDialog.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ReportProblemStateDialog.kt
@@ -3,34 +3,31 @@ package net.mullvad.mullvadvpn.compose.dialog
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.width
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.colorResource
-import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
-import androidx.compose.ui.text.font.FontStyle
-import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.DialogProperties
+import androidx.compose.ui.window.SecureFlagPolicy
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.button.ActionButton
+import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.lib.theme.Dimens
import net.mullvad.mullvadvpn.viewmodel.SendingReportUiState
@@ -59,7 +56,7 @@ fun ShowReportProblemStateDialog(
@Preview
@Composable
private fun PreviewReportProblemSendingDialog() {
- ReportProblemSendingDialog()
+ AppTheme { ReportProblemSendingDialog() }
}
@Composable
@@ -80,10 +77,7 @@ private fun ReportProblemSendingDialog() {
) {
Text(
text = stringResource(id = R.string.sending),
- color = colorResource(id = R.color.white),
- fontSize = dimensionResource(id = R.dimen.text_small).value.sp,
- fontStyle = FontStyle.Normal,
- textAlign = TextAlign.Start,
+ style = MaterialTheme.typography.bodySmall,
modifier = Modifier.fillMaxWidth()
)
}
@@ -94,17 +88,19 @@ private fun ReportProblemSendingDialog() {
dismissOnClickOutside = false,
dismissOnBackPress = false,
),
- containerColor = colorResource(id = R.color.darkBlue)
+ containerColor = MaterialTheme.colorScheme.background
)
}
@Preview
@Composable
private fun PreviewReportProblemSuccessDialog() {
- ReportProblemSuccessDialog(
- "Email@em.com",
- onConfirm = {},
- )
+ AppTheme {
+ ReportProblemSuccessDialog(
+ "Email@em.com",
+ onConfirm = {},
+ )
+ }
}
@Composable
@@ -118,52 +114,75 @@ fun ReportProblemSuccessDialog(email: String?, onConfirm: () -> Unit) {
) {
Image(
painter = painterResource(id = R.drawable.icon_success),
- contentDescription = "Remove",
- modifier = Modifier.width(50.dp).height(50.dp)
+ contentDescription = null,
+ modifier = Modifier.size(Dimens.dialogIconSize)
)
}
},
text = {
- Text(
- text =
- buildAnnotatedString {
- withStyle(SpanStyle(color = colorResource(id = R.color.green))) {
- append(stringResource(id = R.string.sent_thanks))
- }
- append(" ")
+ Column {
+ Text(
+ text =
+ buildAnnotatedString {
+ withStyle(SpanStyle(color = MaterialTheme.colorScheme.surface)) {
+ append(stringResource(id = R.string.sent_thanks))
+ }
+ append(" ")
+ withStyle(SpanStyle(color = MaterialTheme.colorScheme.onPrimary)) {
+ append(stringResource(id = R.string.we_will_look_into_this))
+ }
+ },
+ style = MaterialTheme.typography.bodySmall,
+ modifier = Modifier.fillMaxWidth()
+ )
+
+ Spacer(modifier = Modifier.height(Dimens.smallPadding))
+ email?.let {
+ val emailTemplate = stringResource(R.string.sent_contact)
+ val annotatedEmailString =
+ remember(it) {
+ val emailStart = emailTemplate.indexOf('%')
- withStyle(SpanStyle(color = colorResource(id = R.color.white))) {
- append(stringResource(id = R.string.we_will_look_into_this))
+ buildAnnotatedString {
+ append(emailTemplate.substring(0, emailStart))
+ withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { append(email) }
+ }
}
- },
- fontSize = dimensionResource(id = R.dimen.text_small).value.sp,
- modifier = Modifier.fillMaxWidth()
- )
+
+ Text(
+ text = annotatedEmailString,
+ style = MaterialTheme.typography.bodySmall,
+ modifier = Modifier.fillMaxWidth()
+ )
+ }
+ }
},
confirmButton = {
ActionButton(
modifier = Modifier.fillMaxWidth(),
colors =
ButtonDefaults.buttonColors(
- containerColor = colorResource(id = R.color.blue),
- contentColor = Color.White
+ containerColor = MaterialTheme.colorScheme.primary,
+ contentColor = MaterialTheme.colorScheme.onPrimary,
),
onClick = { onConfirm() },
- ) {
- Text(text = stringResource(id = R.string.dismiss), fontSize = 18.sp)
- }
+ text = stringResource(id = R.string.dismiss)
+ )
},
- containerColor = colorResource(id = R.color.darkBlue)
+ containerColor = MaterialTheme.colorScheme.background,
+ properties = DialogProperties(securePolicy = if (email != null) SecureFlagPolicy.SecureOn else SecureFlagPolicy.Inherit)
)
}
@Preview
@Composable
private fun PreviewReportProblemErrorDialog() {
- ReportProblemErrorDialog(
- onDismiss = {},
- retry = {},
- )
+ AppTheme {
+ ReportProblemErrorDialog(
+ onDismiss = {},
+ retry = {},
+ )
+ }
}
@Composable
@@ -178,15 +197,14 @@ fun ReportProblemErrorDialog(onDismiss: () -> Unit, retry: () -> Unit) {
Image(
painter = painterResource(id = R.drawable.icon_fail),
contentDescription = null,
- modifier = Modifier.width(50.dp).height(50.dp)
+ modifier = Modifier.size(Dimens.dialogIconSize)
)
}
},
text = {
Text(
text = stringResource(id = R.string.failed_to_send_details),
- color = colorResource(id = R.color.white),
- fontSize = dimensionResource(id = R.dimen.text_small).value.sp,
+ style = MaterialTheme.typography.bodySmall,
modifier = Modifier.fillMaxWidth()
)
},
@@ -195,27 +213,25 @@ fun ReportProblemErrorDialog(onDismiss: () -> Unit, retry: () -> Unit) {
modifier = Modifier.fillMaxWidth(),
colors =
ButtonDefaults.buttonColors(
- containerColor = colorResource(id = R.color.blue),
- contentColor = Color.White
+ containerColor = MaterialTheme.colorScheme.primary,
+ contentColor = MaterialTheme.colorScheme.onPrimary,
),
onClick = onDismiss,
- ) {
- Text(text = stringResource(id = R.string.edit_message), fontSize = 18.sp)
- }
+ text = stringResource(id = R.string.edit_message)
+ )
},
confirmButton = {
ActionButton(
modifier = Modifier.fillMaxWidth(),
colors =
ButtonDefaults.buttonColors(
- containerColor = colorResource(id = R.color.green),
- contentColor = Color.White
+ containerColor = MaterialTheme.colorScheme.surface,
+ contentColor = MaterialTheme.colorScheme.onPrimary,
),
onClick = retry,
- ) {
- Text(text = stringResource(id = R.string.try_again), fontSize = 18.sp)
- }
+ text = stringResource(id = R.string.try_again)
+ )
},
- containerColor = colorResource(id = R.color.darkBlue)
+ containerColor = MaterialTheme.colorScheme.background
)
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ReportProblemScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ReportProblemScreen.kt
index 6f030f37fe..1a06c3ae77 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ReportProblemScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ReportProblemScreen.kt
@@ -139,8 +139,9 @@ fun ReportProblemScreen(
Column(
modifier =
Modifier.padding(
- horizontal = Dimens.sideMargin,
- vertical = Dimens.screenVerticalMargin
+ start = Dimens.sideMargin,
+ end = Dimens.sideMargin,
+ bottom = Dimens.verticalSpace,
),
verticalArrangement = Arrangement.spacedBy(Dimens.mediumPadding)
) {
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ViewLogsScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ViewLogsScreen.kt
index 80bb49f1af..53c3f9ff0c 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ViewLogsScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ViewLogsScreen.kt
@@ -72,8 +72,9 @@ fun ViewLogsScreen(
modifier =
Modifier.fillMaxSize()
.padding(
- vertical = Dimens.sideMargin,
- horizontal = Dimens.screenVerticalMargin
+ start = Dimens.sideMargin,
+ end = Dimens.sideMargin,
+ bottom = Dimens.screenVerticalMargin
),
) {
if (uiState.isLoading) {
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/MinLoadingConstant.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/MinLoadingConstant.kt
deleted file mode 100644
index a93422d3f6..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/MinLoadingConstant.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package net.mullvad.mullvadvpn.constant
-
-const val MINIMUM_LOADING_SPINNER_TIME_MILLIS = 500L
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/TimingConstant.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/TimingConstant.kt
new file mode 100644
index 0000000000..cace9b2b79
--- /dev/null
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/TimingConstant.kt
@@ -0,0 +1,4 @@
+package net.mullvad.mullvadvpn.constant
+
+const val MINIMUM_LOADING_TIME_MILLIS = 500L
+const val NAVIGATION_DELAY_MILLIS = 500L
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/CollapsibleTitleController.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/CollapsibleTitleController.kt
deleted file mode 100644
index 1c37945602..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/CollapsibleTitleController.kt
+++ /dev/null
@@ -1,219 +0,0 @@
-package net.mullvad.mullvadvpn.ui
-
-import android.view.View
-import android.view.View.OnLayoutChangeListener
-import android.view.ViewGroup.MarginLayoutParams
-import kotlin.properties.Delegates.observable
-import net.mullvad.mullvadvpn.R
-import net.mullvad.mullvadvpn.util.LinearInterpolation
-import net.mullvad.mullvadvpn.util.ListenableScrollableView
-
-// In order to use this view controller, the parent view must contain four views with specific IDs:
-//
-// 1. A scroll area `View` with the `scrollAreaId` that implements `ListenableScrollableView`, which
-// is used to animate the title based on the scroll offset.
-// 2. A view inside the scroll area with the ID `expanded_title`. This view is made invisible so
-// that it's not drawn, but it is used to measure the layout and the animation positions.
-// 3. A view outside the scroll area with the ID `collapsed_title`. This view is also made
-// invisible just like the `expanded_view`.
-// 4. A view with the ID `title`. This is the view that's actually drawn, and it's position and size
-// are interpolated from the expanded title to the collapsed title. This view should be placed
-// somewhere where it is drawn over all other views.
-//
-// The animation interpolation is calculated based on the Y scroll offset of the scroll area. Once
-// the offset reaches a value that completely hides the expanded title inside the scroll view, the
-// animation finishes with the title being in the collapsed state.
-class CollapsibleTitleController(val parentView: View, scrollAreaId: Int = R.id.scroll_area) {
- private inner class LayoutListener(val listener: (View) -> Unit) : OnLayoutChangeListener {
- override fun onLayoutChange(
- view: View,
- left: Int,
- top: Int,
- right: Int,
- bottom: Int,
- oldLeft: Int,
- oldTop: Int,
- oldRight: Int,
- oldBottom: Int
- ) {
- listener.invoke(view)
- update()
- }
- }
-
- private val scaleInterpolation = LinearInterpolation()
- private val scrollInterpolation = LinearInterpolation()
- private val xOffsetInterpolation = LinearInterpolation()
- private val yOffsetInterpolation = LinearInterpolation()
-
- private val collapsedTitleLayoutListener: LayoutListener = LayoutListener { collapsedTitle ->
- val (x, y) = calculateViewCoordinates(collapsedTitle)
-
- collapsedTitleHeight = collapsedTitle.height.toFloat()
-
- scaleInterpolation.end = collapsedTitleHeight / maxOf(1.0f, titleHeight)
- xOffsetInterpolation.end = x
- yOffsetInterpolation.end = y
- }
-
- private val collapsedTitleView =
- parentView.findViewById<View>(R.id.collapsed_title).apply {
- addOnLayoutChangeListener(collapsedTitleLayoutListener)
- visibility = View.INVISIBLE
- }
-
- private val expandedTitleLayoutListener: LayoutListener = LayoutListener { expandedTitle ->
- val (x, y) = calculateViewCoordinates(expandedTitle)
-
- val expandedTitleMarginTop =
- when (val layoutParams = expandedTitle.layoutParams) {
- is MarginLayoutParams -> layoutParams.topMargin
- else -> 0
- }
-
- expandedTitleHeight = expandedTitle.height.toFloat()
-
- scaleInterpolation.start = expandedTitleHeight / maxOf(1.0f, titleHeight)
- xOffsetInterpolation.start = x
- yOffsetInterpolation.start = y
-
- scrollInterpolation.end = expandedTitleHeight + expandedTitleMarginTop
- }
-
- private val titleLayoutListener: LayoutListener = LayoutListener { title ->
- val (x, y) = calculateViewCoordinates(title)
-
- titleWidth = title.width.toFloat()
- titleHeight = title.height.toFloat()
-
- scaleInterpolation.start = expandedTitleHeight / maxOf(1.0f, titleHeight)
- scaleInterpolation.end = collapsedTitleHeight / maxOf(1.0f, titleHeight)
- xOffsetInterpolation.reference = x
- yOffsetInterpolation.reference = y
- }
-
- private val titleView =
- parentView.findViewById<View>(R.id.title).apply {
- addOnLayoutChangeListener(titleLayoutListener)
-
- // Setting the scale pivot point to the left corner simplifies the calculations
- pivotX = 0.0f
- pivotY = 0.0f
- }
-
- private val scrollAreaLayoutListener: LayoutListener = LayoutListener {
- scrollOffset = scrollArea.verticalScrollOffset.toFloat()
- }
-
- private val scrollArea =
- parentView.findViewById<View>(scrollAreaId).let { view ->
- val scrollableView = view as ListenableScrollableView
-
- view.addOnLayoutChangeListener(scrollAreaLayoutListener)
-
- scrollableView.onScrollListener = { _, top, _, _ ->
- scrollOffset = top.toFloat()
- update()
- }
-
- scrollableView
- }
-
- private var scrollOffsetUpdated = false
- get() {
- if (field == true) {
- field = false
- return true
- } else {
- return false
- }
- }
-
- private var collapsedTitleHeight = 0.0f
- private var expandedTitleHeight = 0.0f
- private var titleWidth = 0.0f
- private var titleHeight = 0.0f
-
- private var scrollOffset: Float by
- observable(0.0f) { _, old, new ->
- if (scrollOffsetUpdated == false && old != new) {
- scrollOffsetUpdated = true
- }
- }
-
- val fullCollapseScrollOffset: Float
- get() = scrollInterpolation.end
-
- var expandedTitleView by
- observable<View?>(null) { _, oldView, newView ->
- oldView?.removeOnLayoutChangeListener(expandedTitleLayoutListener)
- newView?.apply {
- addOnLayoutChangeListener(expandedTitleLayoutListener)
- expandedTitleLayoutListener.listener(this)
- visibility = View.INVISIBLE
- }
- }
-
- init {
- expandedTitleView = parentView.findViewById<View>(R.id.expanded_title)
- update()
- }
-
- fun onDestroy() {
- scrollArea.onScrollListener = null
- (scrollArea as View).removeOnLayoutChangeListener(scrollAreaLayoutListener)
-
- collapsedTitleView.removeOnLayoutChangeListener(collapsedTitleLayoutListener)
- expandedTitleView?.removeOnLayoutChangeListener(expandedTitleLayoutListener)
- titleView.removeOnLayoutChangeListener(titleLayoutListener)
- }
-
- private fun update() {
- val shouldUpdate =
- scrollOffsetUpdated ||
- scaleInterpolation.updated ||
- xOffsetInterpolation.updated ||
- yOffsetInterpolation.updated
-
- if (shouldUpdate) {
- val progress =
- if (expandedTitleView != null) {
- maxOf(0.0f, minOf(1.0f, scrollInterpolation.progress(scrollOffset)))
- } else {
- 1.0f
- }
-
- val scale = scaleInterpolation.interpolate(progress)
- val offsetX = xOffsetInterpolation.interpolate(progress)
- val offsetY = yOffsetInterpolation.interpolate(progress)
-
- titleView.apply {
- scaleX = scale
- scaleY = scale
- translationX = offsetX
- translationY = offsetY
- }
- }
- }
-
- private fun calculateViewCoordinates(view: View): Pair<Float, Float> {
- var currentView = view
- var x = 0.0f
- var y = 0.0f
-
- while (currentView != parentView) {
- val parent = currentView.parent
-
- x += currentView.x - currentView.translationX
- y += currentView.y - currentView.translationY
-
- if (parent is View) {
- currentView = parent
- } else {
- break
- }
- }
-
- return Pair(x, y)
- }
-}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/ListItemDividerDecoration.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/ListItemDividerDecoration.kt
deleted file mode 100644
index 4fcde0e314..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/ListItemDividerDecoration.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package net.mullvad.mullvadvpn.ui
-
-import android.graphics.Rect
-import android.view.View
-import androidx.recyclerview.widget.RecyclerView
-import androidx.recyclerview.widget.RecyclerView.ItemDecoration
-import androidx.recyclerview.widget.RecyclerView.State
-
-class ListItemDividerDecoration(private val bottomOffset: Int = 0, private val topOffset: Int = 0) :
- ItemDecoration() {
-
- override fun getItemOffsets(offsets: Rect, view: View, parent: RecyclerView, state: State) {
- offsets.bottom = bottomOffset
- offsets.top = topOffset
- }
-}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/ProblemReportFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/ProblemReportFragment.kt
index aba7bd860a..397039719c 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/ProblemReportFragment.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/ProblemReportFragment.kt
@@ -12,10 +12,6 @@ import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.viewmodel.ReportProblemViewModel
import org.koin.androidx.viewmodel.ext.android.viewModel
-// TODO
-// [ ] - Showing enable email secure screen?
-// [ ] - Decide to save logs?
-
class ProblemReportFragment : BaseFragment() {
private val vm by viewModel<ReportProblemViewModel>()
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/EditTextExt.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/EditTextExt.kt
deleted file mode 100644
index b90201edfe..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/EditTextExt.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package net.mullvad.mullvadvpn.util
-
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-
-fun EditText.setOnEnterOrDoneAction(callback: () -> Unit) {
- setOnEditorActionListener { _, action, event ->
- if (action == EditorInfo.IME_ACTION_DONE || event?.keyCode == KeyEvent.KEYCODE_ENTER) {
- callback()
- }
-
- false
- }
-}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModel.kt
index 5b69ec9317..a7daf9e8d9 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModel.kt
@@ -8,7 +8,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
-import net.mullvad.mullvadvpn.constant.MINIMUM_LOADING_SPINNER_TIME_MILLIS
+import net.mullvad.mullvadvpn.constant.MINIMUM_LOADING_TIME_MILLIS
import net.mullvad.mullvadvpn.dataproxy.MullvadProblemReport
import net.mullvad.mullvadvpn.dataproxy.SendProblemReportResult
import net.mullvad.mullvadvpn.dataproxy.UserReport
@@ -46,11 +46,11 @@ class ReportProblemViewModel(private val mullvadProblemReporter: MullvadProblemR
it.copy(sendingState = SendingReportUiState.Sending, showConfirmNoEmail = false)
}
- // Ensure we show loading for at least 500 ms
+ // Ensure we show loading for at least MINIMUM_LOADING_TIME_MILLIS
val deferredResult = async {
mullvadProblemReporter.sendReport(UserReport(nullableEmail, description))
}
- delay(MINIMUM_LOADING_SPINNER_TIME_MILLIS)
+ delay(MINIMUM_LOADING_TIME_MILLIS)
_uiState.update {
it.copy(sendingState = deferredResult.await().toUiResult(nullableEmail))
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ViewLogsViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ViewLogsViewModel.kt
index 8ceae43289..7b07adc874 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ViewLogsViewModel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ViewLogsViewModel.kt
@@ -7,6 +7,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
+import net.mullvad.mullvadvpn.constant.NAVIGATION_DELAY_MILLIS
import net.mullvad.mullvadvpn.dataproxy.MullvadProblemReport
data class ViewLogsUiState(val allLines: String = "", val isLoading: Boolean = true)
@@ -22,7 +23,7 @@ class ViewLogsViewModel(private val mullvadProblemReporter: MullvadProblemReport
// fragment transitions is done. I'd very much prefer to use LazyColumn in the view
// which would make the loading way faster but then the SelectionContainer is broken and
// text would not be copyable.
- delay(500)
+ delay(NAVIGATION_DELAY_MILLIS)
_uiState.update {
it.copy(
allLines = mullvadProblemReporter.readLogs().joinToString("\n"),
diff --git a/android/app/src/main/res/layout/confirm_no_email.xml b/android/app/src/main/res/layout/confirm_no_email.xml
deleted file mode 100644
index bd6be5f4a4..0000000000
--- a/android/app/src/main/res/layout/confirm_no_email.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:scrollbars="none">
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="30dp"
- android:background="@drawable/dialog_background"
- android:orientation="vertical"
- android:gravity="start">
- <ImageView android:layout_width="44dp"
- android:layout_height="44dp"
- android:layout_marginTop="8dp"
- android:layout_gravity="center"
- android:src="@drawable/icon_alert" />
- <TextView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:layout_marginTop="16dp"
- android:textColor="@color/white80"
- android:textSize="@dimen/text_small"
- android:text="@string/confirm_no_email" />
- <Button android:id="@+id/send_button"
- android:layout_marginVertical="@dimen/button_separation"
- android:text="@string/send_anyway"
- style="@style/RedButton" />
- <Button android:id="@+id/back_button"
- android:text="@string/back"
- style="@style/BlueButton" />
- </LinearLayout>
-</ScrollView>
diff --git a/android/app/src/main/res/layout/problem_report.xml b/android/app/src/main/res/layout/problem_report.xml
deleted file mode 100644
index 5832b1a893..0000000000
--- a/android/app/src/main/res/layout/problem_report.xml
+++ /dev/null
@@ -1,163 +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/report_a_problem"
- 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">
- <net.mullvad.mullvadvpn.ui.widget.BackButton android:id="@+id/back"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- mullvad:text="@string/settings" />
- <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/report_a_problem"
- 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:orientation="vertical">
- <TextView android:id="@+id/expanded_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:layout_marginTop="2dp"
- android:layout_marginBottom="8dp"
- android:layout_marginHorizontal="@dimen/side_margin"
- android:lines="1"
- android:text="@string/report_a_problem"
- style="@style/SettingsExpandedHeader" />
- <ViewSwitcher android:id="@+id/body_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <LinearLayout android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <TextView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:layout_marginBottom="@dimen/vertical_space"
- android:layout_marginHorizontal="@dimen/side_margin"
- android:textColor="@color/white80"
- android:textSize="@dimen/text_small"
- android:text="@string/problem_report_description" />
- <EditText android:id="@+id/user_email"
- android:inputType="textEmailAddress"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:layout_marginBottom="12dp"
- android:layout_marginHorizontal="22dp"
- android:singleLine="true"
- android:hint="@string/user_email_hint"
- style="@style/InputText" />
- <EditText android:id="@+id/user_message"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:layout_marginHorizontal="@dimen/side_margin"
- android:singleLine="false"
- android:hint="@string/user_message_hint"
- android:gravity="top"
- style="@style/InputText" />
- <Button android:id="@+id/view_logs"
- android:layout_marginHorizontal="@dimen/side_margin"
- android:layout_marginVertical="@dimen/button_separation"
- android:enabled="true"
- android:text="@string/view_logs"
- style="@style/BlueButton" />
- <Button android:id="@+id/send_button"
- android:layout_marginHorizontal="@dimen/side_margin"
- android:layout_marginBottom="@dimen/screen_vertical_margin"
- android:enabled="false"
- android:text="@string/send"
- style="@style/GreenButton" />
- </LinearLayout>
- <LinearLayout android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginTop="16dp"
- android:layout_marginBottom="@dimen/screen_vertical_margin"
- android:layout_marginHorizontal="@dimen/side_margin"
- android:orientation="vertical">
- <FrameLayout android:layout_width="60dp"
- android:layout_height="60dp"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="32dp">
- <ProgressBar android:id="@+id/sending_spinner"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:indeterminate="true"
- android:indeterminateOnly="true"
- android:indeterminateDuration="600"
- android:indeterminateDrawable="@drawable/icon_spinner" />
- <ImageView android:id="@+id/sent_successfully_icon"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:src="@drawable/icon_success"
- android:visibility="gone" />
- <ImageView android:id="@+id/failed_to_send_icon"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:src="@drawable/icon_fail"
- android:visibility="gone" />
- </FrameLayout>
- <TextView android:id="@+id/send_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:textColor="@color/white"
- android:textSize="@dimen/text_huge"
- android:textStyle="bold"
- android:text="@string/sending" />
- <TextView android:id="@+id/send_details"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@color/white60"
- android:textSize="@dimen/text_small"
- android:text="@string/sent_thanks"
- android:visibility="gone" />
- <TextView android:id="@+id/response_message"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@color/white60"
- android:textSize="@dimen/text_small"
- android:text="@string/sent_contact"
- android:visibility="gone" />
- <Space android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1" />
- <Button android:id="@+id/edit_message_button"
- android:layout_marginTop="@dimen/button_separation"
- android:text="@string/edit_message"
- android:visibility="gone"
- style="@style/BlueButton" />
- <Button android:id="@+id/try_again_button"
- android:layout_marginTop="@dimen/button_separation"
- android:text="@string/try_again"
- android:visibility="gone"
- style="@style/GreenButton" />
- </LinearLayout>
- </ViewSwitcher>
- </LinearLayout>
- </net.mullvad.mullvadvpn.ui.widget.ListenableScrollView>
- </LinearLayout>
-</FrameLayout>
diff --git a/android/app/src/main/res/layout/view_logs.xml b/android/app/src/main/res/layout/view_logs.xml
deleted file mode 100644
index 2011c8b5c9..0000000000
--- a/android/app/src/main/res/layout/view_logs.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<LinearLayout 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"
- android:orientation="vertical">
- <net.mullvad.mullvadvpn.ui.widget.BackButton android:id="@+id/back"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- mullvad:text="@string/report_a_problem" />
- <TextView android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:layout_marginTop="2dp"
- android:layout_marginHorizontal="@dimen/side_margin"
- android:text="@string/view_logs"
- style="@style/SettingsExpandedHeader" />
- <ScrollView android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:layout_marginTop="@dimen/vertical_space"
- android:layout_marginHorizontal="@dimen/side_margin"
- android:layout_marginBottom="@dimen/screen_vertical_margin"
- android:scrollbarThumbVertical="@color/blue"
- android:background="@drawable/input_text_background">
- <EditText android:id="@+id/log_area"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:editable="false"
- android:textIsSelectable="true"
- android:singleLine="false"
- android:gravity="top"
- android:background="@null"
- style="@style/InputText" />
- </ScrollView>
-</LinearLayout>
diff --git a/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt b/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt
index 99c2132719..6445c51b56 100644
--- a/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt
+++ b/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt
@@ -56,7 +56,8 @@ data class Dimensions(
val titleIconSize: Dp = 24.dp,
val topBarHeight: Dp = 64.dp,
val verticalSpace: Dp = 20.dp,
- val verticalSpacer: Dp = 1.dp
+ val verticalSpacer: Dp = 1.dp,
+ val dialogIconSize: Dp = 48.dp
)
val defaultDimensions = Dimensions()