Skip to content

Commit

Permalink
Implement ApkMirror updates
Browse files Browse the repository at this point in the history
Add setting for number of columns
  • Loading branch information
rumboalla committed Jul 10, 2023
1 parent 23fadd3 commit c13af6e
Show file tree
Hide file tree
Showing 22 changed files with 358 additions and 99 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ android {
applicationId "com.apkupdater3"
minSdk 24
targetSdk 34
versionCode 30000001
versionName "3.0.0-alpha-01"
versionCode 30000002
versionName "3.0.0-alpha-02"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.apkupdater.data.apkmirror
import com.google.gson.annotations.SerializedName

data class AppExistsResponseApk(
@SerializedName("version_code") val versionCode: Int = 0,
@SerializedName("version_code") val versionCode: Long = 0,
val link: String = "",
@SerializedName("publish_date") val publishDate: String? = null,
val arches: List<String> = emptyList(),
Expand Down
12 changes: 12 additions & 0 deletions app/src/main/java/com/apkupdater/data/ui/AppUpdate.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.apkupdater.data.ui

import android.net.Uri

data class AppUpdate(
val name: String,
val packageName: String,
val version: String,
val versionCode: Long,
val iconUri: Uri = Uri.EMPTY,
val link: String = ""
)
23 changes: 23 additions & 0 deletions app/src/main/java/com/apkupdater/data/ui/AppsUiState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.apkupdater.data.ui


sealed class AppsUiState {
object Loading: AppsUiState()
object Error : AppsUiState()
class Success(val apps: List<AppInstalled>, val excludeSystem: Boolean): AppsUiState()

inline fun onLoading(block: (Loading) -> Unit): AppsUiState {
if (this is Loading) block(this)
return this
}

inline fun onError(block: (Error) -> Unit): AppsUiState {
if (this is Error) block(this)
return this
}

inline fun onSuccess(block: (Success) -> Unit): AppsUiState {
if (this is Success) block(this)
return this
}
}
23 changes: 0 additions & 23 deletions app/src/main/java/com/apkupdater/data/ui/UiState.kt

This file was deleted.

23 changes: 23 additions & 0 deletions app/src/main/java/com/apkupdater/data/ui/UpdatesUiState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.apkupdater.data.ui


sealed class UpdatesUiState {
object Loading: UpdatesUiState()
object Error : UpdatesUiState()
class Success(val updates: List<AppUpdate>): UpdatesUiState()

inline fun onLoading(block: (Loading) -> Unit): UpdatesUiState {
if (this is Loading) block(this)
return this
}

inline fun onError(block: (Error) -> Unit): UpdatesUiState {
if (this is Error) block(this)
return this
}

inline fun onSuccess(block: (Success) -> Unit): UpdatesUiState {
if (this is Success) block(this)
return this
}
}
3 changes: 3 additions & 0 deletions app/src/main/java/com/apkupdater/di/MainModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.apkupdater.repository.AppsRepository
import com.apkupdater.service.ApkMirrorService
import com.apkupdater.viewmodel.AppsViewModel
import com.apkupdater.viewmodel.BottomBarViewModel
import com.apkupdater.viewmodel.SettingsViewModel
import com.apkupdater.viewmodel.UpdatesViewModel
import okhttp3.Cache
import okhttp3.OkHttpClient
Expand Down Expand Up @@ -52,4 +53,6 @@ val mainModule = module {

viewModel { UpdatesViewModel(get(), get(), get()) }

viewModel { SettingsViewModel(get()) }

}
7 changes: 4 additions & 3 deletions app/src/main/java/com/apkupdater/prefs/Prefs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import com.kryptoprefs.preferences.KryptoPrefs

class Prefs(prefs: KryptoPrefs): KryptoContext(prefs) {
val ignoredApps = json("ignoredApps", emptyList<String>())
val excludeSystem get() = boolean("excludeSystem", false)
val excludeDisabled get() = boolean("excludeDisabled", true)
val excludeStore get() = boolean("excludeStore", false)
val excludeSystem = boolean("excludeSystem", true)
val excludeDisabled = boolean("excludeDisabled", true)
val excludeStore = boolean("excludeStore", false)
val portraitColumns = int("portraitColumns", 2)
}
53 changes: 46 additions & 7 deletions app/src/main/java/com/apkupdater/repository/ApkMirrorRepository.kt
Original file line number Diff line number Diff line change
@@ -1,31 +1,70 @@
package com.apkupdater.repository

import android.os.Build
import android.util.Log
import com.apkupdater.data.apkmirror.AppExistsRequest
import com.apkupdater.data.apkmirror.AppExistsResponseApk
import com.apkupdater.data.apkmirror.AppExistsResponseData
import com.apkupdater.data.ui.AppInstalled
import com.apkupdater.prefs.Prefs
import com.apkupdater.service.ApkMirrorService
import com.apkupdater.transform.toAppUpdate
import com.apkupdater.util.combine
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow


class ApkMirrorRepository(
private val service: ApkMirrorService,
private val prefs: Prefs
) {
private val arch = when {
Build.SUPPORTED_ABIS.contains("armeabi-v7a") -> "arm"
Build.SUPPORTED_ABIS.contains("arm64-v8a") -> "arm"
Build.SUPPORTED_ABIS.contains("x86") -> "x86"
Build.SUPPORTED_ABIS.contains("x86_64") -> "x86"
else -> "arm"
}

suspend fun getUpdates(apps: List<String>) = flow {
apps
.chunked(50)
.map { appExists(it) }
.combine { all -> emit(parseUpdates(all.flatMap { it })) }
suspend fun getUpdates(apps: List<AppInstalled>) = flow {
apps.chunked(100)
.map { appExists(getPackageNames(apps)) }
.combine { all -> emit(parseUpdates(all.flatMap { it }, apps)) }
.collect()
}

private fun appExists(apps: List<String>) = flow {
emit(service.appExists(AppExistsRequest(apps)).data)
}.catch {
Log.e("ApkMirrorRepository", "Error getting updates.", it)
}

private fun parseUpdates(updates: List<AppExistsResponseData>) = updates.
filter { it.exists == false }
private fun parseUpdates(updates: List<AppExistsResponseData>, apps: List<AppInstalled>)
= updates
.filter { it.exists == true }
.map { data ->
data.apks
.mapNotNull { filterArch(it) }
.filter { it.versionCode > getVersionCode(apps, data.pname) }
.map { it.toAppUpdate(getApp(apps, data.pname)!!) }
}.flatten()

private fun getVersionCode(apps: List<AppInstalled>, packageName: String) = apps
.find { it.packageName == packageName }?.versionCode ?: 0

private fun getPackageNames(apps: List<AppInstalled>) = apps
.filter { !it.ignored }
.map { it.packageName }

private fun getApp(apps: List<AppInstalled>, packageName: String) = apps
.find { it.packageName == packageName }

private fun filterArch(app: AppExistsResponseApk) = when {
app.arches.isEmpty() -> app
app.arches.contains("universal") || app.arches.contains("noarch") -> app
app.arches.find { a -> a.contains(arch) } != null -> app
else -> null
}

}
30 changes: 15 additions & 15 deletions app/src/main/java/com/apkupdater/repository/AppsRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import com.apkupdater.data.ui.AppInstalled
import com.apkupdater.prefs.Prefs
import com.apkupdater.transform.toAppInstalled
import com.apkupdater.util.orFalse
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow


class AppsRepository(
private val context: Context,
private val prefs: Prefs
Expand All @@ -21,21 +23,19 @@ class AppsRepository(
private fun ignoredApps() = prefs.ignoredApps.get()

suspend fun getApps() = flow<Result<List<AppInstalled>>> {
runCatching {
val apps = context.packageManager.getInstalledPackages(PackageManager.MATCH_ALL)
.asSequence()
.filter { !excludeSystem() || it.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM == 0 }
.filter { !excludeSystem() || it.applicationInfo.flags and ApplicationInfo.FLAG_UPDATED_SYSTEM_APP == 0 }
.filter { !excludeDisabled() || it.applicationInfo.enabled }
.filter { !excludeStore() || !isAppStore(getInstallerPackageName(it.packageName)) }
.map { it.toAppInstalled(context, ignoredApps()) }
.sortedBy { it.name }
.sortedBy { it.ignored }
.toList()
emit(Result.success(apps))
}.getOrElse {
emit(Result.failure(it))
}
val apps = context.packageManager.getInstalledPackages(PackageManager.MATCH_ALL)
.asSequence()
.filter { !excludeSystem() || it.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM == 0 }
.filter { !excludeSystem() || it.applicationInfo.flags and ApplicationInfo.FLAG_UPDATED_SYSTEM_APP == 0 }
.filter { !excludeDisabled() || it.applicationInfo.enabled }
.filter { !excludeStore() || !isAppStore(getInstallerPackageName(it.packageName)) }
.map { it.toAppInstalled(context, ignoredApps()) }
.sortedBy { it.name }
.sortedBy { it.ignored }
.toList()
emit(Result.success(apps))
}.catch {
emit(Result.failure(it))
}

@Suppress("DEPRECATION")
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/java/com/apkupdater/transform/Transforms.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import android.content.Context
import android.content.pm.PackageInfo
import android.net.Uri
import android.os.Build
import com.apkupdater.data.apkmirror.AppExistsResponseApk
import com.apkupdater.data.ui.AppInstalled
import com.apkupdater.data.ui.AppUpdate
import com.apkupdater.util.name


Expand All @@ -18,5 +20,14 @@ fun PackageInfo.toAppInstalled(context: Context, ignored: List<String>) = AppIns
ignored.contains(packageName)
)

fun AppExistsResponseApk.toAppUpdate(app: AppInstalled) = AppUpdate(
app.name,
app.packageName,
"?",
versionCode,
app.iconUri,
"https://www.apkmirror.com/$link"
)

fun iconUri(packageName: String, id: Int): Uri = Uri.parse("android.resource://$packageName/$id")

Loading

0 comments on commit c13af6e

Please sign in to comment.