forked from akanyan/STARTLINER
feat: autoupdate ui
This commit is contained in:
@ -11,6 +11,7 @@ use tauri::AppHandle;
|
|||||||
|
|
||||||
pub struct GlobalState {
|
pub struct GlobalState {
|
||||||
pub remain_open: bool,
|
pub remain_open: bool,
|
||||||
|
pub has_updated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AppData {
|
pub struct AppData {
|
||||||
@ -49,7 +50,7 @@ impl AppData {
|
|||||||
profile: profile,
|
profile: profile,
|
||||||
pkgs: PackageStore::new(apph.clone()),
|
pkgs: PackageStore::new(apph.clone()),
|
||||||
cfg,
|
cfg,
|
||||||
state: GlobalState { remain_open: true },
|
state: GlobalState { remain_open: true, has_updated: false },
|
||||||
patch_set
|
patch_set
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -469,4 +469,12 @@ pub async fn list_patches(state: State<'_, Mutex<AppData>>, target: String) -> R
|
|||||||
let list = appd.patch_set.find_patches(target).map_err(|e| e.to_string())?;
|
let list = appd.patch_set.find_patches(target).map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
Ok(list)
|
Ok(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn has_updated(state: State<'_, Mutex<AppData>>) -> Result<bool, ()> {
|
||||||
|
log::debug!("invoke: has_updated");
|
||||||
|
|
||||||
|
let appd = state.lock().await;
|
||||||
|
Ok(appd.state.has_updated)
|
||||||
}
|
}
|
@ -17,10 +17,9 @@ use fern::colors::{Color, ColoredLevelConfig};
|
|||||||
use model::misc::Game;
|
use model::misc::Game;
|
||||||
use pkg::PkgKey;
|
use pkg::PkgKey;
|
||||||
use pkg_store::Payload;
|
use pkg_store::Payload;
|
||||||
use tauri::{AppHandle, Listener, Manager, RunEvent};
|
use tauri::{AppHandle, Emitter, Listener, Manager, RunEvent};
|
||||||
use tauri_plugin_deep_link::DeepLinkExt;
|
use tauri_plugin_deep_link::DeepLinkExt;
|
||||||
use tauri_plugin_cli::CliExt;
|
use tauri_plugin_cli::CliExt;
|
||||||
use tauri_plugin_updater::UpdaterExt;
|
|
||||||
use tokio::{fs, sync::Mutex, try_join};
|
use tokio::{fs, sync::Mutex, try_join};
|
||||||
|
|
||||||
static EXIT_REQUESTED: OnceLock<()> = OnceLock::new();
|
static EXIT_REQUESTED: OnceLock<()> = OnceLock::new();
|
||||||
@ -248,7 +247,9 @@ pub async fn run(_args: Vec<String>) {
|
|||||||
|
|
||||||
cmd::list_com_ports,
|
cmd::list_com_ports,
|
||||||
|
|
||||||
cmd::list_patches
|
cmd::list_patches,
|
||||||
|
|
||||||
|
cmd::has_updated,
|
||||||
])
|
])
|
||||||
.build(tauri::generate_context!())
|
.build(tauri::generate_context!())
|
||||||
.expect("error while building tauri application");
|
.expect("error while building tauri application");
|
||||||
@ -309,28 +310,56 @@ fn deep_link(app: AppHandle, args: Vec<String>) {
|
|||||||
|
|
||||||
async fn update(app: tauri::AppHandle) -> tauri_plugin_updater::Result<()> {
|
async fn update(app: tauri::AppHandle) -> tauri_plugin_updater::Result<()> {
|
||||||
let mutex = app.state::<Mutex<AppData>>();
|
let mutex = app.state::<Mutex<AppData>>();
|
||||||
let appd = mutex.lock().await;
|
{
|
||||||
if !appd.cfg.enable_autoupdates {
|
let mut appd = mutex.lock().await;
|
||||||
log::info!("skipping autoupdate");
|
if !appd.cfg.enable_autoupdates {
|
||||||
return Ok(());
|
log::info!("skipping auto-update");
|
||||||
|
|
||||||
|
// The frontend may not be available at this point
|
||||||
|
// So emit isn't suitable
|
||||||
|
appd.state.has_updated = true;
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(update) = app.updater()?.check().await? {
|
#[cfg(not(debug_assertions))]
|
||||||
|
{
|
||||||
|
use tauri_plugin_updater::UpdaterExt;
|
||||||
|
if let Some(update) = app.updater()?.check().await? {
|
||||||
|
let mut downloaded = 0;
|
||||||
|
update.download_and_install(
|
||||||
|
|chunk_length, content_length| {
|
||||||
|
downloaded += chunk_length;
|
||||||
|
_ = app.emit("update-progress", (chunk_length as f64) / (content_length.unwrap_or(u64::MAX) as f64));
|
||||||
|
},
|
||||||
|
|| {
|
||||||
|
log::info!("download finished");
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
log::info!("update installed");
|
||||||
|
app.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// One day I will write proper tests
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(2000));
|
||||||
let mut downloaded = 0;
|
let mut downloaded = 0;
|
||||||
update.download_and_install(
|
while downloaded < 200 {
|
||||||
|chunk_length, content_length| {
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||||
downloaded += chunk_length;
|
downloaded += 1;
|
||||||
log::debug!("downloaded {downloaded} from {content_length:?}");
|
app.emit("update-progress", (downloaded as f32) / 200f32)?;
|
||||||
},
|
}
|
||||||
|| {
|
|
||||||
log::info!("download finished");
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
log::info!("update installed");
|
|
||||||
app.restart();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log::info!("ending auto-update check");
|
||||||
|
|
||||||
|
let mut appd = mutex.lock().await;
|
||||||
|
appd.state.has_updated = true;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "STARTLINER",
|
"productName": "STARTLINER",
|
||||||
"version": "0.5.0",
|
"version": "0.6.0",
|
||||||
"identifier": "zip.patafour.startliner",
|
"identifier": "zip.patafour.startliner",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "bun run dev",
|
"beforeDevCommand": "bun run dev",
|
||||||
|
@ -40,10 +40,30 @@ const pkgSearchTerm = ref('');
|
|||||||
|
|
||||||
const isProfileDisabled = computed(() => prf.current === null);
|
const isProfileDisabled = computed(() => prf.current === null);
|
||||||
|
|
||||||
|
const updateVisible = ref(false);
|
||||||
|
const updateProgress = ref(-1);
|
||||||
|
|
||||||
|
const hasUpdatedCheck = async () => {
|
||||||
|
const res = await invoke('has_updated');
|
||||||
|
if (res == false) {
|
||||||
|
updateVisible.value = true;
|
||||||
|
setTimeout(hasUpdatedCheck, 200);
|
||||||
|
} else {
|
||||||
|
updateVisible.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
listen<number>('update-progress', (ev) => {
|
||||||
|
updateProgress.value = ev.payload;
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
invoke('list_directories').then((d) => {
|
invoke('list_directories').then((d) => {
|
||||||
general.dirs = d as Dirs;
|
general.dirs = d as Dirs;
|
||||||
client.load();
|
client.load();
|
||||||
|
if (client.enableAutoupdates) {
|
||||||
|
hasUpdatedCheck();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetch_promise = pkg.fetch(true);
|
const fetch_promise = pkg.fetch(true);
|
||||||
@ -135,6 +155,17 @@ listen<{ message: string; header: string }>('invoke-error', (event) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
<Dialog
|
||||||
|
modal
|
||||||
|
:visible="updateVisible"
|
||||||
|
:closable="false"
|
||||||
|
:header="updateProgress < 0 ? 'Checking for updates' : 'Updating'"
|
||||||
|
:style="{ width: '50vw' }"
|
||||||
|
>
|
||||||
|
<div v-if="updateProgress >= 0">
|
||||||
|
{{ (updateProgress * 100).toFixed(0) }}%
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
<Tabs
|
<Tabs
|
||||||
lazy
|
lazy
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
import { Ref, ref } from 'vue';
|
import { Ref, ref } from 'vue';
|
||||||
import * as path from '@tauri-apps/api/path';
|
import * as path from '@tauri-apps/api/path';
|
||||||
import OptionCategory from './OptionCategory.vue';
|
import OptionCategory from './OptionCategory.vue';
|
||||||
import OptionRow from './OptionRow.vue';
|
|
||||||
import PatchEntry from './PatchEntry.vue';
|
import PatchEntry from './PatchEntry.vue';
|
||||||
import { invoke } from '../invoke';
|
import { invoke } from '../invoke';
|
||||||
import { usePrfStore } from '../stores';
|
import { usePrfStore } from '../stores';
|
||||||
|
Reference in New Issue
Block a user