add check updates

This commit is contained in:
hhu67 2026-08-20 23:13:26 +03:00
parent 6f3350b44c
commit c896a6b1a8
4 changed files with 96 additions and 0 deletions

View file

@ -43,3 +43,10 @@ data class AnswerBotList(
@SerializedName("total") val total: Int, @SerializedName("total") val total: Int,
@SerializedName("items") val items: List<AnswerBot>? @SerializedName("items") val items: List<AnswerBot>?
) )
data class ReleaseInfo(
@SerializedName("tag_name") val tagName: String,
@SerializedName("name") val name: String?,
@SerializedName("body") val body: String?,
@SerializedName("html_url") val htmlUrl: String
)

View file

@ -18,6 +18,11 @@ interface IpService {
suspend fun getIpInfo(): IpInfo suspend fun getIpInfo(): IpInfo
} }
interface ForgejoService {
@GET("api/v1/repos/hhu67/sergay-app/releases/latest")
suspend fun getLatestRelease(): ReleaseInfo
}
interface ApiService { interface ApiService {
@FormUrlEncoded @FormUrlEncoded
@POST("api/login") @POST("api/login")
@ -116,5 +121,13 @@ interface ApiService {
.build() .build()
.create(IpService::class.java) .create(IpService::class.java)
} }
fun createForgejoService(): ForgejoService {
return Retrofit.Builder()
.baseUrl("https://code.hhu67.pw/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ForgejoService::class.java)
}
} }
} }

View file

@ -19,6 +19,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
@ -41,6 +42,7 @@ import kotlin.system.exitProcess
@Composable @Composable
fun MainAppScreen(vm: MainViewModel) { fun MainAppScreen(vm: MainViewModel) {
val ctx = LocalContext.current val ctx = LocalContext.current
val uriHandler = LocalUriHandler.current
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
@ -178,6 +180,41 @@ fun MainAppScreen(vm: MainViewModel) {
icon = { Icon(Icons.Default.BrightnessLow, contentDescription = null, tint = Color.Blue) }, icon = { Icon(Icons.Default.BrightnessLow, contentDescription = null, tint = Color.Blue) },
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding) modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
) )
Spacer(Modifier.weight(1f))
HorizontalDivider()
NavigationDrawerItem(
label = {
Column {
Text("Проверить обновления")
if (vm.updateCheckMessage.isNotEmpty()) {
Text(vm.updateCheckMessage, style = MaterialTheme.typography.labelSmall, color = Color.Gray)
}
}
},
selected = false,
onClick = {
vm.checkForUpdates("1.0")
},
icon = {
if (vm.isCheckingUpdates) {
CircularProgressIndicator(modifier = Modifier.size(24.dp), strokeWidth = 2.dp)
} else {
Icon(Icons.Default.Update, contentDescription = null)
}
},
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
)
vm.updateInfo?.let { info ->
NavigationDrawerItem(
label = { Text("Скачать ${info.tagName}", color = MaterialTheme.colorScheme.primary) },
selected = false,
onClick = {
uriHandler.openUri(info.htmlUrl)
},
icon = { Icon(Icons.Default.Download, contentDescription = null, tint = MaterialTheme.colorScheme.primary) },
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
)
}
} }
} }
) { ) {

View file

@ -1,8 +1,13 @@
package com.sergay.hhu67.pw.app.ui.viewmodel package com.sergay.hhu67.pw.app.ui.viewmodel
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.core.content.FileProvider
import androidx.core.content.edit import androidx.core.content.edit
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
@ -10,10 +15,17 @@ import androidx.lifecycle.viewModelScope
import com.sergay.hhu67.pw.app.data.models.* import com.sergay.hhu67.pw.app.data.models.*
import com.sergay.hhu67.pw.app.data.network.ApiService import com.sergay.hhu67.pw.app.data.network.ApiService
import com.sergay.hhu67.pw.app.data.network.globalCookieJar import com.sergay.hhu67.pw.app.data.network.globalCookieJar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
import java.io.FileOutputStream
import kotlin.math.ceil import kotlin.math.ceil
enum class AppTab(val title: String) { enum class AppTab(val title: String) {
@ -65,6 +77,12 @@ class MainViewModel(appContext: Context) : ViewModel() {
var inoagentModeActive by mutableStateOf(false) var inoagentModeActive by mutableStateOf(false)
var showInoagentDialog by mutableStateOf(false) var showInoagentDialog by mutableStateOf(false)
var updateInfo by mutableStateOf<ReleaseInfo?>(null)
var isCheckingUpdates by mutableStateOf(false)
var updateCheckMessage by mutableStateOf("")
private val forgejo = ApiService.createForgejoService()
init { init {
if (isAuthenticated) { if (isAuthenticated) {
checkRoleAndRestore() checkRoleAndRestore()
@ -290,6 +308,27 @@ class MainViewModel(appContext: Context) : ViewModel() {
inoagentModeActive = true inoagentModeActive = true
} }
fun checkForUpdates(currentVersion: String) {
viewModelScope.launch {
isCheckingUpdates = true
updateCheckMessage = ""
updateInfo = null
try {
val latest = forgejo.getLatestRelease()
if (latest.tagName != currentVersion) {
updateInfo = latest
updateCheckMessage = "Доступно обновление: ${latest.tagName}"
} else {
updateCheckMessage = "У вас последняя версия"
}
} catch (e: Exception) {
updateCheckMessage = "Ошибка проверки: ${e.localizedMessage}"
} finally {
isCheckingUpdates = false
}
}
}
fun deleteBotPhrase(id: Int) { fun deleteBotPhrase(id: Int) {
viewModelScope.launch { viewModelScope.launch {
try { try {