Move update checking entirely into JS and open a modal if an update is available

This commit is contained in:
Josiah Glosson 2025-07-03 12:43:13 -05:00
parent 607c42cf01
commit e59dd086fc
4 changed files with 77 additions and 74 deletions

View File

@ -1,5 +1,5 @@
<script setup>
import { computed, onMounted, onUnmounted, ref, watch, provide } from 'vue'
import { computed, onMounted, onUnmounted, ref, watch, useTemplateRef, provide } from 'vue'
import { RouterView, useRoute, useRouter } from 'vue-router'
import {
ArrowBigUpDashIcon,
@ -42,7 +42,7 @@ import ModrinthLoadingIndicator from '@/components/LoadingIndicatorBar.vue'
import { handleError, useNotifications } from '@/store/notifications.js'
import { command_listener, warning_listener } from '@/helpers/events.js'
import { type } from '@tauri-apps/plugin-os'
import { getOS, isDev, restartApp } from '@/helpers/utils.js'
import {areUpdatesEnabled, getOS, isDev, restartApp} from '@/helpers/utils.js'
import { debugAnalytics, initAnalytics, optOutAnalytics, trackEvent } from '@/helpers/analytics'
import { getCurrentWindow } from '@tauri-apps/api/window'
import { getVersion } from '@tauri-apps/api/app'
@ -69,6 +69,7 @@ import { hide_ads_window, init_ads_window } from '@/helpers/ads.js'
import FriendsList from '@/components/ui/friends/FriendsList.vue'
import { openUrl } from '@tauri-apps/plugin-opener'
import QuickInstanceSwitcher from '@/components/ui/QuickInstanceSwitcher.vue'
import UpdateModal from "@/components/ui/UpdateModal.vue";
import { get_available_capes, get_available_skins } from './helpers/skins'
import { generateSkinPreviews } from './helpers/rendering/batch-skin-renderer'
@ -209,7 +210,6 @@ async function setupApp() {
})
get_opening_command().then(handleCommand)
checkUpdates()
fetchCredentials()
try {
@ -347,15 +347,34 @@ async function handleCommand(e) {
}
const updateAvailable = ref(false)
const updateModal = useTemplateRef('updateModal')
async function checkUpdates() {
const update = await check()
updateAvailable.value = !!update
if (!await areUpdatesEnabled()) {
console.log('Skipping update check as updates are disabled in this build')
return
}
async function performCheck() {
if (updateModal.value.isOpen) {
console.log('Skipping update check because the update modal is already open')
return
}
const update = await check()
updateAvailable.value = !!update
if (updateAvailable.value) {
console.log(`Update ${update.version} is available. Showing update modal.`)
updateModal.value.show()
}
}
await performCheck()
setTimeout(
() => {
checkUpdates()
},
5 * 1000 * 60,
// 5 * 60 * 1000,
30 * 1000,
)
}
@ -399,6 +418,9 @@ function handleAuxClick(e) {
<SplashScreen v-if="!stateFailed" ref="splashScreen" data-tauri-drag-region />
<div id="teleports"></div>
<div v-if="stateInitialized" class="app-grid-layout experimental-styles-within relative">
<Suspense @resolve="checkUpdates">
<UpdateModal ref="updateModal" />
</Suspense>
<Suspense>
<AppSettingsModal ref="settingsModal" />
</Suspense>

View File

@ -0,0 +1,37 @@
<template>
<ModalWrapper
ref="modal"
:header="header"
>
</ModalWrapper>
</template>
<script setup lang="ts">
import ModalWrapper from "@/components/ui/modal/ModalWrapper.vue";
import {defineMessage, useVIntl} from "@vintl/vintl";
import {computed, useTemplateRef, ref} from 'vue';
const {formatMessage} = useVIntl();
const headerMessage = defineMessage({
id: 'app.update.modal-header',
defaultMessage: `An update is available!`,
})
const header = computed(() => formatMessage(headerMessage))
const modal = useTemplateRef('modal')
const isOpen = ref(false)
function show() {
modal.value.show()
isOpen.value = true
}
function hide() {
modal.value.hide()
isOpen.value = false
}
defineExpose({ show, isOpen })
</script>
<style scoped lang="scss">
</style>

View File

@ -5,6 +5,10 @@ export async function isDev() {
return await invoke('is_dev')
}
export async function areUpdatesEnabled() {
return await invoke('are_updates_enabled')
}
// One of 'Windows', 'Linux', 'MacOS'
export async function getOS() {
return await invoke('plugin:utils|get_os')

View File

@ -21,75 +21,9 @@ async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> {
tracing::info!("Initializing app event state...");
theseus::EventState::init(app.clone()).await?;
#[cfg(feature = "updater")]
'updater: {
if env::var("MODRINTH_EXTERNAL_UPDATE_PROVIDER").is_ok() {
State::init().await?;
break 'updater;
}
tracing::info!("Initializing app state...");
State::init().await?;
use tauri_plugin_updater::UpdaterExt;
let updater = app.updater_builder().build()?;
let update_fut = updater.check();
tracing::info!("Initializing app state...");
State::init().await?;
let check_bar = theseus::init_loading(
theseus::LoadingBarType::CheckingForUpdates,
1.0,
"Checking for updates...",
)
.await?;
tracing::info!("Checking for updates...");
let update = update_fut.await;
drop(check_bar);
if let Some(update) = update.ok().flatten() {
tracing::info!("Update found: {:?}", update.download_url);
let loader_bar_id = theseus::init_loading(
theseus::LoadingBarType::LauncherUpdate {
version: update.version.clone(),
current_version: update.current_version.clone(),
},
1.0,
"Updating Modrinth App...",
)
.await?;
// 100 MiB
const DEFAULT_CONTENT_LENGTH: u64 = 1024 * 1024 * 100;
update
.download_and_install(
|chunk_length, content_length| {
let _ = theseus::emit_loading(
&loader_bar_id,
(chunk_length as f64)
/ (content_length
.unwrap_or(DEFAULT_CONTENT_LENGTH)
as f64),
None,
);
},
|| {},
)
.await?;
app.restart();
}
}
#[cfg(not(feature = "updater"))]
{
State::init().await?;
}
tracing::info!("Finished checking for updates!");
let state = State::get().await?;
app.asset_protocol_scope()
.allow_directory(state.directories.caches_dir(), true)?;
@ -125,6 +59,11 @@ fn is_dev() -> bool {
cfg!(debug_assertions)
}
#[tauri::command]
fn are_updates_enabled() -> bool {
cfg!(feature = "updater")
}
// Toggles decorations
#[tauri::command]
async fn toggle_decorations(b: bool, window: tauri::Window) -> api::Result<()> {
@ -264,6 +203,7 @@ fn main() {
.invoke_handler(tauri::generate_handler![
initialize_state,
is_dev,
are_updates_enabled,
toggle_decorations,
show_window,
restart_app,