diff --git a/commons/build.gradle.kts b/commons/build.gradle.kts
index f0a41342e3..794bc27d6a 100644
--- a/commons/build.gradle.kts
+++ b/commons/build.gradle.kts
@@ -106,6 +106,7 @@ dependencies {
implementation(libs.androidx.exifinterface)
implementation(libs.androidx.biometric.ktx)
implementation(libs.androidx.lifecycle.process)
+ implementation(libs.androidx.startup)
implementation(libs.ez.vcard)
implementation(libs.bundles.lifecycle)
diff --git a/commons/src/main/AndroidManifest.xml b/commons/src/main/AndroidManifest.xml
index 1a2cd43393..27c5310e3f 100644
--- a/commons/src/main/AndroidManifest.xml
+++ b/commons/src/main/AndroidManifest.xml
@@ -31,6 +31,16 @@
+
+
+
+
()
private lateinit var backCallback: OnBackPressedCallback
+ private var useBinaryStorageUnits = false
companion object {
private const val GENERIC_PERM_HANDLER = 100
@@ -190,6 +191,7 @@ abstract class BaseSimpleActivity : EdgeToEdgeActivity() {
installFontInflaterFactory()
super.onCreate(savedInstanceState)
+ useBinaryStorageUnits = baseConfig.useBinaryStorageUnits
WindowCompat.enableEdgeToEdge(window)
registerBackPressedCallback()
@@ -221,6 +223,10 @@ abstract class BaseSimpleActivity : EdgeToEdgeActivity() {
override fun onResume() {
super.onResume()
+ if (useBinaryStorageUnits != baseConfig.useBinaryStorageUnits) {
+ recreate()
+ return
+ }
if (useDynamicTheme) {
setTheme(getThemeId(showTransparentTop = true))
updateBackgroundColor(getProperBackgroundColor())
diff --git a/commons/src/main/kotlin/org/fossify/commons/extensions/Context-styling.kt b/commons/src/main/kotlin/org/fossify/commons/extensions/Context-styling.kt
index b7970cacbf..93c36cfdf6 100644
--- a/commons/src/main/kotlin/org/fossify/commons/extensions/Context-styling.kt
+++ b/commons/src/main/kotlin/org/fossify/commons/extensions/Context-styling.kt
@@ -149,6 +149,7 @@ fun Context.getPopupMenuTheme(): Int {
fun Context.syncGlobalConfig(callback: (() -> Unit)? = null) {
if (canAccessGlobalConfig()) {
withGlobalConfig {
+ baseConfig.useBinaryStorageUnits = it?.useBinaryStorageUnits ?: false
if (it != null) {
baseConfig.apply {
showCheckmarksOnSwitches = it.showCheckmarksOnSwitches
@@ -182,6 +183,7 @@ fun Context.syncGlobalConfig(callback: (() -> Unit)? = null) {
} else {
baseConfig.isGlobalThemeEnabled = false
baseConfig.showCheckmarksOnSwitches = false
+ baseConfig.useBinaryStorageUnits = false
validateFontSettings()
callback?.invoke()
}
@@ -224,7 +226,8 @@ fun Context.getGlobalConfig(cursorLoader: CursorLoader): GlobalConfig? {
showCheckmarksOnSwitches = cursor.getIntValue(MyContentProvider.COL_SHOW_CHECKMARKS_ON_SWITCHES) != 0,
lastUpdatedTS = cursor.getIntValue(MyContentProvider.COL_LAST_UPDATED_TS),
fontType = cursor.getIntValueOr(MyContentProvider.COL_FONT_TYPE, -1),
- fontName = cursor.getStringValueOr(MyContentProvider.COL_FONT_NAME, "")
+ fontName = cursor.getStringValueOr(MyContentProvider.COL_FONT_NAME, ""),
+ useBinaryStorageUnits = cursor.getIntValueOr(MyContentProvider.COL_USE_BINARY_STORAGE_UNITS, 0) != 0
)
} catch (_: Exception) {
}
diff --git a/commons/src/main/kotlin/org/fossify/commons/extensions/Int.kt b/commons/src/main/kotlin/org/fossify/commons/extensions/Int.kt
index 6dc9ce2496..19b43d1cb0 100644
--- a/commons/src/main/kotlin/org/fossify/commons/extensions/Int.kt
+++ b/commons/src/main/kotlin/org/fossify/commons/extensions/Int.kt
@@ -10,11 +10,8 @@ import androidx.core.graphics.ColorUtils
import androidx.core.os.postDelayed
import org.fossify.commons.helpers.DARK_GREY
import org.fossify.commons.helpers.WCAG_AA_NORMAL
-import java.text.DecimalFormat
import java.util.Locale
import java.util.Random
-import kotlin.math.log10
-import kotlin.math.pow
fun Int.getContrastColor(): Int {
val luminance = ColorUtils.calculateLuminance(this)
@@ -49,13 +46,7 @@ fun Int.getFormattedDuration(forceShowHours: Boolean = false): String {
}
@Deprecated("Use Long.formatSize() instead.")
-fun Int.formatSize(): String {
- if (this <= 0) return "0 B"
-
- val units = arrayOf("B", "kB", "MB", "GB", "TB")
- val digitGroups = (log10(toDouble()) / log10(1000.0)).toInt()
- return "${DecimalFormat("#,##0.#").format(this / 1000.0.pow(digitGroups.toDouble()))} ${units[digitGroups]}"
-}
+fun Int.formatSize(): String = toLong().formatSize()
@Deprecated(
message = "Broken due to the Year 2038 problem. Use Long.formatDate() instead (but note that it uses milliseconds, not seconds).",
diff --git a/commons/src/main/kotlin/org/fossify/commons/extensions/Long.kt b/commons/src/main/kotlin/org/fossify/commons/extensions/Long.kt
index 5a4a11a541..35cbdd010f 100644
--- a/commons/src/main/kotlin/org/fossify/commons/extensions/Long.kt
+++ b/commons/src/main/kotlin/org/fossify/commons/extensions/Long.kt
@@ -4,19 +4,11 @@ import android.content.Context
import android.text.format.DateFormat
import android.text.format.DateUtils
import android.text.format.Time
-import java.text.DecimalFormat
+import org.fossify.commons.helpers.FileSizeFormatter
import java.util.Calendar
import java.util.Locale
-import kotlin.math.log10
-import kotlin.math.pow
-fun Long.formatSize(): String {
- if (this <= 0) return "0 B"
-
- val units = arrayOf("B", "kB", "MB", "GB", "TB", "PB", "EB")
- val digitGroups = (log10(toDouble()) / log10(1000.0)).toInt()
- return "${DecimalFormat("#,##0.#").format(this / 1000.0.pow(digitGroups.toDouble()))} ${units[digitGroups]}"
-}
+fun Long.formatSize(): String = FileSizeFormatter.format(this)
fun Long.formatDate(context: Context, dateFormat: String? = null, timeFormat: String? = null): String {
val useDateFormat = dateFormat ?: context.baseConfig.dateFormat
diff --git a/commons/src/main/kotlin/org/fossify/commons/helpers/BaseConfig.kt b/commons/src/main/kotlin/org/fossify/commons/helpers/BaseConfig.kt
index c3b9aafe76..9705f35bfd 100644
--- a/commons/src/main/kotlin/org/fossify/commons/helpers/BaseConfig.kt
+++ b/commons/src/main/kotlin/org/fossify/commons/helpers/BaseConfig.kt
@@ -612,6 +612,12 @@ open class BaseConfig(val context: Context) {
var showCheckmarksOnSwitchesFlow = ::showCheckmarksOnSwitches.asFlowNonNull()
+ var useBinaryStorageUnits: Boolean
+ get() = prefs.getBoolean(USE_BINARY_STORAGE_UNITS, false)
+ set(useBinaryStorageUnits) = prefs.edit().putBoolean(USE_BINARY_STORAGE_UNITS, useBinaryStorageUnits).apply()
+
+ val useBinaryStorageUnitsFlow = ::useBinaryStorageUnits.asFlowNonNull()
+
// Font customization
var fontType: Int
get() = prefs.getInt(CUSTOM_FONT_TYPE, FONT_TYPE_SYSTEM_DEFAULT)
diff --git a/commons/src/main/kotlin/org/fossify/commons/helpers/Constants.kt b/commons/src/main/kotlin/org/fossify/commons/helpers/Constants.kt
index 62d54b78b4..6bf828631d 100644
--- a/commons/src/main/kotlin/org/fossify/commons/helpers/Constants.kt
+++ b/commons/src/main/kotlin/org/fossify/commons/helpers/Constants.kt
@@ -203,6 +203,7 @@ const val PASSWORD_COUNTDOWN_START_MS = "password_count_down_start_ms"
const val LAST_UNLOCK_TIMESTAMP_MS = "last_unlock_timestamp_ms"
const val UNLOCK_TIMEOUT_DURATION_MS = "unlock_timeout_duration_ms"
const val SHOW_CHECKMARKS_ON_SWITCHES = "show_checkmarks_on_switches"
+const val USE_BINARY_STORAGE_UNITS = "use_binary_storage_units"
const val FIRST_DAY_OF_WEEK = "first_day_of_week"
const val CUSTOM_FONT_TYPE = "custom_font_type"
const val CUSTOM_FONT_FILE_NAME = "custom_font_file_name"
diff --git a/commons/src/main/kotlin/org/fossify/commons/helpers/FileSizeFormatter.kt b/commons/src/main/kotlin/org/fossify/commons/helpers/FileSizeFormatter.kt
new file mode 100644
index 0000000000..4d38e856cf
--- /dev/null
+++ b/commons/src/main/kotlin/org/fossify/commons/helpers/FileSizeFormatter.kt
@@ -0,0 +1,31 @@
+package org.fossify.commons.helpers
+
+import android.content.Context
+import android.content.SharedPreferences
+import org.fossify.commons.extensions.getSharedPrefs
+import java.text.DecimalFormat
+import kotlin.math.log10
+import kotlin.math.pow
+
+private const val BINARY_UNIT_BASE = 1024.0
+
+internal object FileSizeFormatter {
+ private var preferences: SharedPreferences? = null
+ private val decimalUnits = arrayOf("B", "kB", "MB", "GB", "TB", "PB", "EB")
+ private val binaryUnits = arrayOf("B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB")
+
+ fun initialize(context: Context) {
+ preferences = context.getSharedPrefs()
+ }
+
+ fun format(bytes: Long): String {
+ if (bytes <= 0) return "0 B"
+
+ val useBinaryUnits = preferences?.getBoolean(USE_BINARY_STORAGE_UNITS, false) == true
+ val divisor = if (useBinaryUnits) BINARY_UNIT_BASE else 1000.0
+ val units = if (useBinaryUnits) binaryUnits else decimalUnits
+ val digitGroups = (log10(bytes.toDouble()) / log10(divisor)).toInt()
+ val value = bytes / divisor.pow(digitGroups.toDouble())
+ return "${DecimalFormat("#,##0.#").format(value)} ${units[digitGroups]}"
+ }
+}
diff --git a/commons/src/main/kotlin/org/fossify/commons/helpers/FileSizeFormatterInitializer.kt b/commons/src/main/kotlin/org/fossify/commons/helpers/FileSizeFormatterInitializer.kt
new file mode 100644
index 0000000000..0574ee6832
--- /dev/null
+++ b/commons/src/main/kotlin/org/fossify/commons/helpers/FileSizeFormatterInitializer.kt
@@ -0,0 +1,12 @@
+package org.fossify.commons.helpers
+
+import android.content.Context
+import androidx.startup.Initializer
+
+class FileSizeFormatterInitializer : Initializer {
+ override fun create(context: Context) {
+ FileSizeFormatter.initialize(context)
+ }
+
+ override fun dependencies(): List>> = emptyList()
+}
diff --git a/commons/src/main/kotlin/org/fossify/commons/helpers/MyContentProvider.kt b/commons/src/main/kotlin/org/fossify/commons/helpers/MyContentProvider.kt
index a22be4b02a..0d614df27a 100644
--- a/commons/src/main/kotlin/org/fossify/commons/helpers/MyContentProvider.kt
+++ b/commons/src/main/kotlin/org/fossify/commons/helpers/MyContentProvider.kt
@@ -22,6 +22,7 @@ object MyContentProvider {
const val COL_APP_ICON_COLOR = "app_icon_color"
const val COL_SHOW_CHECKMARKS_ON_SWITCHES = "show_checkmarks_on_switches"
const val COL_LAST_UPDATED_TS = "last_updated_ts"
+ const val COL_USE_BINARY_STORAGE_UNITS = "use_binary_storage_units"
// Font customization
const val COL_FONT_TYPE = "font_type"
diff --git a/commons/src/main/kotlin/org/fossify/commons/models/GlobalConfig.kt b/commons/src/main/kotlin/org/fossify/commons/models/GlobalConfig.kt
index 69811429ef..8b6ff394d2 100644
--- a/commons/src/main/kotlin/org/fossify/commons/models/GlobalConfig.kt
+++ b/commons/src/main/kotlin/org/fossify/commons/models/GlobalConfig.kt
@@ -14,6 +14,7 @@ data class GlobalConfig(
val lastUpdatedTS: Int = 0,
val fontType: Int = FONT_TYPE_SYSTEM_DEFAULT,
val fontName: String = "",
+ val useBinaryStorageUnits: Boolean = false,
)
fun GlobalConfig?.isGlobalThemingEnabled(): Boolean {
diff --git a/commons/src/main/kotlin/org/fossify/commons/receivers/FossifyBroadcastReceiver.kt b/commons/src/main/kotlin/org/fossify/commons/receivers/FossifyBroadcastReceiver.kt
index 699bdbc503..d33e83612e 100644
--- a/commons/src/main/kotlin/org/fossify/commons/receivers/FossifyBroadcastReceiver.kt
+++ b/commons/src/main/kotlin/org/fossify/commons/receivers/FossifyBroadcastReceiver.kt
@@ -9,7 +9,10 @@ import org.fossify.commons.helpers.MyContentProvider
class FossifyBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == MyContentProvider.ACTION_GLOBAL_CONFIG_UPDATED) {
- context?.syncGlobalConfig()
+ context?.let {
+ val pendingResult = goAsync()
+ it.syncGlobalConfig { pendingResult.finish() }
+ }
}
}
}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 51bf9147b6..f32e3214ba 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -12,6 +12,7 @@ detektCompose = "0.4.28"
androidx-customView = "1.2.0"
androidx-customViewPooling = "1.1.0"
androidx-lifecycle = "2.10.0"
+androidx-startup = "1.2.0"
androidx-constraintlayout = "2.2.1"
androidx-documentfile = "1.1.0"
androidx-biometricKtx = "1.4.0-alpha02"
@@ -53,6 +54,7 @@ app-build-javaVersion = "VERSION_17"
app-build-kotlinJVMTarget = "17"
[libraries]
#Android X
+androidx-startup = { module = "androidx.startup:startup-runtime", version.ref = "androidx-startup" }
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
androidx-biometric-ktx = { module = "androidx.biometric:biometric-ktx", version.ref = "androidx-biometricKtx" }
androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "androidx-constraintlayout" }