Newer
Older
package org.futo.inputmethod.updates
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.widget.Toast
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowForward
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.res.booleanResource
import androidx.compose.ui.tooling.preview.Preview
Aleksandras Kostarevas
committed
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
Aleksandras Kostarevas
committed
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
Aleksandras Kostarevas
committed
import org.futo.inputmethod.latin.BuildConfig
import org.futo.inputmethod.latin.R
import org.futo.inputmethod.latin.uix.SettingsKey
import org.futo.inputmethod.latin.uix.getSetting
import org.futo.inputmethod.latin.uix.setSetting
import org.futo.inputmethod.latin.uix.settings.SettingItem
import org.futo.inputmethod.latin.uix.settings.pages.ParagraphText
import org.futo.inputmethod.latin.uix.settings.pages.PaymentSurface
import org.futo.inputmethod.latin.uix.settings.pages.PaymentSurfaceHeading
import org.futo.inputmethod.latin.uix.settings.useDataStore
val LAST_UPDATE_CHECK_RESULT = stringPreferencesKey("last_update_check_result")
Aleksandras Kostarevas
committed
val LAST_UPDATE_CHECK_FAILED = booleanPreferencesKey("last_update_check_failed")
val DISABLE_UPDATE_REMINDER = SettingsKey(booleanPreferencesKey("disable_update_reminder"), false)
val DEFER_MANUAL_UPDATE_UNTIL = longPreferencesKey("defer_manual_update_until")
const val MANUAL_UPDATE_PERIOD_MS = 1000L * 60L * 60L * 24L * 14L // Every two weeks
suspend fun deferManualUpdate(context: Context) {
context.setSetting(
DEFER_MANUAL_UPDATE_UNTIL,
System.currentTimeMillis() + MANUAL_UPDATE_PERIOD_MS
)
}
suspend fun isManualUpdateTimeExpired(context: Context): Boolean {
if(context.getSetting(DISABLE_UPDATE_REMINDER)) {
return false
}
val defermentTime = context.getSetting(DEFER_MANUAL_UPDATE_UNTIL, Long.MAX_VALUE)
return (System.currentTimeMillis() > defermentTime)
}
val LAST_VERSION = longPreferencesKey("last_version")
suspend fun autoDeferManualUpdateIfNeeded(context: Context) {
if(context.getSetting(LAST_VERSION, 0L) != BuildConfig.VERSION_CODE.toLong()) {
context.setSetting(LAST_VERSION, BuildConfig.VERSION_CODE.toLong())
deferManualUpdate(context)
}
}
fun Context.openURI(uri: String, newTask: Boolean = false) {
try {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(uri))
if (newTask) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
startActivity(intent)
} catch(e: ActivityNotFoundException) {
Toast.makeText(this, e.localizedMessage, Toast.LENGTH_SHORT).show()
}
}
fun Context.openManualUpdateCheck() {
openURI("https://keyboard.futo.org/manual_update?version=${BuildConfig.VERSION_CODE}&build=${BuildConfig.FLAVOR}", newTask = true)
fun ConditionalUpdate(navController: NavHostController = rememberNavController()) {
if(!BuildConfig.UPDATE_CHECKING) return
val (updateInfo, _) = useDataStore(key = LAST_UPDATE_CHECK_RESULT, default = "")
Aleksandras Kostarevas
committed
val (lastFailed, _) = useDataStore(key = LAST_UPDATE_CHECK_FAILED, default = false)
val lastUpdateResult = if(!LocalInspectionMode.current){
UpdateResult.fromString(updateInfo)
} else {
UpdateResult(123, "abc", "1.2.3")
}
val context = LocalContext.current
if(lastUpdateResult != null && lastUpdateResult.isNewer()) {
SettingItem(
title = "Update Available",
subtitle = "${UpdateResult.currentVersionString()} -> ${lastUpdateResult.nextVersionString}",
onClick = {
Aleksandras Kostarevas
committed
navController.navigate("update")
//context.openURI(lastUpdateResult.apkUrl)
}
) {
Icon(Icons.Default.ArrowForward, contentDescription = "Go")
}
Aleksandras Kostarevas
committed
} else if(lastFailed) {
SettingItem(
title = "Check for updates manually",
Aleksandras Kostarevas
committed
onClick = {
context.openManualUpdateCheck()
Aleksandras Kostarevas
committed
}
) {
Icon(Icons.Default.ArrowForward, contentDescription = "Go")
}
val dismissedMigrateUpdateNotice = SettingsKey(
key = booleanPreferencesKey("dismissedMigrateFdroidObtainiumNotice"),
default = BuildConfig.IS_PLAYSTORE_BUILD
)
@Composable
@Preview
fun ConditionalMigrateUpdateNotice() {
val context = LocalContext.current
val value = useDataStore(dismissedMigrateUpdateNotice, blocking = true)
if(!value.value) {
PaymentSurface(isPrimary = true) {
ParagraphText("This app doesn't connect to the internet and it won't be able to check for automatic updates. You can check for updates manually though.")
if(booleanResource(R.bool.use_dev_styling)) {
ParagraphText("You are on the development build of FUTO Keyboard. Visit keyboard.futo.org if you want to download the stable build.")
} else {
ParagraphText("Please use F-Droid or Obtainium for automatic updates. Visit keyboard.futo.org for download options.")
}
modifier = Modifier.fillMaxWidth()
) {
Box(modifier = Modifier.weight(1.0f)) {
Button(onClick = {
context.openURI("https://keyboard.futo.org/#downloads")
}, modifier = Modifier.align(Alignment.Center)) {
Text("Visit")
}
Box(modifier = Modifier.weight(1.0f)) {
Button(
onClick = { value.setValue(true) },
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.secondary,
contentColor = MaterialTheme.colorScheme.onSecondary
), modifier = Modifier.align(Alignment.Center)
) {
Text("Dismiss")
}
}
}
}
}
}