Fixed notification system issues and plugin auto update.

This commit is contained in:
Koen J
2026-04-29 13:07:14 +02:00
parent 64938dba6c
commit bb8a9d4dd7
3 changed files with 92 additions and 30 deletions
@@ -15,6 +15,7 @@ import com.futo.platformplayer.R
import com.futo.platformplayer.Settings
import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.states.StateAnnouncement
import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.states.StateBackup
import com.google.android.material.button.MaterialButton
@@ -81,6 +82,8 @@ class AutomaticBackupDialog(context: Context) : AlertDialog(context) {
Settings.instance.backup.didAskAutoBackup = true
Settings.instance.save()
StateAnnouncement.instance.deleteAnnouncement("backup")
UIDialogs.toast(context, context.getString(R.string.automatic_backup_enabled))
try {
StateBackup.startAutomaticBackup(true)
@@ -1,5 +1,6 @@
package com.futo.platformplayer.states
import android.content.Context
import android.view.View
import android.view.WindowManager
import com.futo.platformplayer.R
@@ -122,7 +123,7 @@ class StateAnnouncement {
//Special Announcements
fun registerPluginUpdate(oldConfig: SourcePluginConfig, newConfig: SourcePluginConfig): SessionAnnouncement {
val announcement = SessionAnnouncement(
"update-plugin-" + UUID.randomUUID().toString(),
"update-plugin-" + oldConfig.id + "-v" + newConfig.version,
"${newConfig.name} update v${newConfig.version} available!",
"An update is available to upgrade from ${oldConfig.version} to ${newConfig.version}.",
AnnouncementType.SESSION,
@@ -130,19 +131,62 @@ class StateAnnouncement {
null, null,oldConfig.id,
newConfig?.absoluteIconUrl?.let { ImageVariable.fromUrl(it) }
).withExtraAction("Changelog", StateAnnouncement.ACTION_CHANGELOG, oldConfig.id);
announcement.extraObj = newConfig;
registerAnnouncementSession(announcement);
return announcement;
}
fun registerPluginUpdated(newConfig: SourcePluginConfig) {
registerAnnouncementSession(SessionAnnouncement(
"updated-plugin-" + UUID.randomUUID().toString(),
val announcement = SessionAnnouncement(
"updated-plugin-" + newConfig.id + "-v" + newConfig.version,
"${newConfig.name} updated to v${newConfig.version}!",
"You have succesfully been updated to v${newConfig.version}.",
AnnouncementType.SESSION,
null, "updates", null, null,
null, null,null,
newConfig?.absoluteIconUrl?.let { ImageVariable.fromUrl(it) }
).withExtraAction("Changelog", StateAnnouncement.ACTION_CHANGELOG, newConfig.id));
).withExtraAction("Changelog", StateAnnouncement.ACTION_CHANGELOG, newConfig.id);
announcement.extraObj = newConfig;
registerAnnouncementSession(announcement);
}
fun tryAutoUpdatePlugin(oldConfig: SourcePluginConfig, newConfig: SourcePluginConfig) {
val context = StateApp.instance.contextOrNull;
if(context == null) {
registerPluginUpdate(oldConfig, newConfig);
return;
}
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
try {
val client = ManagedHttpClient();
client.setTimeout(10000);
val oldScript = StatePlugins.instance.getScript(oldConfig.id) ?: "";
val newScript = client.get(newConfig.absoluteScriptUrl)?.body?.string();
if(newScript.isNullOrEmpty()) {
Logger.w(TAG, "Auto-update for ${oldConfig.name}: no script returned, falling back to notification");
withContext(Dispatchers.Main) { registerPluginUpdate(oldConfig, newConfig); }
return@launch;
}
if(!oldConfig.isLowRiskUpdate(oldScript, newConfig, newScript)) {
withContext(Dispatchers.Main) { registerPluginUpdate(oldConfig, newConfig); }
return@launch;
}
StatePlugins.instance.installPluginBackground(context, StateApp.instance.scope, newConfig, newScript,
{ _: String, _: Double -> },
{ ex ->
if(ex == null) {
registerPluginUpdated(newConfig);
} else {
Logger.e(TAG, "Auto-update for ${newConfig.name} failed during install", ex);
UIDialogs.appToast("Update for ${newConfig.name} failed\n" + ex.message);
}
});
} catch(ex: Throwable) {
Logger.e(TAG, "Auto-update for ${oldConfig.name} failed", ex);
withContext(Dispatchers.Main) { registerPluginUpdate(oldConfig, newConfig); }
}
}
}
fun registerLoading(title: String, description: String, icon: ImageVariable? = null, customId: String? = null): SessionAnnouncement {
@@ -282,7 +326,7 @@ class StateAnnouncement {
when (actionId) {
ACTION_NEVER -> neverAnnouncement(item.id);
ACTION_SOMETHING -> actionSomething();
ACTION_CHANGELOG -> actionChangelog(actionData);
ACTION_CHANGELOG -> actionChangelog(item, actionData);
ACTION_UPDATE_PLUGIN -> actionUpdatePlugin(item.id, actionData);
}
}
@@ -314,26 +358,34 @@ class StateAnnouncement {
}
private fun actionChangelog(id: String?) {
if(id == null)
private fun actionChangelog(item: Announcement, id: String?) {
val context = StateApp.instance.contextOrNull ?: return;
val cached = (item as? SessionAnnouncement)?.extraObj as? SourcePluginConfig;
if(cached != null) {
showPluginChangelog(context, cached);
return;
}
if(id == null) return;
StateApp.instance.contextOrNull?.let { context ->
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
val plugin = StatePlugins.instance.getPlugin(id);
if (plugin == null)
return@launch
val update = StatePlugins.instance.checkForUpdates(plugin.config);
if(update == null)
return@launch;
val plugin = StatePlugins.instance.getPlugin(id) ?: return@launch;
val update = StatePlugins.instance.checkForUpdates(plugin.config) ?: return@launch;
withContext(Dispatchers.Main) {
showPluginChangelog(context, update);
}
}
}
StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) {
UIDialogs.showChangelogDialog(context, update.version, update.changelog!!.filterKeys { it.toIntOrNull() != null }
private fun showPluginChangelog(context: Context, config: SourcePluginConfig) {
if(config.changelog?.any() != true) {
UIDialogs.toast(context, "No changelog available");
return;
}
UIDialogs.showChangelogDialog(context, config.version, config.changelog!!.filterKeys { it.toIntOrNull() != null }
.mapKeys { it.key.toInt() }
.mapValues { update.getChangelogString(it.key.toString()) ?: "" });
}
}
}
.mapValues { config.getChangelogString(it.key.toString()) ?: "" });
}
private fun actionUpdatePlugin(notifId: String?, id: String?) {
if(id == null)
@@ -363,7 +415,7 @@ class StateAnnouncement {
if(newScript.isNullOrEmpty())
throw IllegalStateException("No script found");
if(true || plugin.config.isLowRiskUpdate(script, update, newScript)) {
if(plugin.config.isLowRiskUpdate(script, update, newScript)) {
StatePlugins.instance.installPluginBackground(context, StateApp.instance.scope, update, newScript,
{ text: String, progress: Double -> },
{ ex ->
@@ -34,6 +34,7 @@ import com.futo.platformplayer.activities.IWithResultLauncher
import com.futo.platformplayer.activities.MainActivity
import com.futo.platformplayer.api.media.platforms.js.DevJSClient
import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
import com.futo.platformplayer.background.BackgroundWorker
import com.futo.platformplayer.casting.StateCasting
import com.futo.platformplayer.constructs.Event0
@@ -804,15 +805,24 @@ class StateApp {
if(StateHistory.instance.shouldMigrateLegacyHistory())
StateHistory.instance.migrateLegacyHistory();
StateAnnouncement.instance.deleteAnnouncement("plugin-update")
scopeOrNull?.launch(Dispatchers.IO) {
val updateAvailable = StatePlugins.instance.checkForUpdates()
withContext(Dispatchers.Main) {
if (updateAvailable.isNotEmpty()) {
val toNotify = mutableListOf<Pair<SourcePluginConfig, SourcePluginConfig>>();
for(update in updateAvailable) {
if(!StatePlatform.instance.isClientEnabled(update.first.id))
continue;
val descriptor = StatePlugins.instance.getPlugin(update.first.id);
if(descriptor?.appSettings?.automaticUpdate == true)
StateAnnouncement.instance.tryAutoUpdatePlugin(update.first, update.second);
else
toNotify.add(update);
}
if(toNotify.isNotEmpty()) {
UIDialogs.appToast(
ToastView.Toast(updateAvailable
ToastView.Toast(toNotify
.map { " - " + it.first.name }
.joinToString("\n"),
true,
@@ -820,14 +830,11 @@ class StateApp {
"Plugin updates available"
));
for(update in updateAvailable)
if(StatePlatform.instance.isClientEnabled(update.first.id)) {
//UIDialogs.showPluginUpdateDialog(context, update.first, update.second);
for(update in toNotify)
StateAnnouncement.instance.registerPluginUpdate(update.first, update.second);
}
}
}
}
scopeOrNull?.launch(Dispatchers.IO) {
val enabledPlugins = StatePlatform.instance.getEnabledClients();