diff --git a/app/build.gradle b/app/build.gradle index 4f4949b7af732854e6973d38a9d3c9664d9b7816..09d7acdd575626674da13dd663424299d9519296 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -125,6 +125,9 @@ dependencies { // implementation "com.squareup.moshi:moshi-adapters:1.5.0" implementation "com.squareup.okhttp3:okhttp:4.9.2" + // JSON Converter + implementation 'com.squareup.retrofit2:converter-gson:2.5.0' + // YAML factory implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.11.2" diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/ApplicationDeserializer.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/ApplicationDeserializer.kt new file mode 100644 index 0000000000000000000000000000000000000000..a62e7788c5b92febe4b326cd0b24302bfa273905 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/ApplicationDeserializer.kt @@ -0,0 +1,41 @@ +/* + * Copyright ECORP SAS 2022 + * Apps Quickly and easily install Android apps onto your device! + * + * 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 . + */ + +package foundation.e.apps.api.cleanapk + +import com.google.gson.Gson +import com.google.gson.JsonDeserializationContext +import com.google.gson.JsonDeserializer +import com.google.gson.JsonElement +import foundation.e.apps.api.cleanapk.data.app.Application + +class ApplicationDeserializer : JsonDeserializer { + override fun deserialize( + json: JsonElement?, + typeOfT: java.lang.reflect.Type?, + context: JsonDeserializationContext? + ): Application { + val gson = Gson() + val application = gson.fromJson(json?.asJsonObject?.toString(), Application::class.java) + val lastUpdate = application.app.latest_downloaded_version + val lastUpdatedOn = json?.asJsonObject?.get("app")?.asJsonObject?.get(lastUpdate) + ?.asJsonObject?.get("update_on")?.asString ?: "" + application.app.updatedOn = lastUpdatedOn + return application + } +} diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanAPKRepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanAPKRepository.kt index 35a6495cdde17437464229fa1e6b26ce89b5cad4..9bc56e6fe410b1c407b8842027438073adf28ae0 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanAPKRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanAPKRepository.kt @@ -27,7 +27,8 @@ import retrofit2.Response import javax.inject.Inject class CleanAPKRepository @Inject constructor( - private val cleanAPKInterface: CleanAPKInterface + private val cleanAPKInterface: CleanAPKInterface, + private val cleanApkAppDetailApi: CleanApkAppDetailApi ) { suspend fun getHomeScreenData( @@ -42,7 +43,7 @@ class CleanAPKRepository @Inject constructor( architectures: List? = null, type: String? = null ): Response { - return cleanAPKInterface.getAppOrPWADetailsByID(id, architectures, type) + return cleanApkAppDetailApi.getAppOrPWADetailsByID(id, architectures, type) } suspend fun searchApps( diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppDetailApi.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppDetailApi.kt new file mode 100644 index 0000000000000000000000000000000000000000..f6795e12ca59fd8cc3521d5e134755eb44e3cc5e --- /dev/null +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppDetailApi.kt @@ -0,0 +1,41 @@ +/* + * + * * Copyright ECORP SAS 2022 + * * Apps Quickly and easily install Android apps onto your device! + * * + * * 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 . + * + */ + +package foundation.e.apps.api.cleanapk + +import foundation.e.apps.api.cleanapk.data.app.Application +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Query + +interface CleanApkAppDetailApi { + + companion object { + // API endpoints + const val BASE_URL = "https://api.cleanapk.org/v2/" + } + + @GET("apps?action=app_detail") + suspend fun getAppOrPWADetailsByID( + @Query("id") id: String, + @Query("architectures") architectures: List? = null, + @Query("type") type: String? = null + ): Response +} diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/RetrofitModule.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/RetrofitModule.kt index 2672b48f080db54d5c561824fb0259b23ca90906..e0cd5630a56c82c9ee7a6fdfe07e0af5ae2c7185 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/RetrofitModule.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/RetrofitModule.kt @@ -22,12 +22,15 @@ import android.os.Build import android.util.Log import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.dataformat.yaml.YAMLFactory +import com.google.gson.Gson +import com.google.gson.GsonBuilder import com.squareup.moshi.Moshi import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import foundation.e.apps.api.cleanapk.data.app.Application import foundation.e.apps.api.ecloud.EcloudApiInterface import foundation.e.apps.api.exodus.ExodusTrackerApi import foundation.e.apps.api.fdroid.FdroidApiInterface @@ -39,6 +42,7 @@ import okhttp3.Protocol import okhttp3.Response import okhttp3.ResponseBody.Companion.toResponseBody import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.jackson.JacksonConverterFactory import retrofit2.converter.moshi.MoshiConverterFactory import java.net.ConnectException @@ -65,6 +69,24 @@ object RetrofitModule { .create(CleanAPKInterface::class.java) } + /** + * Provides an instance of Retrofit to work with CleanAPK API + * @return instance of [CleanApkAppDetailApi] + */ + @Singleton + @Provides + fun provideCleanAPKDetailApi( + okHttpClient: OkHttpClient, + @Named("gsonCustomAdapter") gson: Gson + ): CleanApkAppDetailApi { + return Retrofit.Builder() + .baseUrl(CleanAPKInterface.BASE_URL) + .client(okHttpClient) + .addConverterFactory(GsonConverterFactory.create(gson)) + .build() + .create(CleanApkAppDetailApi::class.java) + } + @Singleton @Provides fun provideExodusApi(okHttpClient: OkHttpClient, moshi: Moshi): ExodusTrackerApi { @@ -114,6 +136,16 @@ object RetrofitModule { .build() } + @Singleton + @Provides + @Named("gsonCustomAdapter") + fun getGson(): Gson { + return GsonBuilder() + .registerTypeAdapter(Application::class.java, ApplicationDeserializer()) + .enableComplexMapKeySerialization() + .create() + } + /** * Used in above [provideFdroidApi]. * Reference: https://stackoverflow.com/a/69859687 diff --git a/app/src/main/java/foundation/e/apps/api/fused/data/FusedApp.kt b/app/src/main/java/foundation/e/apps/api/fused/data/FusedApp.kt index d48829311e7cd8a9517fabd08d35d53fe9919c3c..cf911a77e4966235ebe5f0ac73ccfdfd151636d4 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/data/FusedApp.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/data/FusedApp.kt @@ -34,6 +34,7 @@ data class FusedApp( val last_modified: String = String(), val latest_version_code: Int = -1, val latest_version_number: String = String(), + val latest_downloaded_version: String = String(), val licence: String = String(), val name: String = String(), val other_images_path: List = emptyList(), @@ -64,4 +65,5 @@ data class FusedApp( * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5136 */ var permsFromExodus: List = LIST_OF_NULL, + var updatedOn: String = String() ) diff --git a/app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt b/app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt index 14aef8e7242945c603d82b71feb484fc63b0627d..bff04df8a1b337e04368934f886a8fe9253e5934 100644 --- a/app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt +++ b/app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt @@ -209,7 +209,7 @@ class ApplicationFragment : Fragment(R.layout.fragment_application) { binding.infoInclude.apply { appUpdatedOn.text = getString( R.string.updated_on, - if (args.origin == Origin.CLEANAPK) getString(R.string.not_available) else it.last_modified + if (args.origin == Origin.CLEANAPK) it.updatedOn else it.last_modified ) appRequires.text = getString(R.string.min_android_version, notAvailable) appVersion.text = getString(