From f02f16d9c55d7bf037abddcbed54ede96ea698c2 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoit@matrix.org>
Date: Thu, 26 Sep 2019 10:41:52 +0200
Subject: [PATCH] Use IEC units instead of SI units for file sizes

---
 tools/check/forbidden_strings_in_code.txt     |  8 ++++-
 .../im/vector/riotx/core/utils/TextUtils.kt   | 27 +++++++++++++++++
 .../home/room/detail/RoomDetailFragment.kt    | 29 ++++++++-----------
 .../helper/ContentUploadStateTrackerBinder.kt |  6 ++--
 .../settings/VectorSettingsGeneralFragment.kt | 14 ++++-----
 5 files changed, 56 insertions(+), 28 deletions(-)

diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt
index 7686cb0b7c..7e00295a48 100644
--- a/tools/check/forbidden_strings_in_code.txt
+++ b/tools/check/forbidden_strings_in_code.txt
@@ -149,4 +149,10 @@ android\.app\.AlertDialog
 new Gson\(\)
 
 ### Use matrixOneTimeWorkRequestBuilder
-import androidx.work.OneTimeWorkRequestBuilder===1
\ No newline at end of file
+import androidx.work.OneTimeWorkRequestBuilder===1
+
+### Use TextUtils.formatFileSize
+Formatter\.formatFileSize===1
+
+### Use TextUtils.formatFileSize with short format param to true
+Formatter\.formatShortFileSize===1
diff --git a/vector/src/main/java/im/vector/riotx/core/utils/TextUtils.kt b/vector/src/main/java/im/vector/riotx/core/utils/TextUtils.kt
index 9d980e7f98..a7fa2cb350 100644
--- a/vector/src/main/java/im/vector/riotx/core/utils/TextUtils.kt
+++ b/vector/src/main/java/im/vector/riotx/core/utils/TextUtils.kt
@@ -16,6 +16,9 @@
 
 package im.vector.riotx.core.utils
 
+import android.content.Context
+import android.os.Build
+import android.text.format.Formatter
 import java.util.*
 
 object TextUtils {
@@ -42,4 +45,28 @@ object TextUtils {
             return value.toString()
         }
     }
+
+    /**
+     * Since Android O, the system considers that 1ko = 1000 bytes instead of 1024 bytes. We want to avoid that for the moment.
+     */
+    fun formatFileSize(context: Context, sizeBytes: Long, useShortFormat: Boolean = false): String {
+        val normalizedSize = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
+            sizeBytes
+        } else {
+            // First convert the size
+            when {
+                sizeBytes < 1024               -> sizeBytes
+                sizeBytes < 1024 * 1024        -> sizeBytes * 1000 / 1024
+                sizeBytes < 1024 * 1024 * 1024 -> sizeBytes * 1000 / 1024 * 1000 / 1024
+                else                           -> sizeBytes * 1000 / 1024 * 1000 / 1024 * 1000 / 1024
+            }
+        }
+
+        return if (useShortFormat) {
+            Formatter.formatShortFileSize(context, normalizedSize)
+        } else {
+            Formatter.formatFileSize(context, normalizedSize)
+
+        }
+    }
 }
\ No newline at end of file
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
index 7c7b90cd4b..ad9201c628 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
@@ -27,8 +27,6 @@ import android.os.Bundle
 import android.os.Parcelable
 import android.text.Editable
 import android.text.Spannable
-import android.text.TextUtils
-import android.text.format.Formatter
 import android.view.*
 import android.view.inputmethod.InputMethodManager
 import android.widget.TextView
@@ -149,18 +147,15 @@ class RoomDetailFragment :
          * @param displayName the display name to sanitize
          * @return the sanitized display name
          */
