diff --git a/README.md b/README.md
index efdb25f37..74b1e1017 100644
--- a/README.md
+++ b/README.md
@@ -93,6 +93,8 @@ You can install this APK by:
##### Internal release
+- Increase bundle_release versionCode + 1 in fastlane/Fastlane file.
+
- Build and publish internal release:
```bash
source fastlane/.env.local && fastlane android beta
diff --git a/android/app/src/main/java/network/mysterium/ui/FeedbackFragment.kt b/android/app/src/main/java/network/mysterium/ui/FeedbackFragment.kt
index fa67994ac..af820a47c 100644
--- a/android/app/src/main/java/network/mysterium/ui/FeedbackFragment.kt
+++ b/android/app/src/main/java/network/mysterium/ui/FeedbackFragment.kt
@@ -66,6 +66,11 @@ class FeedbackFragment : Fragment() {
}
private fun handleFeedbackSubmit(root: View) {
+ if (!feedbackViewModel.isMessageSet()) {
+ showMessage(root.context, getString(R.string.feedback_message_required))
+ return
+ }
+
feedbackSubmitButton.isEnabled = false
navigateTo(root, Screen.MAIN)
showMessage(root.context, getString(R.string.feedback_submit_success))
diff --git a/android/app/src/main/java/network/mysterium/ui/FeedbackViewModel.kt b/android/app/src/main/java/network/mysterium/ui/FeedbackViewModel.kt
index e3b6ab190..be2beef86 100644
--- a/android/app/src/main/java/network/mysterium/ui/FeedbackViewModel.kt
+++ b/android/app/src/main/java/network/mysterium/ui/FeedbackViewModel.kt
@@ -53,6 +53,10 @@ class FeedbackViewModel(private val nodeRepository: NodeRepository): ViewModel()
message = msg
}
+ fun isMessageSet(): Boolean {
+ return message != ""
+ }
+
suspend fun submit() {
val req = SendFeedbackRequest()
req.description = "Platform: Android, Feedback Type: $feebackType, Message: $message"
diff --git a/android/app/src/main/java/network/mysterium/ui/MainVpnFragment.kt b/android/app/src/main/java/network/mysterium/ui/MainVpnFragment.kt
index 21744074c..771b3344e 100644
--- a/android/app/src/main/java/network/mysterium/ui/MainVpnFragment.kt
+++ b/android/app/src/main/java/network/mysterium/ui/MainVpnFragment.kt
@@ -55,6 +55,8 @@ class MainVpnFragment : Fragment() {
private lateinit var vpnStatsDurationLabel: TextView
private lateinit var vpnStatsBytesSentLabel: TextView
private lateinit var vpnStatsBytesReceivedLabel: TextView
+ private lateinit var vpnStatsBytesReceivedUnits: TextView
+ private lateinit var vpnStatsBytesSentUnits: TextView
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
@@ -80,6 +82,8 @@ class MainVpnFragment : Fragment() {
vpnStatsDurationLabel = root.findViewById(R.id.vpn_stats_duration)
vpnStatsBytesReceivedLabel = root.findViewById(R.id.vpn_stats_bytes_received)
vpnStatsBytesSentLabel = root.findViewById(R.id.vpn_stats_bytes_sent)
+ vpnStatsBytesReceivedUnits = root.findViewById(R.id.vpn_stats_bytes_received_units)
+ vpnStatsBytesSentUnits = root.findViewById(R.id.vpn_stats_bytes_sent_units)
feedbackButton.setOnClickListener {
navigateTo(root, Screen.FEEDBACK)
@@ -137,8 +141,10 @@ class MainVpnFragment : Fragment() {
private fun updateStatsLabels(it: StatisticsViewItem) {
vpnStatsDurationLabel.text = it.duration
- vpnStatsBytesReceivedLabel.text = it.bytesReceived
- vpnStatsBytesSentLabel.text = it.bytesSent
+ vpnStatsBytesReceivedLabel.text = it.bytesReceived.value
+ vpnStatsBytesReceivedUnits.text = it.bytesReceived.units
+ vpnStatsBytesSentLabel.text = it.bytesSent.value
+ vpnStatsBytesSentUnits.text = it.bytesSent.units
}
private fun updateConnStateLabel(it: ConnectionState) {
@@ -212,7 +218,7 @@ class MainVpnFragment : Fragment() {
private fun connect(ctx: Context) {
val proposal: ProposalViewItem? = sharedViewModel.selectedProposal.value
if (proposal == null) {
- showMessage(ctx, "Select proposal!")
+ showMessage(ctx, getString(R.string.vpn_select_proposal_warning))
return
}
job?.cancel()
@@ -223,7 +229,7 @@ class MainVpnFragment : Fragment() {
} catch (e: kotlinx.coroutines.CancellationException) {
// Do nothing.
} catch (e: Exception) {
- showMessage(ctx, "Failed to connect. Please try again.")
+ showMessage(ctx, getString(R.string.vpn_failed_to_connect))
Log.e(TAG, "Failed to connect", e)
}
}
@@ -236,7 +242,7 @@ class MainVpnFragment : Fragment() {
try {
sharedViewModel.disconnect()
} catch (e: Exception) {
- showMessage(ctx, "Failed to disconnect. Please try again.")
+ showMessage(ctx, getString(R.string.vpn_failed_to_disconnect))
Log.e(TAG, "Failed to disconnect", e)
}
}
diff --git a/android/app/src/main/java/network/mysterium/ui/SharedViewModel.kt b/android/app/src/main/java/network/mysterium/ui/SharedViewModel.kt
index 8dd61c4a0..1924569bb 100644
--- a/android/app/src/main/java/network/mysterium/ui/SharedViewModel.kt
+++ b/android/app/src/main/java/network/mysterium/ui/SharedViewModel.kt
@@ -52,8 +52,8 @@ class LocationViewItem(
class StatisticsViewItem(
val duration: String,
- val bytesReceived: String,
- val bytesSent: String
+ val bytesReceived: FormattedBytesViewItem,
+ val bytesSent: FormattedBytesViewItem
) {
companion object {
fun from(it: Statistics): StatisticsViewItem {
@@ -196,19 +196,17 @@ class SharedViewModel(
// This is needed since status change can be executed on separate
// inside go node library.
viewModelScope.launch {
- val s = StatisticsViewItem(
- duration = UnitFormatter.timeDisplay(it.duration.toDouble()),
- bytesReceived = UnitFormatter.bytesDisplay(it.bytesReceived.toDouble()),
- bytesSent = UnitFormatter.bytesDisplay(it.bytesSent.toDouble())
- )
- statistics.value = s
+ val s = StatisticsViewItem.from(it)
+ statistics.value = StatisticsViewItem.from(it)
// Show global notification with connected country and statistics.
// At this point we need to check if proposal is not null since
// statistics event can fire sooner than proposal is loaded.
if (selectedProposal.value != null) {
val countryName = selectedProposal.value?.countryName
- mysteriumCoreService.await().showNotification("Connected to $countryName", "Received ${s.bytesReceived} | Send ${s.bytesSent}")
+ val notificationTitle = "Connected to $countryName"
+ val notificationContent = "Received ${s.bytesReceived.value} ${s.bytesReceived.units} | Send ${s.bytesSent.value} ${s.bytesSent.units}"
+ mysteriumCoreService.await().showNotification(notificationTitle, notificationContent)
}
}
}
diff --git a/android/app/src/main/java/network/mysterium/ui/UnitFormatter.kt b/android/app/src/main/java/network/mysterium/ui/UnitFormatter.kt
index d6e1d69cb..f7a70f7a3 100644
--- a/android/app/src/main/java/network/mysterium/ui/UnitFormatter.kt
+++ b/android/app/src/main/java/network/mysterium/ui/UnitFormatter.kt
@@ -20,17 +20,20 @@ package network.mysterium.ui
import kotlin.math.floor
import kotlin.math.roundToInt
+
+class FormattedBytesViewItem(val value: String, val units: String)
+
object UnitFormatter {
val KB = 1024
val MB = 1024 * KB
val GB = 1024 * MB
- fun bytesDisplay(bytes: Double): String {
+ fun bytesDisplay(bytes: Double): FormattedBytesViewItem {
return when {
- bytes < KB -> "$bytes B"
- bytes < MB -> "%.2f KB".format(bytes / KB)
- bytes < GB -> "%.2f MB".format(bytes / MB)
- else -> "%.2f GB".format(bytes / GB)
+ bytes < KB -> FormattedBytesViewItem("$bytes", "B")
+ bytes < MB -> FormattedBytesViewItem("%.2f".format(bytes / KB), "KB")
+ bytes < GB -> FormattedBytesViewItem("%.2f".format(bytes / MB), "MB")
+ else -> FormattedBytesViewItem("%.2f".format(bytes / GB), "GB")
}
}
diff --git a/android/app/src/main/res/layout/fragment_main_vpn.xml b/android/app/src/main/res/layout/fragment_main_vpn.xml
index 4b3b6b59c..d819a9d53 100644
--- a/android/app/src/main/res/layout/fragment_main_vpn.xml
+++ b/android/app/src/main/res/layout/fragment_main_vpn.xml
@@ -281,7 +281,7 @@
android:text="0" />
Loading
Loading
Message
+ Message is required.
+ Please select proposal to connect.
+ Failed to connect. Please try again.
+ Failed to disconnect. Please try again.
diff --git a/android/app/src/test/java/UnitFormatterTest.kt b/android/app/src/test/java/UnitFormatterTest.kt
index ccd0e5129..17d914b20 100644
--- a/android/app/src/test/java/UnitFormatterTest.kt
+++ b/android/app/src/test/java/UnitFormatterTest.kt
@@ -23,18 +23,22 @@ class UnitFormatterTest {
fun testBytesFormatting() {
var longVal: Long = 101
var res = UnitFormatter.bytesDisplay(longVal.toDouble())
- assertEquals("101.0 B", res)
+ assertEquals("101.0 B", "${res.value} ${res.units}")
longVal = 1028
res = UnitFormatter.bytesDisplay(longVal.toDouble())
- assertEquals("1.00 KB", res)
+ assertEquals("1.00 KB", "${res.value} ${res.units}")
longVal = 81068
res = UnitFormatter.bytesDisplay(longVal.toDouble())
- assertEquals("79.17 KB", res)
+ assertEquals("79.17 KB", "${res.value} ${res.units}")
longVal = 9381068
res = UnitFormatter.bytesDisplay(longVal.toDouble())
- assertEquals("8.95 MB", res)
+ assertEquals("8.95 MB", "${res.value} ${res.units}")
+
+ longVal = 1309381068
+ res = UnitFormatter.bytesDisplay(longVal.toDouble())
+ assertEquals("1.22 GB", "${res.value} ${res.units}")
}
}
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
index f9220796e..1ecb3d56b 100644
--- a/fastlane/Fastfile
+++ b/fastlane/Fastfile
@@ -25,7 +25,7 @@ platform :android do
project_dir: "android",
print_command: false, # to prevent outputting passwords
properties: {
- 'versionCode' => 10000 + number_of_commits,
+ 'versionCode' => 1,
'versionName' => last_git_tag,
'applyGoogleServices' => true,
"android.injected.signing.store.file" => ENV["FASTLANE_ANDROID_SIGNING_FILE_PATH"],
@@ -42,7 +42,7 @@ platform :android do
project_dir: "android",
print_command: false, # to prevent outputting passwords
properties: {
- 'versionCode' => 10000 + number_of_commits,
+ 'versionCode' => 10694,
'versionName' => last_git_tag,
'applyGoogleServices' => true,
"android.injected.signing.store.file" => ENV["FASTLANE_ANDROID_SIGNING_FILE_PATH"],