Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Verified Commit 107475a6 authored by Fahim M. Choudhury's avatar Fahim M. Choudhury
Browse files

feat: show size for open-source apps

CleanAPK API response contains APK info in a dynamic property named "update_<X>" where X is any integer.

ApplicationDeserializer is modified to parse the property "apk_file_size" from the property "update_<X>". The value contains a string such as 4.05 KiB, 1.23 MiB, etc.

To make the size info consistent with existing UI for Google Play, which shows the size in KB and MB instead of KiB and MiB, size conversion is implemented in BinaryToDecimalSizeConverter, including unit tests.

If there's no correct size information is found, the app details UI will not show any info.
parent b96969c9
Loading
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ data class Application(
    var status: Status = Status.UNAVAILABLE,
    val shareUrl: String = String(),
    val originalSize: Long = 0,
    val appSize: String = String(),
    var appSize: String = String(),
    var source: Source = Source.PLAY_STORE,
    val price: String = String(),
    val isFree: Boolean = true,
+59 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 e Foundation
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

package foundation.e.apps.data.application.utils

import java.util.Locale

@Suppress("MagicNumber")
fun convertBinaryToDecimal(input: String): String {
    val binaryToDecimalMap = mapOf(
        "KiB" to "KB",
        "MiB" to "MB",
        "GiB" to "GB"
    )

    val regex = Regex("(-?\\d+(?:\\.\\d+)?)\\s*([KMG]iB)")
    val matchResult = regex.find(input)

    return if (matchResult != null) {
        val value = matchResult.groupValues[1].toDouble()

        if (value < 0) {
            return ""
        }

        val binaryUnit = matchResult.groupValues[2]
        val decimalUnit = binaryToDecimalMap[binaryUnit]

        if (decimalUnit != null) {
            // Convert the value from binary to decimal using the correct factor
            val decimalValue = when (binaryUnit) {
                "KiB" -> value * 1.024
                "MiB" -> value * 1.048576
                "GiB" -> value * 1.073741824
                else -> value
            }
            String.format(Locale.getDefault(), "%.2f %s", decimalValue, decimalUnit)
        } else {
            "" // Unknown unit
        }
    } else {
        "" // Invalid input format
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import com.google.gson.Gson
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import foundation.e.apps.data.application.utils.convertBinaryToDecimal
import foundation.e.apps.data.cleanapk.data.app.CleanApkApplication

class ApplicationDeserializer : JsonDeserializer<CleanApkApplication> {
@@ -38,6 +39,11 @@ class ApplicationDeserializer : JsonDeserializer<CleanApkApplication> {
            ?.asJsonObject?.get("update_on")?.asString ?: ""
        cleanApkApplication.app.updatedOn = lastUpdatedOn
        cleanApkApplication.app.latest_version_code = lastUpdateJson?.get("version_code")?.asInt ?: -1
        val appSizeInBinary =
            (json?.asJsonObject?.get("app")?.asJsonObject?.get(lastUpdate)?.asJsonObject?.get("apk_file_size")?.asString
                ?: "")
        cleanApkApplication.app.appSize = convertBinaryToDecimal(appSizeInBinary) // KiB to KB, MiB to MB, etc.

        return cleanApkApplication
    }
}
+60 −0
Original line number Diff line number Diff line
package foundation.e.apps.data.application.utils

/*
 * Copyright (C) 2025 e Foundation
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

import junit.framework.TestCase.assertEquals
import org.junit.Test


class BinaryToDecimalSizeConverterTest {

    @Test
    fun `test valid MiB to MB conversion`() {
        assertEquals("1.05 MB", convertBinaryToDecimal("1 MiB"))
        assertEquals("2.10 MB", convertBinaryToDecimal("2 MiB"))
    }

    @Test
    fun `test valid KiB to KB conversion`() {
        assertEquals("1.02 KB", convertBinaryToDecimal("1 KiB"))
        assertEquals("1048.58 KB", convertBinaryToDecimal("1024 KiB"))
    }

    @Test
    fun `test valid GiB to GB conversion`() {
        assertEquals("1.07 GB", convertBinaryToDecimal("1 GiB"))
        assertEquals("2.15 GB", convertBinaryToDecimal("2 GiB"))
    }

    @Test
    fun `test unknown unit`() {
        assertEquals("", convertBinaryToDecimal("1 TiB")) // Tebibyte
        assertEquals("", convertBinaryToDecimal("1 PiB")) // Pebibyte
    }

    @Test
    fun `test edge cases with zero and negative values`() {
        assertEquals("0.00 MB", convertBinaryToDecimal("0 MiB"))
        assertEquals("0.00 KB", convertBinaryToDecimal("0 KiB"))
        assertEquals("0.00 GB", convertBinaryToDecimal("0 GiB"))

        assertEquals("", convertBinaryToDecimal("-1 MiB")) // Negative value
        assertEquals("", convertBinaryToDecimal("-1024 KiB")) // Negative value
    }
}