From ad207eec4fb9992b5d629a33c31817b2d81df98e Mon Sep 17 00:00:00 2001 From: Adolar0042 <39769465+Adolar0042@users.noreply.github.com> Date: Tue, 12 Dec 2023 18:11:03 +0100 Subject: [PATCH 01/13] dep(gradle): upgrade gradle version 8.3.0-alpha05 -> 8.3.0-alpha11 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 075e039..5f1dcc0 100755 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agp = "8.3.0-alpha05" +agp = "8.3.0-alpha11" acraHttp = "5.11.3" autoService = "1.1.1" coilCompose = "2.4.0" From 55d8a988c032c222343afb0379f34d04f148dd52 Mon Sep 17 00:00:00 2001 From: Adolar0042 <39769465+Adolar0042@users.noreply.github.com> Date: Tue, 12 Dec 2023 18:13:16 +0100 Subject: [PATCH 02/13] feat: Version data class --- .../main/java/com/chouten/app/MainActivity.kt | 4 +- .../java/com/chouten/app/common/Extensions.kt | 33 ----- .../app/domain/model/SemanticVersion.kt | 118 ++++++++++++++++++ .../module_use_cases/AddModuleUseCase.kt | 74 +++++------ 4 files changed, 149 insertions(+), 80 deletions(-) create mode 100644 app/src/main/java/com/chouten/app/domain/model/SemanticVersion.kt diff --git a/app/src/main/java/com/chouten/app/MainActivity.kt b/app/src/main/java/com/chouten/app/MainActivity.kt index b7e15ca..8b85abf 100644 --- a/app/src/main/java/com/chouten/app/MainActivity.kt +++ b/app/src/main/java/com/chouten/app/MainActivity.kt @@ -12,11 +12,11 @@ import androidx.compose.material.icons.filled.Warning import androidx.compose.runtime.SideEffect import androidx.core.net.toUri import androidx.lifecycle.ViewModelProvider -import com.chouten.app.common.compareSemVer import com.chouten.app.common.findActivity import com.chouten.app.domain.model.AlertDialogModel import com.chouten.app.domain.model.LogEntry import com.chouten.app.domain.model.SnackbarModel +import com.chouten.app.domain.model.Version import com.chouten.app.domain.proto.moduleDatastore import com.chouten.app.domain.use_case.log_use_cases.LogUseCases import com.chouten.app.domain.use_case.module_use_cases.ModuleInstallEvent @@ -83,7 +83,7 @@ class MainActivity : ComponentActivity() { moduleUseCases.addModule(updateUrl.toUri()) { event -> when (event) { is ModuleInstallEvent.PARSED -> { - (event.module.version.compareSemVer(module.version) != 1).also { res -> + (Version(event.module.version) < Version(module.version)).also { res -> if (!res) { appState.viewModel.runAsync { logUseCases.insertLog( diff --git a/app/src/main/java/com/chouten/app/common/Extensions.kt b/app/src/main/java/com/chouten/app/common/Extensions.kt index a1de656..ea1a2cf 100644 --- a/app/src/main/java/com/chouten/app/common/Extensions.kt +++ b/app/src/main/java/com/chouten/app/common/Extensions.kt @@ -198,36 +198,3 @@ internal fun scale( */ fun calculateFraction(start: Float, end: Float, pos: Float) = (if (end - start == 0f) 0f else (pos - start) / (end - start)).coerceIn(0f, 1f) - -/** - * Compare two semVer versions - * @param v2 The second version - * @return 1 if the first version is newer, -1 if the second version is newer, 0 if the versions are the same - * @throws IllegalArgumentException if the versions are invalid - */ -fun String.compareSemVer(v2: String): Int { - // Return 1 if the first version is newer - // Return -1 if the second version is newer - // Return 0 if the versions are the same - val v1Split = split(".") - val v2Split = v2.split(".") - if (v1Split.size != 3 || v2Split.size != 3) { - throw IllegalArgumentException("Invalid version") - } - - return if (v1Split[0].toInt() > v2Split[0].toInt()) { - 1 - } else if (v1Split[0].toInt() < v2Split[0].toInt()) { - -1 - } else if (v1Split[1].toInt() > v2Split[1].toInt()) { - 1 - } else if (v1Split[1].toInt() < v2Split[1].toInt()) { - -1 - } else if (v1Split[2].toInt() > v2Split[2].toInt()) { - 1 - } else if (v1Split[2].toInt() < v2Split[2].toInt()) { - -1 - } else { - 0 - } -} \ No newline at end of file diff --git a/app/src/main/java/com/chouten/app/domain/model/SemanticVersion.kt b/app/src/main/java/com/chouten/app/domain/model/SemanticVersion.kt new file mode 100644 index 0000000..1377d23 --- /dev/null +++ b/app/src/main/java/com/chouten/app/domain/model/SemanticVersion.kt @@ -0,0 +1,118 @@ +package com.chouten.app.domain.model + +/** + * Represents a semantic version number. + * + * @property major The major version number, used to indicate incompatible API changes. + * @property minor The minor version number, used to indicate new, but backwards compatible, functionality. + * @property patch The patch version number, used to indicate backwards compatible bug fixes and small changes. + * @property preRelease The pre-release identifier. + * @property buildMetadata The build metadata. + */ +data class Version( + var major: Int, + var minor: Int, + var patch: Int, + var preRelease: String = "", + var buildMetadata: String = "" +) : Comparable { + + /** + * Creates a [Version] object from a version string. + * + * @param versionString The version string to parse. + * @param useRegex Flag to determine whether to use regex for parsing. + * Not using regex is stricter and will throw an exception for more invalid strings. + * @throws IllegalArgumentException If the version string is not valid. + */ + constructor(versionString: String, useRegex: Boolean = false) : this( + major = 0, minor = 0, patch = 0 + ) { + val parsedVersion = parse(versionString, useRegex) + major = parsedVersion.major + minor = parsedVersion.minor + patch = parsedVersion.patch + preRelease = parsedVersion.preRelease + buildMetadata = parsedVersion.buildMetadata + } + + companion object { + private val SEMVER_REGEX = Regex( + "(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?" + ) + + /** + * Parses a version string into a [Version] object. + * + * @param versionString The version string to parse. + * @param useRegex Flag to determine whether to use regex for parsing. + * Not using regex is stricter and will throw an exception for more invalid strings. + * @return The parsed [Version] object. + * @throws IllegalArgumentException If the version string is not valid. + */ + fun parse(versionString: String, useRegex: Boolean = false): Version { + if (useRegex) { + val matchResult = SEMVER_REGEX.matchEntire(versionString) + ?: throw IllegalArgumentException("Invalid semantic version format") + + return Version( + major = matchResult.groupValues[1].toInt(), + minor = matchResult.groupValues[2].toInt(), + patch = matchResult.groupValues[3].toInt(), + preRelease = matchResult.groupValues[4], + buildMetadata = matchResult.groupValues[5] + ) + } else { + val metadataSplit = versionString.split("+", limit = 2) + val mainPart = metadataSplit[0] + val buildMetadata = if (metadataSplit.size > 1) metadataSplit[1] else "" + + val preReleaseSplit = mainPart.split("-", limit = 2) + val numbers = preReleaseSplit[0].split(".") + val preRelease = if (preReleaseSplit.size > 1) preReleaseSplit[1] else "" + + if (numbers.size != 3) { + throw IllegalArgumentException("Invalid version format. Expected format: MAJOR.MINOR.PATCH") + } + + val major = numbers[0].toIntOrNull() + ?: throw IllegalArgumentException("Major version is not a valid integer") + val minor = numbers[1].toIntOrNull() + ?: throw IllegalArgumentException("Minor version is not a valid integer") + val patch = numbers[2].toIntOrNull() + ?: throw IllegalArgumentException("Patch version is not a valid integer") + + return Version(major, minor, patch, preRelease, buildMetadata) + } + } + } + + /** + * Compares this version with the specified version for order. + * + * @param other The [Version] to be compared. + * @return A negative integer if this version is less than the other version, + * zero if they are equal or a positive integer if this version is greater than the other version. + */ + override fun compareTo(other: Version): Int { + if (this.major != other.major) return this.major - other.major + if (this.minor != other.minor) return this.minor - other.minor + if (this.patch != other.patch) return this.patch - other.patch + if (this.preRelease != other.preRelease) { + if (this.preRelease.isEmpty()) return 1 + if (other.preRelease.isEmpty()) return -1 + return this.preRelease.compareTo(other.preRelease) + } + // Note: Build metadata does not affect version precedence + return 0 + } + + /** + * Returns a string representation of the version. + */ + override fun toString(): String { + return "$major.$minor.$patch" + + (if (preRelease.isNotEmpty()) "-$preRelease" else "") + + (if (buildMetadata.isNotEmpty()) "+$buildMetadata" else "") + } +} diff --git a/app/src/main/java/com/chouten/app/domain/use_case/module_use_cases/AddModuleUseCase.kt b/app/src/main/java/com/chouten/app/domain/use_case/module_use_cases/AddModuleUseCase.kt index d5bb02e..eb14e15 100644 --- a/app/src/main/java/com/chouten/app/domain/use_case/module_use_cases/AddModuleUseCase.kt +++ b/app/src/main/java/com/chouten/app/domain/use_case/module_use_cases/AddModuleUseCase.kt @@ -9,8 +9,8 @@ import androidx.core.net.toUri import androidx.documentfile.provider.DocumentFile import com.chouten.app.common.OutOfDateAppException import com.chouten.app.common.OutOfDateModuleException -import com.chouten.app.common.compareSemVer import com.chouten.app.domain.model.ModuleModel +import com.chouten.app.domain.model.Version import com.chouten.app.domain.proto.filepathDatastore import com.chouten.app.domain.repository.ModuleRepository import com.lagradost.nicehttp.Requests @@ -339,57 +339,41 @@ class AddModuleUseCase @Inject constructor( log("Comparing module ${module.id} (${module.version}) with ${it.second.id} (${it.second.version})") // Check if the module already exists if (module.id == it.second.id) { - val ret: Int = try { - module.version.compareSemVer(it.second.version) + val oldModuleVersion: Version = try { + Version(module.version) } catch (e: IllegalArgumentException) { - // Find which module has the invalid version - try { - "0.0.0".compareSemVer(module.version) - } catch (e: IllegalArgumentException) { - // The module being installed has an invalid version - e.printStackTrace() - safeException(e, newModuleUri) - } - - try { - "0.0.0".compareSemVer(it.second.version) - } catch (e: IllegalArgumentException) { - e.printStackTrace() - // The existing module has an invalid version - // We can make a note of it and let the module be installed - log("Module ${it.second.name} (${it.second.id}) has an invalid version (${it.second.version})") - 1 - } + e.printStackTrace() + safeException(e, newModuleUri) + } + val newModuleVersion: Version = try { + Version(it.second.version) + } catch (e: IllegalArgumentException) { + e.printStackTrace() + // The new module has an invalid version + log("Module ${it.second.name} (${it.second.id}) has an invalid version (${it.second.version})") + safeException(e, newModuleUri) } - when (ret) { - // Module being installed is newer than the existing module - 1 -> { - // Delete the old module - if (DocumentFile.fromSingleUri(mContext, it.first)?.delete() == false) { - safeException( - IOException("Could not delete module ${it.second.name} (${it.second.id})"), - newModuleUri - ) - } - log("Updated module ${module.name} (${module.id})") - } - - // Module being installed is the same version as the existing module - 0 -> { - safeException( - IllegalArgumentException("Module ${module.name} (${module.id}) already exists"), - newModuleUri - ) - } - - // Module being installed is older than the existing module - else -> { + if (oldModuleVersion < newModuleVersion) { + // Delete the old module + if (DocumentFile.fromSingleUri(mContext, it.first)?.delete() == false) { safeException( - IllegalArgumentException("Module ${module.name} (${module.id}) is older than the existing module"), + IOException("Could not delete module ${it.second.name} (${it.second.id})"), newModuleUri ) } + log("Updated module ${module.name} (${module.id})") + } + if (oldModuleVersion == newModuleVersion) { + safeException( + IllegalArgumentException("Module ${module.name} (${module.id}) already exists"), + newModuleUri + ) + } else if (oldModuleVersion > newModuleVersion){ + safeException( + IllegalArgumentException("Module ${module.name} (${module.id}) is older than the existing module"), + newModuleUri + ) } } } From 79748fd8cd5791c1ce9f7338725168224316aac5 Mon Sep 17 00:00:00 2001 From: Adolar0042 <39769465+Adolar0042@users.noreply.github.com> Date: Fri, 15 Dec 2023 11:12:56 +0100 Subject: [PATCH 03/13] dep(gradle): upgrade version alpha11 -> alpha17 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5f1dcc0..ef930b4 100755 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agp = "8.3.0-alpha11" +agp = "8.3.0-alpha17" acraHttp = "5.11.3" autoService = "1.1.1" coilCompose = "2.4.0" From 370fd5f24316d2c28ee66b22d8ccb35a22d02f6a Mon Sep 17 00:00:00 2001 From: Adolar0042 <39769465+Adolar0042@users.noreply.github.com> Date: Fri, 15 Dec 2023 11:13:16 +0100 Subject: [PATCH 04/13] feat(Version): String.toVersion() --- .../main/java/com/chouten/app/common/Extensions.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/java/com/chouten/app/common/Extensions.kt b/app/src/main/java/com/chouten/app/common/Extensions.kt index ea1a2cf..f538564 100644 --- a/app/src/main/java/com/chouten/app/common/Extensions.kt +++ b/app/src/main/java/com/chouten/app/common/Extensions.kt @@ -12,6 +12,7 @@ import androidx.compose.material3.ColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.graphics.Color +import com.chouten.app.domain.model.Version import com.chouten.app.domain.proto.AppearancePreferences import com.chouten.app.domain.proto.appearanceDatastore import kotlinx.coroutines.flow.firstOrNull @@ -198,3 +199,15 @@ internal fun scale( */ fun calculateFraction(start: Float, end: Float, pos: Float) = (if (end - start == 0f) 0f else (pos - start) / (end - start)).coerceIn(0f, 1f) + +/** + * Parses a version string into a [Version] object. + * + * @param useRegex Flag to determine whether to use regex for parsing. + * Not using regex is stricter and will throw an exception for more invalid strings. + * @return The parsed [Version] object. + * @throws IllegalArgumentException If the version string is not valid. + */ +fun String.toVersion(useRegex: Boolean = false): Version { + return Version(this, useRegex) +} \ No newline at end of file From 884b82199dea3a318af71edbe56861a66ef4e630 Mon Sep 17 00:00:00 2001 From: Adolar0042 <39769465+Adolar0042@users.noreply.github.com> Date: Fri, 15 Dec 2023 15:31:22 +0100 Subject: [PATCH 05/13] feat(Version): hashCode and equals --- .../java/com/chouten/app/common/Extensions.kt | 4 +- .../app/domain/model/SemanticVersion.kt | 42 ++++++++++++++++++- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/chouten/app/common/Extensions.kt b/app/src/main/java/com/chouten/app/common/Extensions.kt index f538564..e8aa468 100644 --- a/app/src/main/java/com/chouten/app/common/Extensions.kt +++ b/app/src/main/java/com/chouten/app/common/Extensions.kt @@ -208,6 +208,4 @@ fun calculateFraction(start: Float, end: Float, pos: Float) = * @return The parsed [Version] object. * @throws IllegalArgumentException If the version string is not valid. */ -fun String.toVersion(useRegex: Boolean = false): Version { - return Version(this, useRegex) -} \ No newline at end of file +fun String.toVersion(useRegex: Boolean = false) = Version(this, useRegex) \ No newline at end of file diff --git a/app/src/main/java/com/chouten/app/domain/model/SemanticVersion.kt b/app/src/main/java/com/chouten/app/domain/model/SemanticVersion.kt index 1377d23..2eede4b 100644 --- a/app/src/main/java/com/chouten/app/domain/model/SemanticVersion.kt +++ b/app/src/main/java/com/chouten/app/domain/model/SemanticVersion.kt @@ -101,12 +101,52 @@ data class Version( if (this.preRelease != other.preRelease) { if (this.preRelease.isEmpty()) return 1 if (other.preRelease.isEmpty()) return -1 - return this.preRelease.compareTo(other.preRelease) + // Split preRelease strings and compare them part by part. + val thisPreReleaseParts = this.preRelease.split(".") + val otherPreReleaseParts = other.preRelease.split(".") + val maxIndex = minOf(thisPreReleaseParts.size, otherPreReleaseParts.size) + for (i in 0 until maxIndex) { + val cmp = thisPreReleaseParts[i].compareTo(otherPreReleaseParts[i]) + if (cmp != 0) return cmp + } + return thisPreReleaseParts.size - otherPreReleaseParts.size } // Note: Build metadata does not affect version precedence return 0 } + /** + * Checks if this version is equal to the specified version. + * + * @param other The [Version] to compare. + * @return `true` if the versions are equal, `false` otherwise. + */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Version + + if (major != other.major) return false + if (minor != other.minor) return false + if (patch != other.patch) return false + if (preRelease != other.preRelease) return false + + return true + } + + /** + * @return a hash code value for the version. + */ + override fun hashCode(): Int { + var result = major + result = 31 * result + minor + result = 31 * result + patch + result = 31 * result + preRelease.hashCode() + result = 31 * result + buildMetadata.hashCode() + return result + } + /** * Returns a string representation of the version. */ From 191997149338963688fad076cd737a02b59e625f Mon Sep 17 00:00:00 2001 From: Adolar0042 <39769465+Adolar0042@users.noreply.github.com> Date: Fri, 22 Dec 2023 14:56:22 +0100 Subject: [PATCH 06/13] feat: made version class serializable this is untested due to an unrelated crash on app startup --- .../main/java/com/chouten/app/MainActivity.kt | 2 +- .../chouten/app/domain/model/ModuleModel.kt | 2 +- .../app/domain/model/SemanticVersion.kt | 25 ++++++++++ .../module_use_cases/AddModuleUseCase.kt | 49 ++++++++----------- 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/chouten/app/MainActivity.kt b/app/src/main/java/com/chouten/app/MainActivity.kt index 8b85abf..50fb90a 100644 --- a/app/src/main/java/com/chouten/app/MainActivity.kt +++ b/app/src/main/java/com/chouten/app/MainActivity.kt @@ -83,7 +83,7 @@ class MainActivity : ComponentActivity() { moduleUseCases.addModule(updateUrl.toUri()) { event -> when (event) { is ModuleInstallEvent.PARSED -> { - (Version(event.module.version) < Version(module.version)).also { res -> + (event.module.version < module.version).also { res -> if (!res) { appState.viewModel.runAsync { logUseCases.insertLog( diff --git a/app/src/main/java/com/chouten/app/domain/model/ModuleModel.kt b/app/src/main/java/com/chouten/app/domain/model/ModuleModel.kt index 0fa2259..fb5b0b3 100644 --- a/app/src/main/java/com/chouten/app/domain/model/ModuleModel.kt +++ b/app/src/main/java/com/chouten/app/domain/model/ModuleModel.kt @@ -47,7 +47,7 @@ data class ModuleModel( * The version of the module. * This is used to identify the module in the app. */ - val version: String, + val version: Version, /** * The format version for the code of the module. diff --git a/app/src/main/java/com/chouten/app/domain/model/SemanticVersion.kt b/app/src/main/java/com/chouten/app/domain/model/SemanticVersion.kt index 2eede4b..753a1f1 100644 --- a/app/src/main/java/com/chouten/app/domain/model/SemanticVersion.kt +++ b/app/src/main/java/com/chouten/app/domain/model/SemanticVersion.kt @@ -1,5 +1,29 @@ package com.chouten.app.domain.model +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +/** + * Serializer for [Version]. + */ +object VersionAsStringSerializer : KSerializer { + override val descriptor: SerialDescriptor = + PrimitiveSerialDescriptor("Version", PrimitiveKind.STRING) + + override fun serialize(encoder: Encoder, value: Version) { + return encoder.encodeString(value.toString()) + } + + override fun deserialize(decoder: Decoder): Version { + return Version(decoder.decodeString()) + } +} + /** * Represents a semantic version number. * @@ -9,6 +33,7 @@ package com.chouten.app.domain.model * @property preRelease The pre-release identifier. * @property buildMetadata The build metadata. */ +@Serializable(with = VersionAsStringSerializer::class) data class Version( var major: Int, var minor: Int, diff --git a/app/src/main/java/com/chouten/app/domain/use_case/module_use_cases/AddModuleUseCase.kt b/app/src/main/java/com/chouten/app/domain/use_case/module_use_cases/AddModuleUseCase.kt index eb14e15..6849556 100644 --- a/app/src/main/java/com/chouten/app/domain/use_case/module_use_cases/AddModuleUseCase.kt +++ b/app/src/main/java/com/chouten/app/domain/use_case/module_use_cases/AddModuleUseCase.kt @@ -10,7 +10,6 @@ import androidx.documentfile.provider.DocumentFile import com.chouten.app.common.OutOfDateAppException import com.chouten.app.common.OutOfDateModuleException import com.chouten.app.domain.model.ModuleModel -import com.chouten.app.domain.model.Version import com.chouten.app.domain.proto.filepathDatastore import com.chouten.app.domain.repository.ModuleRepository import com.lagradost.nicehttp.Requests @@ -216,17 +215,25 @@ class AddModuleUseCase @Inject constructor( /** * The parsed module */ - val module = metadataInputStream.use { - val stringBuffer = StringBuffer() - it.bufferedReader().use { reader -> - var line = reader.readLine() - while (line != null) { - stringBuffer.append(line) - line = reader.readLine() + val module = try { + metadataInputStream.use { + val stringBuffer = StringBuffer() + it.bufferedReader().use { reader -> + var line = reader.readLine() + while (line != null) { + stringBuffer.append(line) + line = reader.readLine() + } } - } - jsonParser(stringBuffer.toString()) + jsonParser(stringBuffer.toString()) + } + } catch (e: Exception) { + e.printStackTrace() + safeException( + IllegalArgumentException("Could not parse module", e), + newModuleUri + ) } if (callback(ModuleInstallEvent.PARSED(module))) { @@ -338,23 +345,9 @@ class AddModuleUseCase @Inject constructor( metadataUriPairs.forEach { log("Comparing module ${module.id} (${module.version}) with ${it.second.id} (${it.second.version})") // Check if the module already exists + // TODO: check how the error is handled if the module version is invalid, this was previously done here, now idk if (module.id == it.second.id) { - val oldModuleVersion: Version = try { - Version(module.version) - } catch (e: IllegalArgumentException) { - e.printStackTrace() - safeException(e, newModuleUri) - } - val newModuleVersion: Version = try { - Version(it.second.version) - } catch (e: IllegalArgumentException) { - e.printStackTrace() - // The new module has an invalid version - log("Module ${it.second.name} (${it.second.id}) has an invalid version (${it.second.version})") - safeException(e, newModuleUri) - } - - if (oldModuleVersion < newModuleVersion) { + if (module.version < it.second.version) { // old module version < new module version // Delete the old module if (DocumentFile.fromSingleUri(mContext, it.first)?.delete() == false) { safeException( @@ -364,12 +357,12 @@ class AddModuleUseCase @Inject constructor( } log("Updated module ${module.name} (${module.id})") } - if (oldModuleVersion == newModuleVersion) { + if (module.version == it.second.version) { // old module version == new module version safeException( IllegalArgumentException("Module ${module.name} (${module.id}) already exists"), newModuleUri ) - } else if (oldModuleVersion > newModuleVersion){ + } else if (module.version > it.second.version) { // old module version > new module version safeException( IllegalArgumentException("Module ${module.name} (${module.id}) is older than the existing module"), newModuleUri From ed7c7f4a7ada9f20cd0e699fccb5185fbc4243cd Mon Sep 17 00:00:00 2001 From: Toby Bridle Date: Fri, 12 Jan 2024 13:54:33 +0000 Subject: [PATCH 07/13] =?UTF-8?q?fix:=20=F0=9F=90=9B=20crash=20when=20docu?= =?UTF-8?q?ment=20dir=20is=20blank?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/data/repository/ModuleRepositoryImpl.kt | 1 + app/src/main/java/com/chouten/app/di/AppModule.kt | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/chouten/app/data/repository/ModuleRepositoryImpl.kt b/app/src/main/java/com/chouten/app/data/repository/ModuleRepositoryImpl.kt index 974c86d..4281547 100644 --- a/app/src/main/java/com/chouten/app/data/repository/ModuleRepositoryImpl.kt +++ b/app/src/main/java/com/chouten/app/data/repository/ModuleRepositoryImpl.kt @@ -31,6 +31,7 @@ class ModuleRepositoryImpl @Inject constructor( override suspend fun getModuleDirs(): List { val preferences = context.filepathDatastore.data.first() + if (preferences.CHOUTEN_ROOT_DIR == Uri.EMPTY) return emptyList() val contentResolver = context.contentResolver return withContext(Dispatchers.IO) { diff --git a/app/src/main/java/com/chouten/app/di/AppModule.kt b/app/src/main/java/com/chouten/app/di/AppModule.kt index 63042c4..3779baa 100644 --- a/app/src/main/java/com/chouten/app/di/AppModule.kt +++ b/app/src/main/java/com/chouten/app/di/AppModule.kt @@ -124,9 +124,13 @@ object AppModule { @Provides fun provideModuleRepository(app: Application, httpClient: Requests): ModuleRepository { val moduleDirGetter: suspend (Uri) -> Uri = { uri: Uri -> - GetModuleDirUseCase( - app.applicationContext - )(uri) + try { + GetModuleDirUseCase( + app.applicationContext + )(uri) + } catch (e: Exception) { + Uri.EMPTY + } } return ModuleRepositoryImpl(app.applicationContext, moduleDirGetter) } From e080e7212595e4e650f84c9dd91027243efff60e Mon Sep 17 00:00:00 2001 From: Toby Bridle Date: Fri, 12 Jan 2024 13:56:52 +0000 Subject: [PATCH 08/13] =?UTF-8?q?chore(version):=20=F0=9F=94=A7=20update?= =?UTF-8?q?=20version=20&=20code=20(10=20->=2011)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b697a17..d250aa3 100755 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -35,8 +35,8 @@ android { applicationId = "com.chouten.app" minSdk = 23 targetSdk = 34 - versionCode = 10 - versionName = "0.3.0" + versionCode = 11 + versionName = "0.3.1" buildConfigField("String", "WEBHOOK_URL", "\"${properties.getProperty("bug_webhook")}\"") testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" From 8d644e32ab38791384db04594afb4c5421c00224 Mon Sep 17 00:00:00 2001 From: Adolar0042 <39769465+Adolar0042@users.noreply.github.com> Date: Sat, 30 Dec 2023 17:33:13 +0100 Subject: [PATCH 09/13] chore(typo): fixed typos --- app/src/main/java/com/chouten/app/common/Extensions.kt | 2 +- app/src/main/java/com/chouten/app/common/TimeUtils.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/chouten/app/common/Extensions.kt b/app/src/main/java/com/chouten/app/common/Extensions.kt index e8aa468..b886271 100644 --- a/app/src/main/java/com/chouten/app/common/Extensions.kt +++ b/app/src/main/java/com/chouten/app/common/Extensions.kt @@ -138,7 +138,7 @@ fun Long.formatMinSec(): String { return if (this <= 0L) { "00:00" } else { - // Format HH:MM::SS or MM:SS if hours is 0 + // Format HH:MM:SS or MM:SS if hours is 0 if (TimeUnit.MILLISECONDS.toHours(this) > 0) { String.format( "%02d:%02d:%02d", diff --git a/app/src/main/java/com/chouten/app/common/TimeUtils.kt b/app/src/main/java/com/chouten/app/common/TimeUtils.kt index 6aa8611..df78172 100644 --- a/app/src/main/java/com/chouten/app/common/TimeUtils.kt +++ b/app/src/main/java/com/chouten/app/common/TimeUtils.kt @@ -9,9 +9,9 @@ import java.util.Locale import java.util.TimeZone /** - * Converts epoch seconds to a formatted time string. + * Converts epoch milliseconds to a formatted time string. * - * @param epochMilli The epoch time in seconds. + * @param epochMilli The epoch time in milliseconds. * @param pattern The desired pattern for formatting the time (default is "h:mm:ss"). * @return The formatted time string of [epochMilli] in the pattern of [pattern]. */ From a2769f87714f759adb59627893635bd4f14c8cf7 Mon Sep 17 00:00:00 2001 From: Adolar0042 <39769465+Adolar0042@users.noreply.github.com> Date: Thu, 18 Jan 2024 21:30:45 +0100 Subject: [PATCH 10/13] deps: upgrade versions --- gradle/libs.versions.toml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ef930b4..022d90a 100755 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agp = "8.3.0-alpha17" +agp = "8.3.0-beta02" acraHttp = "5.11.3" autoService = "1.1.1" coilCompose = "2.4.0" @@ -7,22 +7,22 @@ core = "1.9.42-beta" datastore = "1.0.0" dynamictheme = "1.0.3" documentfile = "1.0.1" -hiltNavigationCompose = "1.0.0" -kotlin = "1.9.0" +hiltNavigationCompose = "1.1.0" +kotlin = "1.9.21" core-ktx = "1.12.0" junit = "4.13.2" androidx-test-ext-junit = "1.1.5" espresso-core = "3.5.1" -kotlinxSerializationJson = "1.5.1" -lifecycle-runtime-ktx = "2.6.2" -activity-compose = "1.8.0" +kotlinxSerializationJson = "1.6.2" +lifecycle-runtime-ktx = "2.7.0" +activity-compose = "1.8.2" compose-bom = "2023.10.01" daggerHilt = "2.46.1" materialIconsExtended = "1.5.4" -ksp = "1.9.0-1.0.13" # Depends on your kotlin version -media3Exoplayer = "1.1.1" -roomRuntime = "2.6.0" -serialization = "1.9.0" +ksp = "1.9.21-1.0.16" # Depends on your kotlin version +media3Exoplayer = "1.2.1" +roomRuntime = "2.6.1" +serialization = "1.9.21" nicehttp = "+" [libraries] From 9a3aefe6834e336611d1091290b801ead0ce1dde Mon Sep 17 00:00:00 2001 From: Adolar0042 <39769465+Adolar0042@users.noreply.github.com> Date: Thu, 18 Jan 2024 21:31:23 +0100 Subject: [PATCH 11/13] fix(module): fix version comparison --- .../domain/use_case/module_use_cases/AddModuleUseCase.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/chouten/app/domain/use_case/module_use_cases/AddModuleUseCase.kt b/app/src/main/java/com/chouten/app/domain/use_case/module_use_cases/AddModuleUseCase.kt index 6849556..f86b2d8 100644 --- a/app/src/main/java/com/chouten/app/domain/use_case/module_use_cases/AddModuleUseCase.kt +++ b/app/src/main/java/com/chouten/app/domain/use_case/module_use_cases/AddModuleUseCase.kt @@ -347,22 +347,22 @@ class AddModuleUseCase @Inject constructor( // Check if the module already exists // TODO: check how the error is handled if the module version is invalid, this was previously done here, now idk if (module.id == it.second.id) { - if (module.version < it.second.version) { // old module version < new module version + if (module.version > it.second.version) { // new module version > old module version // Delete the old module if (DocumentFile.fromSingleUri(mContext, it.first)?.delete() == false) { safeException( IOException("Could not delete module ${it.second.name} (${it.second.id})"), - newModuleUri + it.first ) } log("Updated module ${module.name} (${module.id})") } - if (module.version == it.second.version) { // old module version == new module version + if (module.version == it.second.version) { // new module version == old module version safeException( IllegalArgumentException("Module ${module.name} (${module.id}) already exists"), newModuleUri ) - } else if (module.version > it.second.version) { // old module version > new module version + } else if (module.version < it.second.version) { // new module version < old module version safeException( IllegalArgumentException("Module ${module.name} (${module.id}) is older than the existing module"), newModuleUri From d49e3ede4df28c5e10c351645423d864b26c961d Mon Sep 17 00:00:00 2001 From: Adolar0042 <39769465+Adolar0042@users.noreply.github.com> Date: Thu, 18 Jan 2024 21:32:33 +0100 Subject: [PATCH 12/13] feat(timeUtils): Long to Time String --- app/src/main/java/com/chouten/app/common/TimeUtils.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/src/main/java/com/chouten/app/common/TimeUtils.kt b/app/src/main/java/com/chouten/app/common/TimeUtils.kt index df78172..f0dc264 100644 --- a/app/src/main/java/com/chouten/app/common/TimeUtils.kt +++ b/app/src/main/java/com/chouten/app/common/TimeUtils.kt @@ -28,4 +28,15 @@ fun epochMillisToTime(epochMilli: Long, pattern: String = "HH:mm:ss"): String { timeZone = userTimeZone }.format(Date(epochMilli)) } +} + +/** + * Converts epoch milliseconds to a formatted time string. + * + * @param epochMilli The epoch time in milliseconds. + * @param pattern The desired pattern for formatting the time (default is "h:mm:ss"). + * @return The formatted time string of [epochMilli] in the pattern of [pattern]. + */ +fun Long.toTimeString(pattern: String = "HH:mm:ss"): String { + return epochMillisToTime(this, pattern) } \ No newline at end of file From 9762bc0aea67d09edadc737cac80a557942ce373 Mon Sep 17 00:00:00 2001 From: Adolar0042 <39769465+Adolar0042@users.noreply.github.com> Date: Thu, 18 Jan 2024 21:50:23 +0100 Subject: [PATCH 13/13] Revert "deps: upgrade versions" This reverts commit a2769f87714f759adb59627893635bd4f14c8cf7. --- gradle/libs.versions.toml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 022d90a..ef930b4 100755 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agp = "8.3.0-beta02" +agp = "8.3.0-alpha17" acraHttp = "5.11.3" autoService = "1.1.1" coilCompose = "2.4.0" @@ -7,22 +7,22 @@ core = "1.9.42-beta" datastore = "1.0.0" dynamictheme = "1.0.3" documentfile = "1.0.1" -hiltNavigationCompose = "1.1.0" -kotlin = "1.9.21" +hiltNavigationCompose = "1.0.0" +kotlin = "1.9.0" core-ktx = "1.12.0" junit = "4.13.2" androidx-test-ext-junit = "1.1.5" espresso-core = "3.5.1" -kotlinxSerializationJson = "1.6.2" -lifecycle-runtime-ktx = "2.7.0" -activity-compose = "1.8.2" +kotlinxSerializationJson = "1.5.1" +lifecycle-runtime-ktx = "2.6.2" +activity-compose = "1.8.0" compose-bom = "2023.10.01" daggerHilt = "2.46.1" materialIconsExtended = "1.5.4" -ksp = "1.9.21-1.0.16" # Depends on your kotlin version -media3Exoplayer = "1.2.1" -roomRuntime = "2.6.1" -serialization = "1.9.21" +ksp = "1.9.0-1.0.13" # Depends on your kotlin version +media3Exoplayer = "1.1.1" +roomRuntime = "2.6.0" +serialization = "1.9.0" nicehttp = "+" [libraries]