Show update size in modal

This commit is contained in:
Josiah Glosson
2025-07-07 12:26:53 -05:00
parent 523800ea39
commit 52d6bf3907
6 changed files with 112 additions and 12 deletions

View File

@@ -360,7 +360,7 @@ async function checkUpdates() {
return
}
const update = await check()
const update = await invoke('plugin:updater|check')
updateAvailable.value = !!update
if (updateAvailable.value) {
console.log(`Update ${update.version} is available. Showing update modal.`)

View File

@@ -1,6 +1,14 @@
<template>
<ModalWrapper ref="modal" :header="formatMessage(messages.header)">
<div>{{ formatMessage(messages.body, { version: update!.version }) }}</div>
<div>{{ formatMessage(messages.bodyVersion, { version: update!.version }) }}</div>
<div v-if="updateSize">
{{ formatMessage(messages.bodySize, { size: formatBytes(updateSize) }) }}
</div>
<div>
<a href="https://modrinth.com/news/changelog?filter=app">{{
formatMessage(messages.bodyChangelog)
}}</a>
</div>
<div class="mt-4 flex flex-wrap gap-2">
<ButtonStyled color="green">
<button>
@@ -26,9 +34,11 @@
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import { defineMessages, useVIntl } from '@vintl/vintl'
import { useTemplateRef, ref } from 'vue'
import type { Update } from '@tauri-apps/plugin-updater'
import { ButtonStyled } from '@modrinth/ui'
import { RefreshCwIcon } from '@modrinth/assets'
import { getUpdateSize } from '@/helpers/utils'
import { formatBytes } from '@modrinth/utils'
import { handleError } from '@/store/notifications'
const { formatMessage } = useVIntl()
@@ -37,17 +47,25 @@ const messages = defineMessages({
id: 'app.update.modal-header',
defaultMessage: 'An update is available!',
},
body: {
id: 'app.update.modal-body',
bodyVersion: {
id: 'app.update.modal-body-version',
defaultMessage: 'Version {version} of the Modrinth App is available for installation.',
},
bodySize: {
id: 'app.update.modal-body-size',
defaultMessage: 'The download is {size} in size.',
},
bodyChangelog: {
id: 'app.update.modal-body-changelog',
defaultMessage: 'Click here to view the changelog.',
},
restartNow: {
id: 'app.update.restart',
defaultMessage: 'Restart Now',
defaultMessage: 'Update Now',
},
later: {
id: 'app.update.later',
defaultMessage: 'Later',
defaultMessage: 'Update on Next Restart',
},
skip: {
id: 'app.update.skip',
@@ -55,13 +73,20 @@ const messages = defineMessages({
},
})
const update = ref<Update>()
type UpdateData = {
rid: number
version: string
}
const update = ref<UpdateData>()
const updateSize = ref<number>()
const modal = useTemplateRef('modal')
const isOpen = ref(false)
function show(newUpdate: Update) {
async function show(newUpdate: UpdateData) {
update.value = newUpdate
updateSize.value = await getUpdateSize(newUpdate.rid).catch(handleError)
modal.value!.show()
isOpen.value = true
}

View File

@@ -9,6 +9,10 @@ export async function areUpdatesEnabled() {
return await invoke('are_updates_enabled')
}
export async function getUpdateSize(updateRid) {
return await invoke('get_update_size', { rid: updateRid })
}
// One of 'Windows', 'Linux', 'MacOS'
export async function getOS() {
return await invoke('plugin:utils|get_os')

View File

@@ -21,16 +21,22 @@
"message": "Resource management"
},
"app.update.later": {
"message": "Later"
"message": "Update on Next Restart"
},
"app.update.modal-body": {
"app.update.modal-body-changelog": {
"message": "Click here to view the changelog."
},
"app.update.modal-body-size": {
"message": "The download is {size} in size."
},
"app.update.modal-body-version": {
"message": "Version {version} of the Modrinth App is available for installation."
},
"app.update.modal-header": {
"message": "An update is available!"
},
"app.update.restart": {
"message": "Restart Now"
"message": "Update Now"
},
"app.update.skip": {
"message": "Skip This Update"

View File

@@ -14,6 +14,9 @@ mod error;
#[cfg(target_os = "macos")]
mod macos;
#[cfg(feature = "updater")]
mod update_size_checker;
// Should be called in launcher initialization
#[tracing::instrument(skip_all)]
#[tauri::command]
@@ -64,6 +67,15 @@ fn are_updates_enabled() -> bool {
cfg!(feature = "updater")
}
#[cfg(feature = "updater")]
pub use update_size_checker::get_update_size;
#[cfg(not(feature = "updater"))]
#[tauri::command]
fn get_update_size() -> theseus::Result<()> {
Err(theseus::ErrorKind::OtherError("Updates are disabled in this build.".to_string()).into())
}
// Toggles decorations
#[tauri::command]
async fn toggle_decorations(b: bool, window: tauri::Window) -> api::Result<()> {
@@ -204,6 +216,7 @@ fn main() {
initialize_state,
is_dev,
are_updates_enabled,
get_update_size,
toggle_decorations,
show_window,
restart_app,

View File

@@ -0,0 +1,52 @@
use tauri::{Manager, ResourceId, Runtime, Webview};
use tauri::http::header::ACCEPT;
use tauri::http::HeaderValue;
use tauri_plugin_http::reqwest;
use tauri_plugin_http::reqwest::ClientBuilder;
use tauri_plugin_updater::Error;
use tauri_plugin_updater::Result;
const UPDATER_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
// Reimplementation of Update::download mostly, minus the actual download part
#[tauri::command]
pub async fn get_update_size<R: Runtime>(webview: Webview<R>, rid: ResourceId) -> Result<Option<u64>> {
use tauri_plugin_updater::Update;
let update = webview.resources_table().get::<Update>(rid)?;
let mut headers = update.headers.clone();
if !headers.contains_key(ACCEPT) {
headers.insert(ACCEPT, HeaderValue::from_static("application/octet-stream"));
}
let mut request = ClientBuilder::new().user_agent(UPDATER_USER_AGENT);
if let Some(timeout) = update.timeout {
request = request.timeout(timeout);
}
if let Some(ref proxy) = update.proxy {
let proxy = reqwest::Proxy::all(proxy.as_str())?;
request = request.proxy(proxy);
}
let response = request
.build()?
.get(update.download_url.clone())
.headers(headers)
.send()
.await?;
if !response.status().is_success() {
return Err(Error::Network(format!(
"Download request failed with status: {}",
response.status()
)).into());
}
let content_length = response
.headers()
.get("Content-Length")
.and_then(|value| value.to_str().ok())
.and_then(|value| value.parse().ok());
Ok(content_length)
}