From 3f059d7748cae89a8e4dd93bc8c0463873789034 Mon Sep 17 00:00:00 2001 From: Ax333l Date: Mon, 7 Aug 2023 11:03:50 +0200 Subject: [PATCH] feat: switch to the new api (#75) --- .../revanced/manager/di/RepositoryModule.kt | 5 +-- .../domain/bundles/RemotePatchBundle.kt | 44 +++++++++++-------- .../domain/manager/PreferencesManager.kt | 2 +- .../domain/repository/GithubRepository.kt | 1 + .../domain/repository/ReVancedRepository.kt | 25 ----------- .../manager/network/api/ManagerAPI.kt | 43 ------------------ .../manager/network/api/ReVancedAPI.kt | 26 +++++++++++ .../network/dto/ReVancedContributors.kt | 14 +++--- .../manager/network/dto/ReVancedRelease.kt | 32 ++++++++++++++ .../manager/network/dto/ReVancedReleases.kt | 20 --------- .../network/service/ReVancedService.kt | 20 +++------ .../settings/update/UpdateProgressScreen.kt | 4 +- .../ui/viewmodel/ContributorViewModel.kt | 17 ++++--- .../ui/viewmodel/UpdateProgressViewModel.kt | 37 +++++++++++++--- 14 files changed, 142 insertions(+), 148 deletions(-) delete mode 100644 app/src/main/java/app/revanced/manager/domain/repository/ReVancedRepository.kt delete mode 100644 app/src/main/java/app/revanced/manager/network/api/ManagerAPI.kt create mode 100644 app/src/main/java/app/revanced/manager/network/api/ReVancedAPI.kt create mode 100644 app/src/main/java/app/revanced/manager/network/dto/ReVancedRelease.kt delete mode 100644 app/src/main/java/app/revanced/manager/network/dto/ReVancedReleases.kt diff --git a/app/src/main/java/app/revanced/manager/di/RepositoryModule.kt b/app/src/main/java/app/revanced/manager/di/RepositoryModule.kt index 6f2ab435..2265d0b3 100644 --- a/app/src/main/java/app/revanced/manager/di/RepositoryModule.kt +++ b/app/src/main/java/app/revanced/manager/di/RepositoryModule.kt @@ -4,14 +4,13 @@ import app.revanced.manager.data.platform.FileSystem import app.revanced.manager.data.platform.NetworkInfo import app.revanced.manager.domain.repository.* import app.revanced.manager.domain.worker.WorkerRepository -import app.revanced.manager.network.api.ManagerAPI +import app.revanced.manager.network.api.ReVancedAPI import org.koin.core.module.dsl.singleOf import org.koin.dsl.module val repositoryModule = module { - singleOf(::ReVancedRepository) + singleOf(::ReVancedAPI) singleOf(::GithubRepository) - singleOf(::ManagerAPI) singleOf(::FileSystem) singleOf(::NetworkInfo) singleOf(::PatchBundlePersistenceRepository) diff --git a/app/src/main/java/app/revanced/manager/domain/bundles/RemotePatchBundle.kt b/app/src/main/java/app/revanced/manager/domain/bundles/RemotePatchBundle.kt index 7ef5e99a..93c945a8 100644 --- a/app/src/main/java/app/revanced/manager/domain/bundles/RemotePatchBundle.kt +++ b/app/src/main/java/app/revanced/manager/domain/bundles/RemotePatchBundle.kt @@ -2,20 +2,18 @@ package app.revanced.manager.domain.bundles import androidx.compose.runtime.Stable import app.revanced.manager.data.room.bundles.VersionInfo -import app.revanced.manager.domain.bundles.APIPatchBundle.Companion.toBundleAsset -import app.revanced.manager.domain.repository.Assets import app.revanced.manager.domain.repository.PatchBundlePersistenceRepository -import app.revanced.manager.domain.repository.ReVancedRepository -import app.revanced.manager.network.dto.Asset +import app.revanced.manager.network.api.ReVancedAPI +import app.revanced.manager.network.api.ReVancedAPI.Extensions.findAssetByType import app.revanced.manager.network.dto.BundleAsset import app.revanced.manager.network.dto.BundleInfo import app.revanced.manager.network.service.HttpService import app.revanced.manager.network.utils.getOrThrow -import app.revanced.manager.util.ghIntegrations -import app.revanced.manager.util.ghPatches +import app.revanced.manager.util.APK_MIMETYPE +import app.revanced.manager.util.JAR_MIMETYPE import io.ktor.client.request.url -import io.ktor.http.Url import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch @@ -57,7 +55,11 @@ sealed class RemotePatchBundle(name: String, id: Int, directory: File, val endpo suspend fun update(): Boolean = withContext(Dispatchers.IO) { val info = getLatestInfo() - if (hasInstalled() && VersionInfo(info.patches.version, info.integrations.version) == currentVersion()) { + if (hasInstalled() && VersionInfo( + info.patches.version, + info.integrations.version + ) == currentVersion() + ) { return@withContext false } @@ -94,18 +96,24 @@ class JsonPatchBundle(name: String, id: Int, directory: File, endpoint: String) class APIPatchBundle(name: String, id: Int, directory: File, endpoint: String) : RemotePatchBundle(name, id, directory, endpoint) { - private val api: ReVancedRepository by inject() + private val api: ReVancedAPI by inject() - override suspend fun getLatestInfo() = api.getAssets().toBundleInfo() - - private companion object { - fun Assets.toBundleInfo(): BundleInfo { - val patches = find(ghPatches, ".jar") - val integrations = find(ghIntegrations, ".apk") - - return BundleInfo(patches.toBundleAsset(), integrations.toBundleAsset()) + override suspend fun getLatestInfo() = coroutineScope { + fun getAssetAsync(repo: String, mime: String) = async(Dispatchers.IO) { + api + .getRelease(repo) + .getOrThrow() + .let { + BundleAsset(it.metadata.tag, it.findAssetByType(mime).downloadUrl) + } } - fun Asset.toBundleAsset() = BundleAsset(version, downloadUrl) + val patches = getAssetAsync("revanced-patches", JAR_MIMETYPE) + val integrations = getAssetAsync("revanced-integrations", APK_MIMETYPE) + + BundleInfo( + patches.await(), + integrations.await() + ) } } \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/domain/manager/PreferencesManager.kt b/app/src/main/java/app/revanced/manager/domain/manager/PreferencesManager.kt index 697a72eb..34d7af60 100644 --- a/app/src/main/java/app/revanced/manager/domain/manager/PreferencesManager.kt +++ b/app/src/main/java/app/revanced/manager/domain/manager/PreferencesManager.kt @@ -10,7 +10,7 @@ class PreferencesManager( val dynamicColor = booleanPreference("dynamic_color", true) val theme = enumPreference("theme", Theme.SYSTEM) - val api = stringPreference("api_url", "https://releases.revanced.app") + val api = stringPreference("api_url", "https://api.revanced.app") val allowExperimental = booleanPreference("allow_experimental", false) diff --git a/app/src/main/java/app/revanced/manager/domain/repository/GithubRepository.kt b/app/src/main/java/app/revanced/manager/domain/repository/GithubRepository.kt index d2797115..79587dfc 100644 --- a/app/src/main/java/app/revanced/manager/domain/repository/GithubRepository.kt +++ b/app/src/main/java/app/revanced/manager/domain/repository/GithubRepository.kt @@ -2,6 +2,7 @@ package app.revanced.manager.domain.repository import app.revanced.manager.network.service.GithubService +// TODO: delete this when the revanced api adds download count. class GithubRepository(private val service: GithubService) { suspend fun getChangelog(repo: String) = service.getChangelog(repo) } \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/domain/repository/ReVancedRepository.kt b/app/src/main/java/app/revanced/manager/domain/repository/ReVancedRepository.kt deleted file mode 100644 index 5d35fddd..00000000 --- a/app/src/main/java/app/revanced/manager/domain/repository/ReVancedRepository.kt +++ /dev/null @@ -1,25 +0,0 @@ -package app.revanced.manager.domain.repository - -import app.revanced.manager.domain.manager.PreferencesManager -import app.revanced.manager.network.api.MissingAssetException -import app.revanced.manager.network.dto.Asset -import app.revanced.manager.network.dto.ReVancedReleases -import app.revanced.manager.network.service.ReVancedService -import app.revanced.manager.network.utils.getOrThrow - -class ReVancedRepository( - private val service: ReVancedService, - private val prefs: PreferencesManager -) { - private suspend fun apiUrl() = prefs.api.get() - - suspend fun getContributors() = service.getContributors(apiUrl()) - - suspend fun getAssets() = Assets(service.getAssets(apiUrl()).getOrThrow()) -} - -class Assets(private val releases: ReVancedReleases): List by releases.tools { - fun find(repo: String, file: String) = find { asset -> - asset.name.contains(file) && asset.repository.contains(repo) - } ?: throw MissingAssetException() -} \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/network/api/ManagerAPI.kt b/app/src/main/java/app/revanced/manager/network/api/ManagerAPI.kt deleted file mode 100644 index 49c6f360..00000000 --- a/app/src/main/java/app/revanced/manager/network/api/ManagerAPI.kt +++ /dev/null @@ -1,43 +0,0 @@ -package app.revanced.manager.network.api - -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import app.revanced.manager.domain.repository.Assets -import app.revanced.manager.domain.repository.ReVancedRepository -import app.revanced.manager.network.dto.Asset -import app.revanced.manager.network.service.HttpService -import app.revanced.manager.util.* -import io.ktor.client.plugins.onDownload -import io.ktor.client.request.url -import java.io.File - -// TODO: merge ReVancedRepository into this class -class ManagerAPI( - private val http: HttpService, - private val revancedRepository: ReVancedRepository -) { - var downloadProgress: Float? by mutableStateOf(null) - var downloadedSize: Long? by mutableStateOf(null) - var totalSize: Long? by mutableStateOf(null) - - private suspend fun downloadAsset(asset: Asset, saveLocation: File) { - http.download(saveLocation) { - url(asset.downloadUrl) - onDownload { bytesSentTotal, contentLength -> - downloadProgress = (bytesSentTotal.toFloat() / contentLength.toFloat()) - downloadedSize = bytesSentTotal - totalSize = contentLength - } - } - downloadProgress = null - } - - suspend fun downloadManager(location: File) { - val managerAsset = revancedRepository.getAssets().find(ghManager, ".apk") - downloadAsset(managerAsset, location) - } - -} - -class MissingAssetException : Exception() \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/network/api/ReVancedAPI.kt b/app/src/main/java/app/revanced/manager/network/api/ReVancedAPI.kt new file mode 100644 index 00000000..3367bcf2 --- /dev/null +++ b/app/src/main/java/app/revanced/manager/network/api/ReVancedAPI.kt @@ -0,0 +1,26 @@ +package app.revanced.manager.network.api + +import app.revanced.manager.domain.manager.PreferencesManager +import app.revanced.manager.network.dto.Asset +import app.revanced.manager.network.dto.ReVancedLatestRelease +import app.revanced.manager.network.dto.ReVancedRelease +import app.revanced.manager.network.service.ReVancedService +import app.revanced.manager.network.utils.getOrThrow +import app.revanced.manager.network.utils.transform + +class ReVancedAPI( + private val service: ReVancedService, + private val prefs: PreferencesManager +) { + private suspend fun apiUrl() = prefs.api.get() + + suspend fun getContributors() = service.getContributors(apiUrl()).transform { it.repositories } + + suspend fun getRelease(name: String) = service.getRelease(apiUrl(), name).transform { it.release } + + companion object Extensions { + fun ReVancedRelease.findAssetByType(mime: String) = assets.singleOrNull { it.contentType == mime } ?: throw MissingAssetException(mime) + } +} + +class MissingAssetException(type: String) : Exception("No asset with type $type") \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/network/dto/ReVancedContributors.kt b/app/src/main/java/app/revanced/manager/network/dto/ReVancedContributors.kt index 4e4c96a5..ef52108c 100644 --- a/app/src/main/java/app/revanced/manager/network/dto/ReVancedContributors.kt +++ b/app/src/main/java/app/revanced/manager/network/dto/ReVancedContributors.kt @@ -4,18 +4,18 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -class ReVancedRepositories( - @SerialName("repositories") val repositories: List, +data class ReVancedGitRepositories( + val repositories: List, ) @Serializable -class ReVancedRepository( - @SerialName("name") val name: String, - @SerialName("contributors") val contributors: List, +data class ReVancedGitRepository( + val name: String, + val contributors: List, ) @Serializable -class ReVancedContributor( - @SerialName("login") val username: String, +data class ReVancedContributor( + val username: String, @SerialName("avatar_url") val avatarUrl: String, ) diff --git a/app/src/main/java/app/revanced/manager/network/dto/ReVancedRelease.kt b/app/src/main/java/app/revanced/manager/network/dto/ReVancedRelease.kt new file mode 100644 index 00000000..d97b335c --- /dev/null +++ b/app/src/main/java/app/revanced/manager/network/dto/ReVancedRelease.kt @@ -0,0 +1,32 @@ +package app.revanced.manager.network.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ReVancedLatestRelease( + val release: ReVancedRelease, +) + +@Serializable +data class ReVancedRelease( + val metadata: ReVancedReleaseMeta, + val assets: List +) + +@Serializable +data class ReVancedReleaseMeta( + @SerialName("tag_name") val tag: String, + val name: String, + val draft: Boolean, + val prerelease: Boolean, + @SerialName("created_at") val createdAt: String, + @SerialName("published_at") val publishedAt: String +) + +@Serializable +data class Asset( + val name: String, + @SerialName("browser_download_url") val downloadUrl: String, + @SerialName("content_type") val contentType: String +) \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/network/dto/ReVancedReleases.kt b/app/src/main/java/app/revanced/manager/network/dto/ReVancedReleases.kt deleted file mode 100644 index 684a956d..00000000 --- a/app/src/main/java/app/revanced/manager/network/dto/ReVancedReleases.kt +++ /dev/null @@ -1,20 +0,0 @@ -package app.revanced.manager.network.dto - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -class ReVancedReleases( - @SerialName("tools") val tools: List, -) - -@Serializable -class Asset( - @SerialName("repository") val repository: String, - @SerialName("version") val version: String, - @SerialName("timestamp") val timestamp: String, - @SerialName("name") val name: String, - @SerialName("size") val size: String?, - @SerialName("browser_download_url") val downloadUrl: String, - @SerialName("content_type") val content_type: String -) \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/network/service/ReVancedService.kt b/app/src/main/java/app/revanced/manager/network/service/ReVancedService.kt index 55a8bd78..b5681afe 100644 --- a/app/src/main/java/app/revanced/manager/network/service/ReVancedService.kt +++ b/app/src/main/java/app/revanced/manager/network/service/ReVancedService.kt @@ -1,11 +1,8 @@ package app.revanced.manager.network.service -import app.revanced.manager.network.api.MissingAssetException -import app.revanced.manager.network.dto.Asset -import app.revanced.manager.network.dto.ReVancedReleases -import app.revanced.manager.network.dto.ReVancedRepositories +import app.revanced.manager.network.dto.ReVancedLatestRelease +import app.revanced.manager.network.dto.ReVancedGitRepositories import app.revanced.manager.network.utils.APIResponse -import app.revanced.manager.network.utils.getOrThrow import io.ktor.client.request.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -13,20 +10,17 @@ import kotlinx.coroutines.withContext class ReVancedService( private val client: HttpService, ) { - suspend fun getAssets(api: String): APIResponse { - return withContext(Dispatchers.IO) { + suspend fun getRelease(api: String, repo: String): APIResponse = + withContext(Dispatchers.IO) { client.request { - url("$api/tools") + url("$api/v2/$repo/releases/latest") } } - } - suspend fun getContributors(api: String): APIResponse { - return withContext(Dispatchers.IO) { + suspend fun getContributors(api: String): APIResponse = + withContext(Dispatchers.IO) { client.request { url("$api/contributors") } } - } - } \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/screen/settings/update/UpdateProgressScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/settings/update/UpdateProgressScreen.kt index 5ea51ebe..b1a5f152 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/settings/update/UpdateProgressScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/settings/update/UpdateProgressScreen.kt @@ -56,7 +56,7 @@ fun UpdateProgressScreen( ), style = MaterialTheme.typography.headlineMedium ) LinearProgressIndicator( - progress = vm.downloadProgress / 100f, + progress = vm.downloadProgress, modifier = Modifier .padding(vertical = 16.dp) .fillMaxWidth() @@ -66,7 +66,7 @@ fun UpdateProgressScreen( vm.totalSize.div( 1000000 ) - } MB (${vm.downloadProgress.toInt()}%)" else stringResource(R.string.installing_message), + } MB (${vm.downloadProgress.times(100).toInt()}%)" else stringResource(R.string.installing_message), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.outline, modifier = Modifier.align(Alignment.CenterHorizontally), diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/ContributorViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/ContributorViewModel.kt index f32a1488..3230c011 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/ContributorViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/ContributorViewModel.kt @@ -3,22 +3,21 @@ package app.revanced.manager.ui.viewmodel import androidx.compose.runtime.mutableStateListOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import app.revanced.manager.domain.repository.ReVancedRepository +import app.revanced.manager.network.api.ReVancedAPI +import app.revanced.manager.network.dto.ReVancedGitRepository import app.revanced.manager.network.utils.getOrNull import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -class ContributorViewModel(private val repository: ReVancedRepository): ViewModel() { - val repositories = mutableStateListOf() +class ContributorViewModel(private val reVancedAPI: ReVancedAPI) : ViewModel() { + val repositories = mutableStateListOf() + init { viewModelScope.launch { - withContext(Dispatchers.IO) { - val repos = repository.getContributors().getOrNull()?.repositories - withContext(Dispatchers.Main) { - if (repos != null) { repositories.addAll(repos) } - } - } + withContext(Dispatchers.IO) { reVancedAPI.getContributors().getOrNull() }?.let( + repositories::addAll + ) } } } \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateProgressViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateProgressViewModel.kt index cf51a61a..2ee6ed33 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateProgressViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateProgressViewModel.kt @@ -8,24 +8,36 @@ import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import app.revanced.manager.R -import app.revanced.manager.network.api.ManagerAPI +import app.revanced.manager.network.api.ReVancedAPI +import app.revanced.manager.network.api.ReVancedAPI.Extensions.findAssetByType +import app.revanced.manager.network.service.HttpService +import app.revanced.manager.network.utils.getOrThrow +import app.revanced.manager.util.APK_MIMETYPE import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import app.revanced.manager.util.PM import app.revanced.manager.util.uiSafe +import io.ktor.client.plugins.onDownload +import io.ktor.client.request.url import kotlinx.coroutines.withContext import java.io.File class UpdateProgressViewModel( app: Application, - private val managerAPI: ManagerAPI, + private val reVancedAPI: ReVancedAPI, + private val http: HttpService, private val pm: PM ) : ViewModel() { + var downloadedSize by mutableStateOf(0L) + private set + var totalSize by mutableStateOf(0L) + private set + val downloadProgress by derivedStateOf { + if (downloadedSize == 0L || totalSize == 0L) return@derivedStateOf 0f - val downloadProgress by derivedStateOf { managerAPI.downloadProgress?.times(100) ?: 0f } - val downloadedSize by derivedStateOf { managerAPI.downloadedSize ?: 0L } - val totalSize by derivedStateOf { managerAPI.totalSize ?: 0L } - val isInstalling by derivedStateOf { downloadProgress >= 100 } + downloadedSize.toFloat() / totalSize.toFloat() + } + val isInstalling by derivedStateOf { downloadProgress >= 1 } var finished by mutableStateOf(false) private set @@ -33,7 +45,18 @@ class UpdateProgressViewModel( private val job = viewModelScope.launch { uiSafe(app, R.string.download_manager_failed, "Failed to download manager") { withContext(Dispatchers.IO) { - managerAPI.downloadManager(location) + val asset = reVancedAPI + .getRelease("revanced-manager") + .getOrThrow() + .findAssetByType(APK_MIMETYPE) + + http.download(location) { + url(asset.downloadUrl) + onDownload { bytesSentTotal, contentLength -> + downloadedSize = bytesSentTotal + totalSize = contentLength + } + } } finished = true }