Loading domain/src/main/java/foundation/e/apps/domain/ResultSupreme.kt 0 → 100644 +194 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 ECORP * * 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.domain import foundation.e.apps.domain.enums.ResultStatus import java.util.concurrent.TimeoutException private const val UNKNOWN_ERROR = "Unknown error!" /** * Another implementation of Result class. * This removes the use of [ResultStatus] class for different status. * This class also follows the standard code patterns. However, we still have the same * flaw that [data] is nullable. As such we may have to add extra null checks or just * brute force with !! * * Also since for each case we now use an inner class with slightly different name, * we need some refactoring. * * Issue: https://gitlab.e.foundation/e/os/backlog/-/issues/313 */ sealed class ResultSupreme<T> { /** * Success case. * Use [isSuccess] to check. * * @param data End result of processing. */ class Success<T>(data: T) : ResultSupreme<T>() { init { setData(data) } } /** * Timed out during network related job. * Use [isTimeout] to check. * * @param data The process is expected to output some blank data, but it cannot be null. * Example can be an empty list. * @param exception Optional exception from try-catch block. */ class Timeout<T>(data: T? = null, exception: Exception = TimeoutException()) : ResultSupreme<T>() { init { data?.let { setData(it) } this.exception = exception } } /** * Miscellaneous error case. * No valid data from processing. * Use [isUnknownError] to check. */ open class Error<T>() : ResultSupreme<T>() { /** * @param message A String message to log or display to the user. * @param exception Optional exception from try-catch block. */ constructor(message: String, exception: Exception? = null) : this() { this.message = message this.exception = exception } /** * @param data Non-null data. Example a String which could not be parsed into a JSON. * @param message A optional String message to log or display to the user. */ constructor(data: T, message: String = "") : this() { setData(data) this.message = message } } class WorkError<T> constructor(data: T, payload: Any? = null) : Error<T>(data) { init { this.otherPayload = payload } } /** * Data from processing. May be null. */ var data: T? = null private set /** * A custom string message for logging or displaying to the user. */ var message: String = "" var otherPayload: Any? = null /** * Exception from try-catch block for error cases. */ var exception: Exception? = null fun isValidData() = data != null fun isSuccess() = this is Success && isValidData() fun isTimeout() = this is Timeout fun isUnknownError() = this is Error fun setData(data: T) { this.data = data } fun getResultStatus(): ResultStatus { return when (this) { is Success -> ResultStatus.OK is Timeout -> ResultStatus.TIMEOUT else -> ResultStatus.UNKNOWN.apply { message = this@ResultSupreme.exception?.localizedMessage ?: UNKNOWN_ERROR } } } companion object { /** * Function to create an instance of ResultSupreme from a [ResultStatus] status, * and other available info - [data], [message], [exception]. */ fun <T> create( status: ResultStatus, data: T? = null, message: String = "", exception: Exception? = null, ): ResultSupreme<T> { val resultObject = when { status == ResultStatus.OK && data != null -> Success<T>(data) status == ResultStatus.TIMEOUT && data != null -> Timeout<T>(data) else -> Error(message.ifBlank { status.message }, exception) } resultObject.apply { if (isUnknownError()) { this.data = data } else { this.message = message.ifBlank { status.message } this.exception = exception } } return resultObject } /** * Create a similar [ResultSupreme] instance i.e. of type [Success], [Timeout]... * using a supplied [result] object but with a different generic type and new data. * * @param result Class of [ResultSupreme] whose replica is to be made. * @param newData Nullable new data for this replica. * @param message Optional new message for this replica. If not provided, * the new object will get the message from [result]. * @param exception Optional new exception for this replica. If not provided, * the new object will get the exception from [result]. */ fun <T> replicate( result: ResultSupreme<*>, newData: T?, message: String? = null, exception: Exception? = null, ): ResultSupreme<T> { val status = when (result) { is Success -> ResultStatus.OK is Timeout -> ResultStatus.TIMEOUT is Error -> ResultStatus.UNKNOWN } return create( status, newData, message ?: result.message, exception ?: result.exception ) } } } domain/src/main/java/foundation/e/apps/domain/cleanapk/CleanApkConstants.kt 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2026 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.domain.cleanapk object CleanApkConstants { const val BASE_URL = "https://api.cleanapk.org/v2/" const val ASSET_URL = "https://api.cleanapk.org/v2/media/" const val APP_SOURCE_FOSS = "open" const val APP_SOURCE_ANY = "any" const val APP_TYPE_NATIVE = "native" const val APP_TYPE_PWA = "pwa" const val APP_TYPE_ANY = "any" } domain/src/main/java/foundation/e/apps/domain/enums/AppTag.kt 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019-2022 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.domain.enums /** * This sealed class is used for the tags shown in the categories screen, * the [displayTag] holds the tag in the user device specific locale. * (Example: [OpenSource.displayTag] for Deutsch language = "Quelloffen") * * Previously this was hard coded, which led to crashes due to changes in different locales. * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5364 */ sealed class AppTag(val displayTag: String) { class OpenSource(displayTag: String) : AppTag(displayTag) class PWA(displayTag: String) : AppTag(displayTag) class GPlay(displayTag: String = "") : AppTag(displayTag) /** * In many places in the code, checks are for hard coded string "Open Source". * This method allows for all those check to work without modification. */ fun getOperationalTag(): String { return if (this is OpenSource) { "Open Source" } else { this::class.java.simpleName } } } domain/src/main/java/foundation/e/apps/domain/enums/FilterLevel.kt 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019-2022 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.domain.enums /** * Use this class for various levels of filtering. * * Example 1: Searching for "Wild rift" should display the app, but show "N/A" for most cases. * This is because in some countries, the app is downloadable and in some countries it is not, * hence completely filtering it out of the search results is not the best thing to do. * Instead if we detect that the app is not downloadable for a region, we use [UI] level * filter; if it is downloadable for a different region, we then use [NONE] filter. * * Similar app: de.tlllr.tlllrfan * * Example 2: Some apps like "com.skype.m2" can not only be not downloaded, even its details * page cannot be opened. Such apps cannot be shown on lists. Hence we use the [DATA] filter. * * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5720 */ enum class FilterLevel { UI, // Show the app in lists, but show "N/A" in the install button. DATA, // Filter the app out from lists and search results, don't show the app at all. NONE, // No restrictions UNKNOWN, // Not initialised yet } fun FilterLevel.isUnFiltered(): Boolean = this == FilterLevel.NONE fun FilterLevel.isInitialized(): Boolean = this != FilterLevel.UNKNOWN domain/src/main/java/foundation/e/apps/domain/enums/ResultStatus.kt 0 → 100644 +9 −0 Original line number Diff line number Diff line package foundation.e.apps.domain.enums enum class ResultStatus { OK, TIMEOUT, UNKNOWN, RETRY; var message: String = "" } Loading
domain/src/main/java/foundation/e/apps/domain/ResultSupreme.kt 0 → 100644 +194 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 ECORP * * 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.domain import foundation.e.apps.domain.enums.ResultStatus import java.util.concurrent.TimeoutException private const val UNKNOWN_ERROR = "Unknown error!" /** * Another implementation of Result class. * This removes the use of [ResultStatus] class for different status. * This class also follows the standard code patterns. However, we still have the same * flaw that [data] is nullable. As such we may have to add extra null checks or just * brute force with !! * * Also since for each case we now use an inner class with slightly different name, * we need some refactoring. * * Issue: https://gitlab.e.foundation/e/os/backlog/-/issues/313 */ sealed class ResultSupreme<T> { /** * Success case. * Use [isSuccess] to check. * * @param data End result of processing. */ class Success<T>(data: T) : ResultSupreme<T>() { init { setData(data) } } /** * Timed out during network related job. * Use [isTimeout] to check. * * @param data The process is expected to output some blank data, but it cannot be null. * Example can be an empty list. * @param exception Optional exception from try-catch block. */ class Timeout<T>(data: T? = null, exception: Exception = TimeoutException()) : ResultSupreme<T>() { init { data?.let { setData(it) } this.exception = exception } } /** * Miscellaneous error case. * No valid data from processing. * Use [isUnknownError] to check. */ open class Error<T>() : ResultSupreme<T>() { /** * @param message A String message to log or display to the user. * @param exception Optional exception from try-catch block. */ constructor(message: String, exception: Exception? = null) : this() { this.message = message this.exception = exception } /** * @param data Non-null data. Example a String which could not be parsed into a JSON. * @param message A optional String message to log or display to the user. */ constructor(data: T, message: String = "") : this() { setData(data) this.message = message } } class WorkError<T> constructor(data: T, payload: Any? = null) : Error<T>(data) { init { this.otherPayload = payload } } /** * Data from processing. May be null. */ var data: T? = null private set /** * A custom string message for logging or displaying to the user. */ var message: String = "" var otherPayload: Any? = null /** * Exception from try-catch block for error cases. */ var exception: Exception? = null fun isValidData() = data != null fun isSuccess() = this is Success && isValidData() fun isTimeout() = this is Timeout fun isUnknownError() = this is Error fun setData(data: T) { this.data = data } fun getResultStatus(): ResultStatus { return when (this) { is Success -> ResultStatus.OK is Timeout -> ResultStatus.TIMEOUT else -> ResultStatus.UNKNOWN.apply { message = this@ResultSupreme.exception?.localizedMessage ?: UNKNOWN_ERROR } } } companion object { /** * Function to create an instance of ResultSupreme from a [ResultStatus] status, * and other available info - [data], [message], [exception]. */ fun <T> create( status: ResultStatus, data: T? = null, message: String = "", exception: Exception? = null, ): ResultSupreme<T> { val resultObject = when { status == ResultStatus.OK && data != null -> Success<T>(data) status == ResultStatus.TIMEOUT && data != null -> Timeout<T>(data) else -> Error(message.ifBlank { status.message }, exception) } resultObject.apply { if (isUnknownError()) { this.data = data } else { this.message = message.ifBlank { status.message } this.exception = exception } } return resultObject } /** * Create a similar [ResultSupreme] instance i.e. of type [Success], [Timeout]... * using a supplied [result] object but with a different generic type and new data. * * @param result Class of [ResultSupreme] whose replica is to be made. * @param newData Nullable new data for this replica. * @param message Optional new message for this replica. If not provided, * the new object will get the message from [result]. * @param exception Optional new exception for this replica. If not provided, * the new object will get the exception from [result]. */ fun <T> replicate( result: ResultSupreme<*>, newData: T?, message: String? = null, exception: Exception? = null, ): ResultSupreme<T> { val status = when (result) { is Success -> ResultStatus.OK is Timeout -> ResultStatus.TIMEOUT is Error -> ResultStatus.UNKNOWN } return create( status, newData, message ?: result.message, exception ?: result.exception ) } } }
domain/src/main/java/foundation/e/apps/domain/cleanapk/CleanApkConstants.kt 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2026 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.domain.cleanapk object CleanApkConstants { const val BASE_URL = "https://api.cleanapk.org/v2/" const val ASSET_URL = "https://api.cleanapk.org/v2/media/" const val APP_SOURCE_FOSS = "open" const val APP_SOURCE_ANY = "any" const val APP_TYPE_NATIVE = "native" const val APP_TYPE_PWA = "pwa" const val APP_TYPE_ANY = "any" }
domain/src/main/java/foundation/e/apps/domain/enums/AppTag.kt 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019-2022 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.domain.enums /** * This sealed class is used for the tags shown in the categories screen, * the [displayTag] holds the tag in the user device specific locale. * (Example: [OpenSource.displayTag] for Deutsch language = "Quelloffen") * * Previously this was hard coded, which led to crashes due to changes in different locales. * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5364 */ sealed class AppTag(val displayTag: String) { class OpenSource(displayTag: String) : AppTag(displayTag) class PWA(displayTag: String) : AppTag(displayTag) class GPlay(displayTag: String = "") : AppTag(displayTag) /** * In many places in the code, checks are for hard coded string "Open Source". * This method allows for all those check to work without modification. */ fun getOperationalTag(): String { return if (this is OpenSource) { "Open Source" } else { this::class.java.simpleName } } }
domain/src/main/java/foundation/e/apps/domain/enums/FilterLevel.kt 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019-2022 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.domain.enums /** * Use this class for various levels of filtering. * * Example 1: Searching for "Wild rift" should display the app, but show "N/A" for most cases. * This is because in some countries, the app is downloadable and in some countries it is not, * hence completely filtering it out of the search results is not the best thing to do. * Instead if we detect that the app is not downloadable for a region, we use [UI] level * filter; if it is downloadable for a different region, we then use [NONE] filter. * * Similar app: de.tlllr.tlllrfan * * Example 2: Some apps like "com.skype.m2" can not only be not downloaded, even its details * page cannot be opened. Such apps cannot be shown on lists. Hence we use the [DATA] filter. * * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5720 */ enum class FilterLevel { UI, // Show the app in lists, but show "N/A" in the install button. DATA, // Filter the app out from lists and search results, don't show the app at all. NONE, // No restrictions UNKNOWN, // Not initialised yet } fun FilterLevel.isUnFiltered(): Boolean = this == FilterLevel.NONE fun FilterLevel.isInitialized(): Boolean = this != FilterLevel.UNKNOWN
domain/src/main/java/foundation/e/apps/domain/enums/ResultStatus.kt 0 → 100644 +9 −0 Original line number Diff line number Diff line package foundation.e.apps.domain.enums enum class ResultStatus { OK, TIMEOUT, UNKNOWN, RETRY; var message: String = "" }