-        fun sanitizeDisplayname(displayName: String): String? {
-            // sanity checks
-            if (!TextUtils.isEmpty(displayName)) {
-                val ircPattern = " (IRC)"
-
-                if (displayName.endsWith(ircPattern)) {
-                    return displayName.substring(0, displayName.length - ircPattern.length)
-                }
+        private fun sanitizeDisplayName(displayName: String): String {
+            if (displayName.endsWith(ircPattern)) {
+                return displayName.substring(0, displayName.length - ircPattern.length)
             }
 
             return displayName
         }
+
+        private const val ircPattern = " (IRC)"
     }
 
     private val roomDetailArgs: RoomDetailArgs by args()
@@ -264,8 +259,8 @@ class RoomDetailFragment :
                 .setTitle(R.string.dialog_title_error)
                 .setMessage(getString(R.string.error_file_too_big,
                         error.filename,
-                        Formatter.formatFileSize(requireContext(), error.fileSizeInBytes),
-                        Formatter.formatFileSize(requireContext(), error.homeServerLimitInBytes)
+                        TextUtils.formatFileSize(requireContext(), error.fileSizeInBytes),
+                        TextUtils.formatFileSize(requireContext(), error.homeServerLimitInBytes)
                 ))
                 .setPositiveButton(R.string.ok, null)
                 .show()
@@ -987,23 +982,23 @@ class RoomDetailFragment :
 //            var vibrate = false
 
             val myDisplayName = session.getUser(session.myUserId)?.displayName
-            if (TextUtils.equals(myDisplayName, text)) {
+            if (myDisplayName == text) {
                 // current user
-                if (TextUtils.isEmpty(composerLayout.composerEditText.text)) {
+                if (composerLayout.composerEditText.text.isBlank()) {
                     composerLayout.composerEditText.append(Command.EMOTE.command + " ")
                     composerLayout.composerEditText.setSelection(composerLayout.composerEditText.text.length)
 //                    vibrate = true
                 }
             } else {
                 // another user
-                if (TextUtils.isEmpty(composerLayout.composerEditText.text)) {
+                if (composerLayout.composerEditText.text.isBlank()) {
                     // Ensure displayName will not be interpreted as a Slash command
                     if (text.startsWith("/")) {
                         composerLayout.composerEditText.append("\\")
                     }
-                    composerLayout.composerEditText.append(sanitizeDisplayname(text)!! + ": ")
+                    composerLayout.composerEditText.append(sanitizeDisplayName(text) + ": ")
                 } else {
-                    composerLayout.composerEditText.text.insert(composerLayout.composerEditText.selectionStart, sanitizeDisplayname(text)!! + " ")
+                    composerLayout.composerEditText.text.insert(composerLayout.composerEditText.selectionStart, sanitizeDisplayName(text) + " ")
                 }
 
 //                vibrate = true
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/ContentUploadStateTrackerBinder.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/ContentUploadStateTrackerBinder.kt
index 09b2e86a83..96cb7f0d8e 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/ContentUploadStateTrackerBinder.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/ContentUploadStateTrackerBinder.kt
@@ -16,7 +16,6 @@
 
 package im.vector.riotx.features.home.room.detail.timeline.helper
 
-import android.text.format.Formatter
 import android.view.View
 import android.view.ViewGroup
 import android.widget.ProgressBar
@@ -28,6 +27,7 @@ import im.vector.riotx.R
 import im.vector.riotx.core.di.ActiveSessionHolder
 import im.vector.riotx.core.error.ErrorFormatter
 import im.vector.riotx.core.resources.ColorProvider
+import im.vector.riotx.core.utils.TextUtils
 import im.vector.riotx.features.ui.getMessageTextColor
 import javax.inject.Inject
 
@@ -126,8 +126,8 @@ private class ContentMediaProgressUpdater(private val progressLayout: ViewGroup,
         progressBar?.isIndeterminate = false
         progressBar?.progress = percent.toInt()
         progressTextView?.text = progressLayout.context.getString(resId,
-                Formatter.formatShortFileSize(progressLayout.context, current),
-                Formatter.formatShortFileSize(progressLayout.context, total))
+                TextUtils.formatFileSize(progressLayout.context, current, true),
+                TextUtils.formatFileSize(progressLayout.context, total, true))
         progressTextView?.setTextColor(colorProvider.getMessageTextColor(SendState.SENDING))
     }
 
diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsGeneralFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsGeneralFragment.kt
index 2bec8cf103..e51feb2363 100644
--- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsGeneralFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsGeneralFragment.kt
@@ -20,7 +20,7 @@ import android.app.Activity
 import android.content.Context
 import android.content.Intent
 import android.text.Editable
-import android.text.TextUtils
+import android.util.Patterns
 import android.view.View
 import android.view.ViewGroup
 import android.view.inputmethod.InputMethodManager
@@ -171,7 +171,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
             MXSession.getApplicationSizeCaches(activity, object : SimpleApiCallback<Long>() {
                 override fun onSuccess(size: Long) {
                     if (null != activity) {
-                        it.summary = android.text.format.Formatter.formatFileSize(activity, size)
+                        it.summary = TextUtils.formatFileSize(activity, size)
                     }
                 }
             })
@@ -189,7 +189,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
             val size = getSizeOfFiles(requireContext(),
                     File(requireContext().cacheDir, DiskCache.Factory.DEFAULT_DISK_CACHE_DIR))
 
-            it.summary = android.text.format.Formatter.formatFileSize(activity, size.toLong())
+            it.summary = TextUtils.formatFileSize(requireContext(), size.toLong())
 
             it.onPreferenceClickListener = Preference.OnPreferenceClickListener {
                 GlobalScope.launch(Dispatchers.Main) {
@@ -208,7 +208,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
                                 File(requireContext().cacheDir, DiskCache.Factory.DEFAULT_DISK_CACHE_DIR))
                     }
 
-                    it.summary = android.text.format.Formatter.formatFileSize(activity, newSize.toLong())
+                    it.summary = TextUtils.formatFileSize(requireContext(), newSize.toLong())
 
                     hideLoadingView()
                 }
@@ -534,7 +534,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
     private fun addEmail(email: String) {
         // check first if the email syntax is valid
         // if email is null , then also its invalid email
-        if (TextUtils.isEmpty(email) || !android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
+        if (email.isBlank() || !Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
             activity?.toast(R.string.auth_invalid_email)
             return
         }
@@ -719,9 +719,9 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
                     val newPwd = newPasswordText.text.toString().trim()
                     val newConfirmPwd = confirmNewPasswordText.text.toString().trim()
 
-                    updateButton.isEnabled = oldPwd.isNotEmpty() && newPwd.isNotEmpty() && TextUtils.equals(newPwd, newConfirmPwd)
+                    updateButton.isEnabled = oldPwd.isNotEmpty() && newPwd.isNotEmpty() && newPwd == newConfirmPwd
 
-                    if (newPwd.isNotEmpty() && newConfirmPwd.isNotEmpty() && !TextUtils.equals(newPwd, newConfirmPwd)) {
+                    if (newPwd.isNotEmpty() && newConfirmPwd.isNotEmpty() && newPwd != newConfirmPwd) {
                         confirmNewPasswordTil.error = getString(R.string.passwords_do_not_match)
                     }
                 }