Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: updater UI and code improvements #1597

Merged
merged 4 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ val viewModelModule = module {
viewModelOf(::DownloadsViewModel)
viewModelOf(::InstalledAppsViewModel)
viewModelOf(::InstalledAppInfoViewModel)
viewModelOf(::UpdatesSettingsViewModel)
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class APIPatchBundle(name: String, id: Int, directory: File, endpoint: String) :
.getLatestRelease(repo)
.getOrThrow()
.let {
BundleAsset(it.metadata.tag, it.findAssetByType(mime).downloadUrl)
BundleAsset(it.version, it.findAssetByType(mime).downloadUrl)
}
}

Expand Down
16 changes: 13 additions & 3 deletions app/src/main/java/app/revanced/manager/network/api/ReVancedAPI.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package app.revanced.manager.network.api

import android.os.Build
import app.revanced.manager.domain.manager.PreferencesManager
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(
Expand All @@ -13,12 +15,20 @@ class ReVancedAPI(

suspend fun getContributors() = service.getContributors(apiUrl()).transform { it.repositories }

suspend fun getLatestRelease(name: String) = service.getLatestRelease(apiUrl(), name).transform { it.release }
suspend fun getLatestRelease(name: String) =
service.getLatestRelease(apiUrl(), name).transform { it.release }

suspend fun getReleases(name: String) = service.getReleases(apiUrl(), name).transform { it.releases }
suspend fun getReleases(name: String) =
service.getReleases(apiUrl(), name).transform { it.releases }

suspend fun getAppUpdate() =
getLatestRelease("revanced-manager")
.getOrThrow()
.takeIf { it.version != Build.VERSION.RELEASE }

companion object Extensions {
fun ReVancedRelease.findAssetByType(mime: String) = assets.singleOrNull { it.contentType == mime } ?: throw MissingAssetException(mime)
fun ReVancedRelease.findAssetByType(mime: String) =
assets.singleOrNull { it.contentType == mime } ?: throw MissingAssetException(mime)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ data class ReVancedReleases(
data class ReVancedRelease(
val metadata: ReVancedReleaseMeta,
val assets: List<Asset>
)
) {
val version get() = metadata.tag
}

@Serializable
data class ReVancedReleaseMeta(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import kotlinx.coroutines.launch

@Composable
fun BooleanItem(
modifier: Modifier = Modifier,
preference: Preference<Boolean>,
coroutineScope: CoroutineScope = rememberCoroutineScope(),
@StringRes headline: Int,
Expand All @@ -22,6 +23,7 @@ fun BooleanItem(
val value by preference.getAsState()

BooleanItem(
modifier = modifier,
value = value,
onValueChange = { coroutineScope.launch { preference.update(it) } },
headline = headline,
Expand All @@ -31,12 +33,15 @@ fun BooleanItem(

@Composable
fun BooleanItem(
modifier: Modifier = Modifier,
value: Boolean,
onValueChange: (Boolean) -> Unit,
@StringRes headline: Int,
@StringRes description: Int
) = SettingsListItem(
modifier = Modifier.clickable { onValueChange(!value) },
modifier = Modifier
.clickable { onValueChange(!value) }
.then(modifier),
headlineContent = stringResource(headline),
supportingContent = stringResource(description),
trailingContent = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,34 @@ package app.revanced.manager.ui.screen.settings.update
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Update
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import app.revanced.manager.R
import app.revanced.manager.domain.manager.PreferencesManager
import app.revanced.manager.ui.component.AppTopBar
import app.revanced.manager.ui.component.NotificationCard
import app.revanced.manager.ui.component.settings.BooleanItem
import app.revanced.manager.ui.component.settings.SettingsListItem
import app.revanced.manager.ui.viewmodel.UpdatesSettingsViewModel
import kotlinx.coroutines.launch
import org.koin.androidx.compose.getViewModel
import org.koin.compose.rememberKoinInject

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun UpdatesSettingsScreen(
onBackClick: () -> Unit,
onChangelogClick: () -> Unit,
onUpdateClick: () -> Unit,
vm: UpdatesSettingsViewModel = getViewModel(),
) {
val listItems = listOf(
Triple(
stringResource(R.string.update_channel),
stringResource(R.string.update_channel_description),
third = { /*TODO*/ }
),
Triple(
stringResource(R.string.update_notifications),
stringResource(R.string.update_notifications_description),
third = { /*TODO*/ }
),
Triple(
stringResource(R.string.changelog),
stringResource(R.string.changelog_description),
third = onChangelogClick
),
)

val coroutineScope = rememberCoroutineScope()

Scaffold(
topBar = {
Expand All @@ -60,22 +46,29 @@ fun UpdatesSettingsScreen(
.padding(paddingValues)
.verticalScroll(rememberScrollState())
) {
NotificationCard(
text = stringResource(R.string.update_notification),
icon = Icons.Default.Update,
primaryAction = onUpdateClick
SettingsListItem(
modifier = Modifier.clickable {
coroutineScope.launch {
if (vm.checkForUpdates()) onUpdateClick()
}
},
headlineContent = stringResource(R.string.manual_update_check),
supportingContent = stringResource(R.string.manual_update_check_description)
)

listItems.forEach { (title, description, onClick) ->
SettingsListItem(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 8.dp)
.clickable { onClick() },
headlineContent = title,
supportingContent = description
SettingsListItem(
modifier = Modifier.clickable(onClick = onChangelogClick),
headlineContent = stringResource(R.string.changelog),
supportingContent = stringResource(
R.string.changelog_description
)
}
)

BooleanItem(
preference = vm.managerAutoUpdates,
headline = R.string.update_checking_manager,
description = R.string.update_checking_manager_description
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class ChangelogsViewModel(
uiSafe(app, R.string.changelog_download_fail, "Failed to download changelog") {
changelogs = api.getReleases("revanced-manager").getOrNull().orEmpty().map { release ->
Changelog(
release.metadata.tag,
release.version,
release.findAssetByType(APK_MIMETYPE).downloadCount,
release.metadata.publishedAt,
release.metadata.body
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ import app.revanced.manager.network.utils.getOrThrow
import app.revanced.manager.ui.theme.Theme
import app.revanced.manager.util.tag
import app.revanced.manager.util.toast
import app.revanced.manager.util.uiSafe
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json

Expand All @@ -55,13 +58,8 @@ class MainViewModel(
private suspend fun checkForManagerUpdates() {
if (!prefs.managerAutoUpdates.get() || !networkInfo.isConnected()) return

try {
reVancedAPI.getLatestRelease("revanced-manager").getOrThrow().let { release ->
updatedManagerVersion = release.metadata.tag.takeIf { it != Build.VERSION.RELEASE }
}
} catch (e: Exception) {
app.toast(app.getString(R.string.failed_to_check_updates))
Log.e(tag, "Failed to check for updates", e)
uiSafe(app, R.string.failed_to_check_updates, "Failed to check for updates") {
updatedManagerVersion = reVancedAPI.getAppUpdate()?.version
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import app.revanced.manager.R
import app.revanced.manager.data.platform.Filesystem
import app.revanced.manager.data.platform.NetworkInfo
import app.revanced.manager.network.api.ReVancedAPI
import app.revanced.manager.network.api.ReVancedAPI.Extensions.findAssetByType
Expand Down Expand Up @@ -47,6 +48,7 @@ class UpdateViewModel(
private val http: HttpService by inject()
private val pm: PM by inject()
private val networkInfo: NetworkInfo by inject()
private val fs: Filesystem by inject()

var downloadedSize by mutableStateOf(0L)
private set
Expand All @@ -65,17 +67,16 @@ class UpdateViewModel(

var changelog: Changelog? by mutableStateOf(null)

private val location = File.createTempFile("updater", ".apk", app.cacheDir)
private val location = fs.tempDir.resolve("updater.apk")
private var release: ReVancedRelease? = null
private val job = viewModelScope.launch {
uiSafe(app, R.string.download_manager_failed, "Failed to download ReVanced Manager") {
withContext(Dispatchers.IO) {
val response = reVancedAPI
.getLatestRelease("revanced-manager")
.getOrThrow()
val response = reVancedAPI.getAppUpdate() ?: throw Exception("No update available")

release = response
changelog = Changelog(
response.metadata.tag,
response.version,
response.findAssetByType(APK_MIMETYPE).downloadCount,
response.metadata.publishedAt,
response.metadata.body
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package app.revanced.manager.ui.viewmodel

import android.app.Application
import androidx.lifecycle.ViewModel
import app.revanced.manager.R
import app.revanced.manager.domain.manager.PreferencesManager
import app.revanced.manager.network.api.ReVancedAPI
import app.revanced.manager.util.toast
import app.revanced.manager.util.uiSafe

class UpdatesSettingsViewModel(
prefs: PreferencesManager,
private val app: Application,
private val reVancedAPI: ReVancedAPI,
) : ViewModel() {
val managerAutoUpdates = prefs.managerAutoUpdates

suspend fun checkForUpdates(): Boolean {
uiSafe(app, R.string.failed_to_check_updates, "Failed to check for updates") {
app.toast(app.getString(R.string.update_check))

if (reVancedAPI.getAppUpdate() == null)
app.toast(app.getString(R.string.no_update_available))
else
return true
}

return false
}
}
13 changes: 7 additions & 6 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -281,11 +281,10 @@
<string name="ready_to_install_update">Ready to install update</string>
<string name="update_completed">Update installed</string>
<string name="install_update_manager_failed">Failed to install update</string>
<string name="update_notification">A minor update for ReVanced Manager is available. Click here to update and get the latest features and fixes!</string>
<string name="update_channel">Update channel</string>
<string name="update_channel_description">Stable</string>
<string name="update_notifications">Update notifications</string>
<string name="update_notifications_description">Dialog on app launch + badges</string>
<string name="manual_update_check">Check for updates</string>
<string name="manual_update_check_description">Manually check for updates</string>
<string name="update_checking_manager">Update checking</string>
<string name="update_checking_manager_description">Check for new versions of ReVanced Manager when the application starts</string>
<string name="changelog">Changelog</string>
<string name="changelog_loading">Loading changelog</string>
<string name="changelog_download_fail">Failed to download changelog: %s</string>
Expand All @@ -306,7 +305,9 @@
<string name="invalid_date">Invalid date</string>
<string name="disable_battery_optimization">Disable battery optimization</string>

<string name="failed_to_check_updates">Failed to check for updates</string>
<string name="failed_to_check_updates">Failed to check for updates: %s</string>
<string name="no_update_available">No update available</string>
<string name="update_check">Checking for updates…</string>
<string name="dismiss_temporary">Not now</string>
<string name="update_available_dialog_title">New update available</string>
<string name="update_available_dialog_description">A new version (%s) is available for download.</string>
Expand Down