check updates on launch, handle package updated
This commit is contained in:
+2
@@ -15,6 +15,7 @@ import com.seiko.imageloader.LocalImageLoader
|
|||||||
import ru.shadowsparky.koin
|
import ru.shadowsparky.koin
|
||||||
import ru.shadowsparky.ui.components.BackButton
|
import ru.shadowsparky.ui.components.BackButton
|
||||||
import ru.shadowsparky.ui.nav.Nav
|
import ru.shadowsparky.ui.nav.Nav
|
||||||
|
import ru.shadowsparky.updater.presentation.UpdateDialog
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.VideoScreen
|
import ru.shadowsparky.vbox.shared.presentation.list.VideoScreen
|
||||||
import ru.shadowsparky.vbox.shared.presentation.loading.LoadingScreen
|
import ru.shadowsparky.vbox.shared.presentation.loading.LoadingScreen
|
||||||
import ru.shadowsparky.vbox.shared.presentation.nav.Child
|
import ru.shadowsparky.vbox.shared.presentation.nav.Child
|
||||||
@@ -77,6 +78,7 @@ private fun NavInternal(rootComponent: RootComponent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UpdateDialog(rootComponent.updateComponent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-2
@@ -2,15 +2,18 @@ package ru.shadowsparky.vbox.shared.presentation
|
|||||||
|
|
||||||
import com.arkivanov.decompose.ComponentContext
|
import com.arkivanov.decompose.ComponentContext
|
||||||
import com.arkivanov.decompose.ExperimentalDecomposeApi
|
import com.arkivanov.decompose.ExperimentalDecomposeApi
|
||||||
|
import com.arkivanov.decompose.childContext
|
||||||
import com.arkivanov.decompose.router.stack.childStackWebNavigation
|
import com.arkivanov.decompose.router.stack.childStackWebNavigation
|
||||||
import com.arkivanov.decompose.router.webhistory.WebNavigation
|
import com.arkivanov.decompose.router.webhistory.WebNavigation
|
||||||
import com.arkivanov.decompose.router.webhistory.WebNavigationOwner
|
import com.arkivanov.decompose.router.webhistory.WebNavigationOwner
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
import org.koin.core.Koin
|
import org.koin.core.Koin
|
||||||
import org.koin.core.annotation.Factory
|
import org.koin.core.annotation.Factory
|
||||||
import ru.shadowsparky.http.domain.TokenStorage
|
import ru.shadowsparky.http.domain.TokenStorage
|
||||||
import ru.shadowsparky.ui.nav.BaseRootComponent
|
import ru.shadowsparky.ui.nav.BaseRootComponent
|
||||||
|
import ru.shadowsparky.updater.presentation.UpdateComponentFactory
|
||||||
import ru.shadowsparky.vbox.shared.di.factory.ImageLoaderProvider
|
import ru.shadowsparky.vbox.shared.di.factory.ImageLoaderProvider
|
||||||
import ru.shadowsparky.vbox.shared.domain.HeathCheck
|
import ru.shadowsparky.vbox.shared.domain.HeathCheck
|
||||||
import ru.shadowsparky.vbox.shared.presentation.nav.Route
|
import ru.shadowsparky.vbox.shared.presentation.nav.Route
|
||||||
@@ -22,9 +25,12 @@ class RootComponent(
|
|||||||
override val initStack: List<Route>,
|
override val initStack: List<Route>,
|
||||||
private val healthCheck: HeathCheck,
|
private val healthCheck: HeathCheck,
|
||||||
val imageLoaderProvider: ImageLoaderProvider,
|
val imageLoaderProvider: ImageLoaderProvider,
|
||||||
|
private val updateComponentFactory: UpdateComponentFactory,
|
||||||
override val serializer: KSerializer<Route> = Route.serializer(),
|
override val serializer: KSerializer<Route> = Route.serializer(),
|
||||||
override val koin: Koin = ru.shadowsparky.koin
|
override val koin: Koin = ru.shadowsparky.koin
|
||||||
) : BaseRootComponent<Route>(componentContext), WebNavigationOwner {
|
) : BaseRootComponent<Route>(componentContext), WebNavigationOwner {
|
||||||
|
val updateComponent = updateComponentFactory.create(childContext("UpdateComponentRoot"))
|
||||||
|
private val scope = createComponentScope()
|
||||||
val isLoggedIn = tokenStorage.token.map {
|
val isLoggedIn = tokenStorage.token.map {
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
runCatching { healthCheck.check() }.getOrNull() ?: return@map false
|
runCatching { healthCheck.check() }.getOrNull() ?: return@map false
|
||||||
@@ -34,6 +40,10 @@ class RootComponent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
scope.launch { updateComponent.checkUpdates(false) }
|
||||||
|
}
|
||||||
|
|
||||||
override val webNavigation: WebNavigation<*> =
|
override val webNavigation: WebNavigation<*> =
|
||||||
childStackWebNavigation(
|
childStackWebNavigation(
|
||||||
navigator = nav,
|
navigator = nav,
|
||||||
@@ -52,7 +62,8 @@ class RootComponent(
|
|||||||
class RootFactory(
|
class RootFactory(
|
||||||
private val tokenStorage: TokenStorage,
|
private val tokenStorage: TokenStorage,
|
||||||
private val heathCheck: HeathCheck,
|
private val heathCheck: HeathCheck,
|
||||||
private val imageLoaderProvider: ImageLoaderProvider
|
private val imageLoaderProvider: ImageLoaderProvider,
|
||||||
|
private val updateComponentFactory: UpdateComponentFactory
|
||||||
) {
|
) {
|
||||||
fun create(
|
fun create(
|
||||||
context: ComponentContext,
|
context: ComponentContext,
|
||||||
@@ -70,7 +81,8 @@ class RootFactory(
|
|||||||
tokenStorage,
|
tokenStorage,
|
||||||
listOf(Route.Loading(next = initStack.toSet())),
|
listOf(Route.Loading(next = initStack.toSet())),
|
||||||
heathCheck,
|
heathCheck,
|
||||||
imageLoaderProvider
|
imageLoaderProvider,
|
||||||
|
updateComponentFactory
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package ru.shadowsparky.ui.nav
|
package ru.shadowsparky.ui.nav
|
||||||
|
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import com.arkivanov.decompose.ExperimentalDecomposeApi
|
import com.arkivanov.decompose.ExperimentalDecomposeApi
|
||||||
import com.arkivanov.decompose.extensions.compose.stack.Children
|
import com.arkivanov.decompose.extensions.compose.stack.Children
|
||||||
@@ -7,8 +9,9 @@ import com.arkivanov.decompose.extensions.compose.stack.animation.fade
|
|||||||
import com.arkivanov.decompose.extensions.compose.stack.animation.predictiveback.androidPredictiveBackAnimatableV2
|
import com.arkivanov.decompose.extensions.compose.stack.animation.predictiveback.androidPredictiveBackAnimatableV2
|
||||||
import com.arkivanov.decompose.extensions.compose.stack.animation.predictiveback.predictiveBackAnimation
|
import com.arkivanov.decompose.extensions.compose.stack.animation.predictiveback.predictiveBackAnimation
|
||||||
import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation
|
import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation
|
||||||
|
import ru.shadowsparky.ui.theme.getColorScheme
|
||||||
|
|
||||||
@OptIn(ExperimentalDecomposeApi::class)
|
@OptIn(ExperimentalDecomposeApi::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun Nav(
|
fun Nav(
|
||||||
rootComponent: BaseRootComponent<*>,
|
rootComponent: BaseRootComponent<*>,
|
||||||
@@ -23,6 +26,8 @@ fun Nav(
|
|||||||
selector = { backEvent, _, _ -> androidPredictiveBackAnimatableV2(backEvent) },
|
selector = { backEvent, _, _ -> androidPredictiveBackAnimatableV2(backEvent) },
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
|
MaterialTheme(getColorScheme()) {
|
||||||
process(it.instance, it.configuration as Route)
|
process(it.instance, it.configuration as Route)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
<manifest xmlns:tools="http://schemas.android.com/tools"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"
|
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.REQUEST_INSTALL_PACKAGES"
|
||||||
tools:ignore="RequestInstallPackagesPolicy" />
|
tools:ignore="RequestInstallPackagesPolicy" />
|
||||||
|
|
||||||
<application>
|
<application>
|
||||||
|
<receiver
|
||||||
|
android:name=".presentation.UpdateInstalledReceiver"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="${applicationId}.provider"
|
android:authorities="${applicationId}.provider"
|
||||||
|
|||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
package ru.shadowsparky.updater.presentation
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import ru.shadowsparky.koin
|
||||||
|
import ru.shadowsparky.updater.domain.UpdateDownloader
|
||||||
|
|
||||||
|
class UpdateInstalledReceiver : BroadcastReceiver() {
|
||||||
|
override fun onReceive(p0: Context?, p1: Intent?) {
|
||||||
|
if (p1?.action == Intent.ACTION_MY_PACKAGE_REPLACED) {
|
||||||
|
koin.getOrNull<UpdateDownloader>()?.let { downloader ->
|
||||||
|
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
|
val async = goAsync()
|
||||||
|
scope.launch {
|
||||||
|
try {
|
||||||
|
downloader.clean()
|
||||||
|
} finally {
|
||||||
|
async.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="updater_title_available">Доступно обновление</string>
|
<string name="updater_title_available">Доступно обновление на версию %1$s</string>
|
||||||
<string name="updater_title_not_found">Обновления не найдены</string>
|
<string name="updater_title_not_found">Обновления не найдены</string>
|
||||||
|
<string name="updater_title_completed">Обновление успешно установлено</string>
|
||||||
|
|
||||||
<string name="updater_btn_close">Закрыть</string>
|
<string name="updater_btn_close">Закрыть</string>
|
||||||
|
|
||||||
<string name="updater_btn_download">Скачать</string>
|
<string name="updater_btn_download">Скачать</string>
|
||||||
|
|||||||
+5
-1
@@ -1,6 +1,7 @@
|
|||||||
package ru.shadowsparky.updater.domain
|
package ru.shadowsparky.updater.domain
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import org.koin.core.annotation.Factory
|
import org.koin.core.annotation.Factory
|
||||||
import ru.shadowsparky.domain.AppConfig
|
import ru.shadowsparky.domain.AppConfig
|
||||||
@@ -53,7 +54,7 @@ class UpdateInteractor(
|
|||||||
return@flow
|
return@flow
|
||||||
}
|
}
|
||||||
emit(UpdateState.Downloading(0f, 0, 0))
|
emit(UpdateState.Downloading(0f, 0, 0))
|
||||||
downloader.download(url).collect { progress ->
|
downloader.download(url).firstOrNull { progress ->
|
||||||
when (progress) {
|
when (progress) {
|
||||||
is DownloadProgress.Active -> {
|
is DownloadProgress.Active -> {
|
||||||
emit(
|
emit(
|
||||||
@@ -63,12 +64,15 @@ class UpdateInteractor(
|
|||||||
totalBytes = progress.totalBytes
|
totalBytes = progress.totalBytes
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
false
|
||||||
}
|
}
|
||||||
is DownloadProgress.Success -> {
|
is DownloadProgress.Success -> {
|
||||||
emit(UpdateState.ReadyToInstall(filePath = progress.path))
|
emit(UpdateState.ReadyToInstall(filePath = progress.path))
|
||||||
|
true
|
||||||
}
|
}
|
||||||
is DownloadProgress.Error -> {
|
is DownloadProgress.Error -> {
|
||||||
emit(UpdateState.Error(message = progress.throwable.message ?: "Ошибка скачивания", throwable = progress.throwable))
|
emit(UpdateState.Error(message = progress.throwable.message ?: "Ошибка скачивания", throwable = progress.throwable))
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -20,6 +20,8 @@ sealed interface UpdateState {
|
|||||||
|
|
||||||
data object UpToDate : UpdateState
|
data object UpToDate : UpdateState
|
||||||
|
|
||||||
|
data object Completed : UpdateState
|
||||||
|
|
||||||
data class Downloading(
|
data class Downloading(
|
||||||
val progress: Float,
|
val progress: Float,
|
||||||
val downloadedBytes: Long,
|
val downloadedBytes: Long,
|
||||||
|
|||||||
+13
-3
@@ -8,6 +8,7 @@ import com.arkivanov.essenty.lifecycle.doOnResume
|
|||||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -26,6 +27,7 @@ class UpdateComponent(
|
|||||||
_state.value = UpdateState.Error(throwable.message ?: "$throwable", throwable)
|
_state.value = UpdateState.Error(throwable.message ?: "$throwable", throwable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var lastJob: Job? = null
|
||||||
private val scope = CoroutineScope(exceptionHandler + SupervisorJob() + Dispatchers.Main.immediate)
|
private val scope = CoroutineScope(exceptionHandler + SupervisorJob() + Dispatchers.Main.immediate)
|
||||||
|
|
||||||
private val _state = MutableValue<UpdateState>(UpdateState.Idle)
|
private val _state = MutableValue<UpdateState>(UpdateState.Idle)
|
||||||
@@ -47,7 +49,7 @@ class UpdateComponent(
|
|||||||
|
|
||||||
fun checkUpdates(byUser: Boolean = true) {
|
fun checkUpdates(byUser: Boolean = true) {
|
||||||
if (!hasSupport) return
|
if (!hasSupport) return
|
||||||
scope.launch {
|
lastJob = scope.launch {
|
||||||
interactor.checkUpdate().collect {
|
interactor.checkUpdate().collect {
|
||||||
isForceUpdate = (it as? UpdateState.UpdateAvailable)?.isForceUpdate ?: false
|
isForceUpdate = (it as? UpdateState.UpdateAvailable)?.isForceUpdate ?: false
|
||||||
_state.value = if (byUser) {
|
_state.value = if (byUser) {
|
||||||
@@ -66,12 +68,15 @@ class UpdateComponent(
|
|||||||
|
|
||||||
fun downloadUpdate(url: String) {
|
fun downloadUpdate(url: String) {
|
||||||
pendingUrl = url
|
pendingUrl = url
|
||||||
scope.launch {
|
lastJob = scope.launch {
|
||||||
interactor.startDownload(url).collect { newState ->
|
interactor.startDownload(url).collect { newState ->
|
||||||
_state.value = newState
|
_state.value = newState
|
||||||
if (newState !is UpdateState.InstallPermissionRequired) {
|
if (newState !is UpdateState.InstallPermissionRequired) {
|
||||||
pendingUrl = null
|
pendingUrl = null
|
||||||
}
|
}
|
||||||
|
if (newState is UpdateState.ReadyToInstall) {
|
||||||
|
installApk(newState.filePath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,12 +86,17 @@ class UpdateComponent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun installApk(path: String) {
|
fun installApk(path: String) {
|
||||||
scope.launch { interactor.installApk(path) }
|
scope.launch {
|
||||||
|
_state.value = UpdateState.Checking
|
||||||
|
interactor.installApk(path)
|
||||||
|
_state.value = UpdateState.Completed
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reset() {
|
fun reset() {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
_state.value = UpdateState.Checking
|
_state.value = UpdateState.Checking
|
||||||
|
if (lastJob?.isActive == true) lastJob?.cancel()
|
||||||
interactor.reset()
|
interactor.reset()
|
||||||
_state.value = UpdateState.Idle
|
_state.value = UpdateState.Idle
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-10
@@ -11,12 +11,12 @@ import androiddev.libs.updater.updater_client.generated.resources.updater_change
|
|||||||
import androiddev.libs.updater.updater_client.generated.resources.updater_desc_permission
|
import androiddev.libs.updater.updater_client.generated.resources.updater_desc_permission
|
||||||
import androiddev.libs.updater.updater_client.generated.resources.updater_download_progress
|
import androiddev.libs.updater.updater_client.generated.resources.updater_download_progress
|
||||||
import androiddev.libs.updater.updater_client.generated.resources.updater_title_available
|
import androiddev.libs.updater.updater_client.generated.resources.updater_title_available
|
||||||
|
import androiddev.libs.updater.updater_client.generated.resources.updater_title_completed
|
||||||
import androiddev.libs.updater.updater_client.generated.resources.updater_title_downloading
|
import androiddev.libs.updater.updater_client.generated.resources.updater_title_downloading
|
||||||
import androiddev.libs.updater.updater_client.generated.resources.updater_title_error
|
import androiddev.libs.updater.updater_client.generated.resources.updater_title_error
|
||||||
import androiddev.libs.updater.updater_client.generated.resources.updater_title_not_found
|
import androiddev.libs.updater.updater_client.generated.resources.updater_title_not_found
|
||||||
import androiddev.libs.updater.updater_client.generated.resources.updater_title_permission
|
import androiddev.libs.updater.updater_client.generated.resources.updater_title_permission
|
||||||
import androiddev.libs.updater.updater_client.generated.resources.updater_title_ready
|
import androiddev.libs.updater.updater_client.generated.resources.updater_title_ready
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@@ -24,23 +24,23 @@ import androidx.compose.foundation.layout.Spacer
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material3.BasicAlertDialog
|
import androidx.compose.material3.BasicAlertDialog
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.LinearProgressIndicator
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||||
|
import org.jetbrains.compose.resources.StringResource
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
import ru.shadowsparky.ui.components.Loading
|
import ru.shadowsparky.ui.components.Loading
|
||||||
import ru.shadowsparky.updater.domain.UpdateState
|
import ru.shadowsparky.updater.domain.UpdateState
|
||||||
@@ -63,11 +63,12 @@ fun UpdateDialog(
|
|||||||
canDismiss,
|
canDismiss,
|
||||||
),
|
),
|
||||||
content = {
|
content = {
|
||||||
Box(
|
Surface(
|
||||||
modifier = Modifier.clip(RoundedCornerShape(28.dp))
|
shape = MaterialTheme.shapes.extraLarge,
|
||||||
.background(MaterialTheme.colorScheme.surfaceContainerHigh)
|
color = MaterialTheme.colorScheme.surface,
|
||||||
.padding(16.dp)
|
contentColor = MaterialTheme.colorScheme.onSurface
|
||||||
) {
|
) {
|
||||||
|
Box(modifier = Modifier.padding(16.dp)) {
|
||||||
when (val currentState = state) {
|
when (val currentState = state) {
|
||||||
is UpdateState.Checking -> UpdateCheckingContent()
|
is UpdateState.Checking -> UpdateCheckingContent()
|
||||||
is UpdateState.UpdateAvailable -> UpdateAvailableContent(
|
is UpdateState.UpdateAvailable -> UpdateAvailableContent(
|
||||||
@@ -91,12 +92,19 @@ fun UpdateDialog(
|
|||||||
onRetryClick = { component.checkUpdates() }
|
onRetryClick = { component.checkUpdates() }
|
||||||
)
|
)
|
||||||
is UpdateState.UpToDate -> {
|
is UpdateState.UpToDate -> {
|
||||||
UpdateNotFoundContent(onSkip = { component.reset() })
|
UpdateFinishedContent(onSkip = { component.reset() })
|
||||||
|
}
|
||||||
|
is UpdateState.Completed -> {
|
||||||
|
UpdateFinishedContent(
|
||||||
|
Res.string.updater_title_completed,
|
||||||
|
onSkip = { component.reset() }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,7 +208,8 @@ private fun UpdateReadyContent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun UpdateNotFoundContent(
|
private fun UpdateFinishedContent(
|
||||||
|
text: StringResource = Res.string.updater_title_not_found,
|
||||||
onSkip: () -> Unit,
|
onSkip: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
@@ -209,7 +218,7 @@ private fun UpdateNotFoundContent(
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(Res.string.updater_title_not_found), style = MaterialTheme.typography.titleLarge)
|
Text(text = stringResource(text), style = MaterialTheme.typography.titleLarge)
|
||||||
Button(onClick = onSkip, modifier = Modifier.fillMaxWidth()) {
|
Button(onClick = onSkip, modifier = Modifier.fillMaxWidth()) {
|
||||||
Text(stringResource(Res.string.updater_btn_close), style = MaterialTheme.typography.labelLarge)
|
Text(stringResource(Res.string.updater_btn_close), style = MaterialTheme.typography.labelLarge)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user