Bump tauri to v2 (#3018)

* Bump tauri to v2

* Switch to virtual typed list for content page

* Fix unexpected hang on windows

* Fix ads window scaling issues on some devices

* Use DPR from browser

* Fix link opens, bump version, fix lint
This commit is contained in:
Geometrically
2024-12-14 19:23:47 -07:00
committed by GitHub
parent 7f445e9b8c
commit f2e653b732
16 changed files with 878 additions and 502 deletions

View File

@@ -1,7 +1,7 @@
{
"name": "@modrinth/app-frontend",
"private": true,
"version": "0.8.9",
"version": "0.9.0",
"type": "module",
"scripts": {
"dev": "vite",
@@ -16,12 +16,12 @@
"@modrinth/ui": "workspace:*",
"@modrinth/utils": "workspace:*",
"@sentry/vue": "^8.27.0",
"@tauri-apps/api": "^2.0.0-rc.3",
"@tauri-apps/plugin-dialog": "^2.0.0-rc.0",
"@tauri-apps/plugin-os": "^2.0.0-rc.0",
"@tauri-apps/plugin-shell": "^2.0.0-rc.0",
"@tauri-apps/plugin-updater": "^2.0.0-rc.0",
"@tauri-apps/plugin-window-state": "^2.0.0-rc.0",
"@tauri-apps/api": "^2.1.1",
"@tauri-apps/plugin-dialog": "^2.2.0",
"@tauri-apps/plugin-os": "^2.2.0",
"@tauri-apps/plugin-opener": "^2.2.1",
"@tauri-apps/plugin-updater": "^2.3.0",
"@tauri-apps/plugin-window-state": "^2.2.0",
"@vintl/vintl": "^4.4.1",
"dayjs": "^1.11.10",
"floating-vue": "^5.2.2",
@@ -35,8 +35,8 @@
"vue-virtual-scroller": "v2.0.0-beta.8"
},
"devDependencies": {
"@formatjs/cli": "^6.2.12",
"@eslint/compat": "^1.1.1",
"@formatjs/cli": "^6.2.12",
"@nuxt/eslint-config": "^0.5.6",
"@vitejs/plugin-vue": "^5.0.4",
"autoprefixer": "^10.4.19",

View File

@@ -56,7 +56,7 @@ import dayjs from 'dayjs'
import PromotionWrapper from '@/components/ui/PromotionWrapper.vue'
import { hide_ads_window, show_ads_window } from '@/helpers/ads.js'
import FriendsList from '@/components/ui/friends/FriendsList.vue'
import { open as openURL } from '@tauri-apps/plugin-shell'
import { openUrl } from '@tauri-apps/plugin-opener'
const themeStore = useTheming()
@@ -191,6 +191,7 @@ async function setupApp() {
get_opening_command().then(handleCommand)
checkUpdates()
fetchCredentials()
}
const stateFailed = ref(false)
@@ -283,8 +284,6 @@ onMounted(() => {
install.setIncompatibilityWarningModal(incompatibilityWarningModal)
install.setInstallConfirmModal(installConfirmModal)
install.setModInstallModal(modInstallModal)
fetchCredentials()
})
const accounts = ref(null)
@@ -330,10 +329,9 @@ function handleClick(e) {
!target.classList.contains('router-link-active') &&
!target.href.startsWith('http://localhost') &&
!target.href.startsWith('https://tauri.localhost') &&
!target.href.startsWith('http://tauri.localhost') &&
target.target !== '_blank'
!target.href.startsWith('http://tauri.localhost')
) {
openURL(target.href)
openUrl(target.href)
}
e.preventDefault()
break
@@ -359,13 +357,13 @@ function handleAuxClick(e) {
<template>
<SplashScreen v-if="!stateFailed" ref="splashScreen" data-tauri-drag-region />
<Suspense>
<AppSettingsModal ref="settingsModal" />
</Suspense>
<Suspense>
<InstanceCreationModal ref="installationModal" />
</Suspense>
<div v-if="stateInitialized" class="app-grid-layout relative">
<Suspense>
<AppSettingsModal ref="settingsModal" />
</Suspense>
<Suspense>
<InstanceCreationModal ref="installationModal" />
</Suspense>
<div
class="app-grid-navbar bg-bg-raised flex flex-col p-[1rem] pt-0 gap-[0.5rem] z-10 w-[--left-bar-width]"
>

View File

@@ -4,20 +4,29 @@ import { ChevronRightIcon } from '@modrinth/assets'
import { init_ads_window, open_ads_link, record_ads_click } from '@/helpers/ads.js'
const adsWrapper = ref(null)
let devicePixelRatioWatcher = null
function initDevicePixelRatioWatcher() {
if (devicePixelRatioWatcher) {
devicePixelRatioWatcher.removeEventListener('change', updateAdPosition)
}
devicePixelRatioWatcher = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`)
devicePixelRatioWatcher.addEventListener('change', updateAdPosition)
}
onMounted(() => {
updateAdPosition()
window.addEventListener('resize', updateAdPosition)
initDevicePixelRatioWatcher()
})
function updateAdPosition() {
if (adsWrapper.value) {
const rect = adsWrapper.value.getBoundingClientRect()
const x = rect.left + window.scrollX
const y = rect.top + window.scrollY
init_ads_window(x, y, 300, 250, true)
init_ads_window(true)
initDevicePixelRatioWatcher()
}
}

View File

@@ -1,11 +1,11 @@
import { invoke } from '@tauri-apps/api/core'
export async function init_ads_window(x, y, width, height, overrideShown = false) {
return await invoke('plugin:ads|init_ads_window', { x, y, width, height, overrideShown })
export async function init_ads_window(overrideShown = false) {
return await invoke('plugin:ads|init_ads_window', { overrideShown, dpr: window.devicePixelRatio })
}
export async function show_ads_window() {
return await invoke('plugin:ads|show_ads_window')
return await invoke('plugin:ads|show_ads_window', { dpr: window.devicePixelRatio })
}
export async function hide_ads_window(reset) {

View File

@@ -1,6 +1,6 @@
[package]
name = "theseus_gui"
version = "0.8.9"
version = "0.9.0"
description = "The Modrinth App is a desktop application for managing your Minecraft mods"
license = "GPL-3.0-only"
repository = "https://github.com/modrinth/code/apps/app/"
@@ -8,7 +8,7 @@ edition = "2021"
build = "build.rs"
[build-dependencies]
tauri-build = { version = "2.0.0-rc", features = ["codegen"] }
tauri-build = { version = "2.0.3", features = ["codegen"] }
[dependencies]
theseus = { path = "../../packages/app-lib", features = ["tauri"] }
@@ -16,14 +16,14 @@ theseus = { path = "../../packages/app-lib", features = ["tauri"] }
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
tauri = { version = "2.0.0-rc", features = ["devtools", "macos-private-api", "protocol-asset", "unstable"] }
tauri-plugin-window-state = "2.0.0-rc"
tauri-plugin-deep-link = "2.0.0-rc"
tauri-plugin-os = "2.0.0-rc"
tauri-plugin-shell = "2.0.0-rc"
tauri-plugin-dialog = "2.0.0-rc"
tauri-plugin-updater = { version = "2.0.0-rc" }
tauri-plugin-single-instance = { version = "2.0.0-rc" }
tauri = { version = "2.1.1", features = ["devtools", "macos-private-api", "protocol-asset", "unstable"] }
tauri-plugin-window-state = "2.2.0"
tauri-plugin-deep-link = "2.2.0"
tauri-plugin-os = "2.2.0"
tauri-plugin-opener = "2.2.1"
tauri-plugin-dialog = "2.2.0"
tauri-plugin-updater = { version = "2.3.0" }
tauri-plugin-single-instance = { version = "2.2.0" }
tokio = { version = "1", features = ["full"] }
thiserror = "1.0"
@@ -59,7 +59,7 @@ objc = "0.2.7"
rand = "0.8.5"
[target.'cfg(target_os = "linux")'.dependencies]
tauri-plugin-updater = { version = "2.0.0-rc", optional = true, features = ["native-tls-vendored", "zip"], default-features = false }
tauri-plugin-updater = { version = "2.3.0", optional = true, features = ["native-tls-vendored", "zip"], default-features = false }
[features]
# by default Tauri runs in production mode

View File

@@ -6,7 +6,7 @@
"permissions": [
"dialog:allow-open",
"dialog:allow-confirm",
"shell:allow-open",
"opener:default",
"os:allow-platform",
"os:allow-version",
"os:allow-os-type",

View File

@@ -9,7 +9,7 @@
"fix": "cargo fmt && cargo clippy --fix"
},
"devDependencies": {
"@tauri-apps/cli": "2.0.0-rc.16"
"@tauri-apps/cli": "2.1.0"
},
"dependencies": {
"@modrinth/app-frontend": "workspace:*",

View File

@@ -1,15 +1,13 @@
use std::collections::HashSet;
use std::time::{Duration, Instant};
use tauri::plugin::TauriPlugin;
use tauri::{LogicalPosition, LogicalSize, Manager, Runtime};
use tauri_plugin_shell::ShellExt;
use tauri::{Manager, PhysicalPosition, PhysicalSize, Runtime};
use tauri_plugin_opener::OpenerExt;
use theseus::settings;
use tokio::sync::RwLock;
pub struct AdsState {
pub shown: bool,
pub size: Option<LogicalSize<f32>>,
pub position: Option<LogicalPosition<f32>>,
pub last_click: Option<Instant>,
pub malicious_origins: HashSet<String>,
}
@@ -21,8 +19,6 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
.setup(|app, _api| {
app.manage(RwLock::new(AdsState {
shown: true,
size: None,
position: None,
last_click: None,
malicious_origins: HashSet::new(),
}));
@@ -54,14 +50,30 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
.build()
}
fn get_webview_position<R: Runtime>(
app: &tauri::AppHandle<R>,
dpr: f32,
) -> crate::api::Result<(PhysicalPosition<f32>, PhysicalSize<f32>)> {
let main_window = app.get_window("main").unwrap();
let width = 300.0 * dpr;
let height = 250.0 * dpr;
let main_window_size = main_window.inner_size()?;
let x = (main_window_size.width as f32) - width;
let y = (main_window_size.height as f32) - height;
Ok((
PhysicalPosition::new(x, y),
PhysicalSize::new(width, height),
))
}
#[tauri::command]
#[cfg(not(target_os = "linux"))]
pub async fn init_ads_window<R: Runtime>(
app: tauri::AppHandle<R>,
x: f32,
y: f32,
width: f32,
height: f32,
dpr: f32,
override_shown: bool,
) -> crate::api::Result<()> {
use tauri::WebviewUrl;
@@ -69,37 +81,40 @@ pub async fn init_ads_window<R: Runtime>(
let state = app.state::<RwLock<AdsState>>();
let mut state = state.write().await;
state.size = Some(LogicalSize::new(width, height));
state.position = Some(LogicalPosition::new(x, y));
if override_shown {
state.shown = true;
}
if let Some(webview) = app.webviews().get("ads-window") {
if state.shown {
let _ = webview.set_position(LogicalPosition::new(x, y));
let _ = webview.set_size(LogicalSize::new(width, height));
}
} else if let Some(window) = app.get_window("main") {
let _ = window.add_child(
tauri::webview::WebviewBuilder::new(
"ads-window",
WebviewUrl::External(
AD_LINK.parse().unwrap(),
),
)
.initialization_script(LINK_SCRIPT)
.user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36")
.zoom_hotkeys_enabled(false)
.transparent(true),
if let Ok((position, size)) = get_webview_position(&app, dpr) {
if let Some(webview) = app.webviews().get("ads-window") {
if state.shown {
LogicalPosition::new(x, y)
let _ = webview.set_position(position);
let _ = webview.set_size(size);
} else {
LogicalPosition::new(-1000.0, -1000.0)
},
LogicalSize::new(width, height),
);
let _ =
webview.set_position(PhysicalPosition::new(-1000, -1000));
}
} else if let Some(window) = app.get_window("main") {
let _ = window.add_child(
tauri::webview::WebviewBuilder::new(
"ads-window",
WebviewUrl::External(
AD_LINK.parse().unwrap(),
),
)
.initialization_script(LINK_SCRIPT)
.user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36")
.zoom_hotkeys_enabled(false)
.transparent(true),
if state.shown {
position
} else {
PhysicalPosition::new(-1000.0, -1000.0)
},
size,
);
}
}
Ok(())
@@ -113,17 +128,15 @@ pub async fn init_ads_window() {}
#[tauri::command]
pub async fn show_ads_window<R: Runtime>(
app: tauri::AppHandle<R>,
dpr: f32,
) -> crate::api::Result<()> {
if let Some(webview) = app.webviews().get("ads-window") {
let state = app.state::<RwLock<AdsState>>();
let mut state = state.write().await;
let state = state.read().await;
state.shown = true;
if let Some(size) = state.size {
if state.shown {
let (position, size) = get_webview_position(&app, dpr)?;
let _ = webview.set_size(size);
}
if let Some(position) = state.position {
let _ = webview.set_position(position);
}
}
@@ -137,16 +150,14 @@ pub async fn hide_ads_window<R: Runtime>(
reset: Option<bool>,
) -> crate::api::Result<()> {
if let Some(webview) = app.webviews().get("ads-window") {
let state = app.state::<RwLock<AdsState>>();
let mut state = state.write().await;
state.shown = false;
if reset.unwrap_or(false) {
state.size = None;
state.position = None;
let state = app.state::<RwLock<AdsState>>();
let mut state = state.write().await;
state.shown = false;
}
let _ = webview.set_position(LogicalPosition::new(-1000, -1000));
let _ = webview.set_position(PhysicalPosition::new(-1000, -1000));
}
Ok(())
@@ -178,7 +189,7 @@ pub async fn open_link<R: Runtime>(
{
if let Some(last_click) = state.last_click {
if last_click.elapsed() < Duration::from_millis(100) {
let _ = app.shell().open(&path, None);
let _ = app.opener().open_url(&path, None::<String>);
state.last_click = None;
return Ok(());

View File

@@ -185,7 +185,7 @@ fn main() {
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_deep_link::init())
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_opener::init())
.plugin(
tauri_plugin_window_state::Builder::default()
.with_filename("app-window-state.json")