From 8f59bb8afaf13f10886565fab7c799a078575834 Mon Sep 17 00:00:00 2001 From: Wyatt Verchere Date: Thu, 3 Aug 2023 19:22:35 -0700 Subject: [PATCH 1/9] fixes --- theseus/src/api/pack/import/mod.rs | 31 ++++++- theseus/src/api/pack/install_mrpack.rs | 13 ++- theseus_gui/src/App.vue | 3 +- theseus_gui/src/components/ui/ExportModal.vue | 1 + .../components/ui/InstanceCreationModal.vue | 92 +++++++++++++++---- .../src/components/ui/JavaDetectionModal.vue | 2 + .../components/ui/tutorial/ImportingCard.vue | 26 +++++- theseus_gui/src/pages/Settings.vue | 13 ++- theseus_gui/src/pages/instance/Logs.vue | 2 +- theseus_gui/src/pages/instance/Mods.vue | 17 ++-- 10 files changed, 160 insertions(+), 40 deletions(-) diff --git a/theseus/src/api/pack/import/mod.rs b/theseus/src/api/pack/import/mod.rs index f5d026e00..62bc6073d 100644 --- a/theseus/src/api/pack/import/mod.rs +++ b/theseus/src/api/pack/import/mod.rs @@ -1,4 +1,7 @@ -use std::path::{Path, PathBuf}; +use std::{ + fmt, + path::{Path, PathBuf}, +}; use io::IOError; use serde::{Deserialize, Serialize}; @@ -24,6 +27,19 @@ pub enum ImportLauncherType { #[serde(other)] Unknown, } +// impl display +impl fmt::Display for ImportLauncherType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ImportLauncherType::MultiMC => write!(f, "MultiMC"), + ImportLauncherType::PrismLauncher => write!(f, "PrismLauncher"), + ImportLauncherType::ATLauncher => write!(f, "ATLauncher"), + ImportLauncherType::GDLauncher => write!(f, "GDLauncher"), + ImportLauncherType::Curseforge => write!(f, "Curseforge"), + ImportLauncherType::Unknown => write!(f, "Unknown"), + } + } +} // Return a list of importable instances from a launcher type and base path, by iterating through the folder and checking pub async fn get_importable_instances( @@ -31,12 +47,12 @@ pub async fn get_importable_instances( base_path: PathBuf, ) -> crate::Result> { // Some launchers have a different folder structure for instances - let instances_folder = match launcher_type { + let instances_subfolder = match launcher_type { ImportLauncherType::GDLauncher | ImportLauncherType::MultiMC | ImportLauncherType::PrismLauncher - | ImportLauncherType::ATLauncher => base_path.join("instances"), - ImportLauncherType::Curseforge => base_path.join("Instances"), + | ImportLauncherType::ATLauncher => "instances", + ImportLauncherType::Curseforge => "Instances", ImportLauncherType::Unknown => { return Err(crate::ErrorKind::InputError( "Launcher type Unknown".to_string(), @@ -44,8 +60,13 @@ pub async fn get_importable_instances( .into()) } }; + let instances_folder = base_path.join(instances_subfolder); let mut instances = Vec::new(); - let mut dir = io::read_dir(&instances_folder).await?; + let mut dir = io::read_dir(&instances_folder).await.map_err(| _ | { + crate::ErrorKind::InputError(format!( + "Invalid {launcher_type} launcher path, could not find '{instances_subfolder}' subfolder." + )) + })?; while let Some(entry) = dir .next_entry() .await diff --git a/theseus/src/api/pack/install_mrpack.rs b/theseus/src/api/pack/install_mrpack.rs index a905362eb..d2c9aaec3 100644 --- a/theseus/src/api/pack/install_mrpack.rs +++ b/theseus/src/api/pack/install_mrpack.rs @@ -9,7 +9,7 @@ use crate::prelude::ProfilePathId; use crate::state::{ProfileInstallStage, Profiles, SideType}; use crate::util::fetch::{fetch_mirrors, write}; use crate::util::io; -use crate::State; +use crate::{profile, State}; use async_zip::tokio::read::seek::ZipFileReader; use std::io::Cursor; @@ -82,6 +82,7 @@ pub async fn install_zipped_mrpack_files( let version_id = create_pack.description.version_id; let existing_loading_bar = create_pack.description.existing_loading_bar; let profile_path = create_pack.description.profile_path; + let icon_exists = icon.is_some(); let reader: Cursor<&bytes::Bytes> = Cursor::new(&file); @@ -186,7 +187,7 @@ pub async fn install_zipped_mrpack_files( let path = profile_path .get_full_path() .await? - .join(project.path); + .join(&project.path); write(&path, &file, &state.io_semaphore) .await?; } @@ -261,6 +262,14 @@ pub async fn install_zipped_mrpack_files( } } + // If the icon doesn't exist, we expect icon.png to be a potential icon. + // If it doesn't exist, and an override to icon.png exists, cache and use that + let potential_icon = + profile_path.get_full_path().await?.join("icon.png"); + if !icon_exists && potential_icon.exists() { + profile::edit_icon(&profile_path, Some(&potential_icon)).await?; + } + if let Some(profile_val) = crate::api::profile::get(&profile_path, None).await? { diff --git a/theseus_gui/src/App.vue b/theseus_gui/src/App.vue index 535db78a2..5f7c7e8a1 100644 --- a/theseus_gui/src/App.vue +++ b/theseus_gui/src/App.vue @@ -40,7 +40,7 @@ import OnboardingScreen from '@/components/ui/tutorial/OnboardingScreen.vue' const themeStore = useTheming() const urlModal = ref(null) const isLoading = ref(true) -const videoPlaying = ref(true) +const videoPlaying = ref(false) const showOnboarding = ref(false) const onboardingVideo = ref() @@ -50,6 +50,7 @@ defineExpose({ isLoading.value = false const { theme, opt_out_analytics, collapsed_navigation, advanced_rendering, onboarded_new } = await get() + videoPlaying.value = !onboarded_new const dev = await isDev() const version = await getVersion() showOnboarding.value = !onboarded_new diff --git a/theseus_gui/src/components/ui/ExportModal.vue b/theseus_gui/src/components/ui/ExportModal.vue index f11bc6135..fabd134d5 100644 --- a/theseus_gui/src/components/ui/ExportModal.vue +++ b/theseus_gui/src/components/ui/ExportModal.vue @@ -188,6 +188,7 @@ const exportPack = async () => { } .select-checkbox { + button.checkbox { border: none; } diff --git a/theseus_gui/src/components/ui/InstanceCreationModal.vue b/theseus_gui/src/components/ui/InstanceCreationModal.vue index 183617c50..fdb83d48f 100644 --- a/theseus_gui/src/components/ui/InstanceCreationModal.vue +++ b/theseus_gui/src/components/ui/InstanceCreationModal.vue @@ -73,7 +73,7 @@ {{ showAdvanced ? 'Hide advanced' : 'Show advanced' }} - @@ -202,7 +202,7 @@ import { FolderSearchIcon, UpdatedIcon, } from 'omorphia' -import { computed, ref, shallowRef } from 'vue' +import { computed, onUnmounted, ref, shallowRef } from 'vue' import { get_loaders } from '@/helpers/tags' import { create } from '@/helpers/profile' import { open } from '@tauri-apps/api/dialog' @@ -219,7 +219,7 @@ import mixpanel from 'mixpanel-browser' import { useTheming } from '@/store/state.js' import { listen } from '@tauri-apps/api/event' import { install_from_file } from '@/helpers/pack.js' -import { get_importable_instances, import_instance } from '@/helpers/import.js' +import { get_default_launcher_path, get_importable_instances, import_instance } from '@/helpers/import.js' const themeStore = useTheming() @@ -234,9 +234,10 @@ const showAdvanced = ref(false) const creating = ref(false) const showSnapshots = ref(false) const creationType = ref('from file') +const isShowing = ref(false) defineExpose({ - show: () => { + show: async () => { game_version.value = '' specified_loader_version.value = '' profile_name.value = '' @@ -247,12 +248,48 @@ defineExpose({ loader_version.value = 'stable' icon.value = null display_icon.value = null + isShowing.value = true modal.value.show() + + unlistener.value = await listen('tauri://file-drop', async (event) => { + // Only if modal is showing + if (!isShowing.value) return + if (creationType.value !== 'from file') return + hide() + if (event.payload && event.payload.length > 0 && event.payload[0].endsWith('.mrpack')) { + await install_from_file(event.payload[0]).catch(handleError) + mixpanel.track('InstanceCreate', { + source: 'CreationModalFileDrop', + }) + } + }) + + mixpanel.track('InstanceCreateStart', { source: 'CreationModal' }) }, }) +const unlistener = ref(null); +const hide = () => { + console.log("hiding nicely") + isShowing.value = false + modal.value.hide() + if (unlistener.value) { + unlistener.value() + unlistener.value = null + } +} +onUnmounted(() => { + if (unlistener.value) { + unlistener.value() + unlistener.value = null + } +}) + + + + const [fabric_versions, forge_versions, quilt_versions, all_game_versions, loaders] = await Promise.all([ get_fabric_versions().then(shallowRef).catch(handleError), @@ -303,7 +340,7 @@ const create_instance = async () => { loader_version.value === 'other' ? specified_loader_version.value : loader_version.value const loaderVersion = loader.value === 'vanilla' ? null : loader_version_value ?? 'stable' - modal.value.hide() + hide() creating.value = false await create( @@ -366,8 +403,7 @@ const toggle_advanced = () => { const openFile = async () => { const newProject = await open({ multiple: false }) if (!newProject) return - - modal.value.hide() + hide() await install_from_file(newProject).catch(handleError) mixpanel.track('InstanceCreate', { @@ -375,15 +411,6 @@ const openFile = async () => { }) } -listen('tauri://file-drop', async (event) => { - modal.value.hide() - if (event.payload && event.payload.length > 0 && event.payload[0].endsWith('.mrpack')) { - await install_from_file(event.payload[0]).catch(handleError) - mixpanel.track('InstanceCreate', { - source: 'CreationModalFileDrop', - }) - } -}) const profiles = ref( new Map([ @@ -406,6 +433,30 @@ const profileOptions = ref([ { name: 'PrismLauncher', path: '' }, ]) +// Attempt to get import profiles on default paths +const promises = profileOptions.value.map(async (option) => { + const path = await get_default_launcher_path(option.name).catch(handleError) + if (!path || path === '') return + + // Try catch to allow failure and simply ignore default path attempt + try { + const instances = await get_importable_instances( + option.name, + path) + + if (!instances) return + profileOptions.value.find((profile) => profile.name === option.name).path = path + profiles.value.set( + option.name, + instances.map((name) => ({ name, selected: false })) + ) + } catch (error) { + // Allow failure silently + } +}) +await Promise.all(promises) + + const selectLauncherPath = async () => { selectedProfileType.value.path = await open({ multiple: false, directory: true }) @@ -419,10 +470,15 @@ const reload = async () => { selectedProfileType.value.name, selectedProfileType.value.path ).catch(handleError) - profiles.value.set( + if (instances) { + profiles.value.set( selectedProfileType.value.name, instances.map((name) => ({ name, selected: false })) - ) + ) } else { + profiles.value.set(selectedProfileType.value.name, []) + } + + console.log(instances) } const setPath = () => { diff --git a/theseus_gui/src/components/ui/JavaDetectionModal.vue b/theseus_gui/src/components/ui/JavaDetectionModal.vue index 9ded1aa66..6e6937f53 100644 --- a/theseus_gui/src/components/ui/JavaDetectionModal.vue +++ b/theseus_gui/src/components/ui/JavaDetectionModal.vue @@ -99,6 +99,8 @@ function setJavaInstall(javaInstall) { align-items: center; justify-content: center; } + + padding: 0.5rem; } } diff --git a/theseus_gui/src/components/ui/tutorial/ImportingCard.vue b/theseus_gui/src/components/ui/tutorial/ImportingCard.vue index 252d0df53..8eb73d793 100644 --- a/theseus_gui/src/components/ui/tutorial/ImportingCard.vue +++ b/theseus_gui/src/components/ui/tutorial/ImportingCard.vue @@ -10,7 +10,7 @@ import { UpdatedIcon, } from 'omorphia' import { ref } from 'vue' -import { get_importable_instances, import_instance } from '@/helpers/import.js' +import { get_default_launcher_path, get_importable_instances, import_instance } from '@/helpers/import.js' import { open } from '@tauri-apps/api/dialog' import { handleError } from '@/store/state.js' @@ -46,6 +46,30 @@ const profileOptions = ref([ { name: 'PrismLauncher', path: '' }, ]) + +// Attempt to get import profiles on default paths +const promises = profileOptions.value.map(async (option) => { + const path = await get_default_launcher_path(option.name).catch(handleError) + if (!path || path === '') return + + // Try catch to allow failure and simply ignore default path attempt + try { + const instances = await get_importable_instances( + option.name, + path) + + if (!instances) return + profileOptions.value.find((profile) => profile.name === option.name).path = path + profiles.value.set( + option.name, + instances.map((name) => ({ name, selected: false })) + ) + } catch (error) { + // Allow failure silently + } +}) +Promise.all(promises) + const selectLauncherPath = async () => { selectedProfileType.value.path = await open({ multiple: false, directory: true }) diff --git a/theseus_gui/src/pages/Settings.vue b/theseus_gui/src/pages/Settings.vue index 2014c4767..d9642fd0f 100644 --- a/theseus_gui/src/pages/Settings.vue +++ b/theseus_gui/src/pages/Settings.vue @@ -1,6 +1,6 @@ From 587ef0fa2612e9548004d3443462953cf3227a1f Mon Sep 17 00:00:00 2001 From: Wyatt Verchere Date: Thu, 3 Aug 2023 19:35:18 -0700 Subject: [PATCH 2/9] prettier --- theseus_gui/src/components/ui/ExportModal.vue | 1 - .../components/ui/InstanceCreationModal.vue | 32 ++++++++----------- .../components/ui/tutorial/ImportingCard.vue | 13 ++++---- theseus_gui/src/pages/instance/Mods.vue | 11 +++---- 4 files changed, 26 insertions(+), 31 deletions(-) diff --git a/theseus_gui/src/components/ui/ExportModal.vue b/theseus_gui/src/components/ui/ExportModal.vue index fabd134d5..f11bc6135 100644 --- a/theseus_gui/src/components/ui/ExportModal.vue +++ b/theseus_gui/src/components/ui/ExportModal.vue @@ -188,7 +188,6 @@ const exportPack = async () => { } .select-checkbox { - button.checkbox { border: none; } diff --git a/theseus_gui/src/components/ui/InstanceCreationModal.vue b/theseus_gui/src/components/ui/InstanceCreationModal.vue index fdb83d48f..34a0ab653 100644 --- a/theseus_gui/src/components/ui/InstanceCreationModal.vue +++ b/theseus_gui/src/components/ui/InstanceCreationModal.vue @@ -219,7 +219,11 @@ import mixpanel from 'mixpanel-browser' import { useTheming } from '@/store/state.js' import { listen } from '@tauri-apps/api/event' import { install_from_file } from '@/helpers/pack.js' -import { get_default_launcher_path, get_importable_instances, import_instance } from '@/helpers/import.js' +import { + get_default_launcher_path, + get_importable_instances, + import_instance, +} from '@/helpers/import.js' const themeStore = useTheming() @@ -251,8 +255,7 @@ defineExpose({ isShowing.value = true modal.value.show() - - unlistener.value = await listen('tauri://file-drop', async (event) => { + unlistener.value = await listen('tauri://file-drop', async (event) => { // Only if modal is showing if (!isShowing.value) return if (creationType.value !== 'from file') return @@ -265,14 +268,13 @@ defineExpose({ } }) - mixpanel.track('InstanceCreateStart', { source: 'CreationModal' }) }, }) -const unlistener = ref(null); +const unlistener = ref(null) const hide = () => { - console.log("hiding nicely") + console.log('hiding nicely') isShowing.value = false modal.value.hide() if (unlistener.value) { @@ -287,9 +289,6 @@ onUnmounted(() => { } }) - - - const [fabric_versions, forge_versions, quilt_versions, all_game_versions, loaders] = await Promise.all([ get_fabric_versions().then(shallowRef).catch(handleError), @@ -411,7 +410,6 @@ const openFile = async () => { }) } - const profiles = ref( new Map([ ['MultiMC', []], @@ -440,10 +438,8 @@ const promises = profileOptions.value.map(async (option) => { // Try catch to allow failure and simply ignore default path attempt try { - const instances = await get_importable_instances( - option.name, - path) - + const instances = await get_importable_instances(option.name, path) + if (!instances) return profileOptions.value.find((profile) => profile.name === option.name).path = path profiles.value.set( @@ -456,7 +452,6 @@ const promises = profileOptions.value.map(async (option) => { }) await Promise.all(promises) - const selectLauncherPath = async () => { selectedProfileType.value.path = await open({ multiple: false, directory: true }) @@ -472,9 +467,10 @@ const reload = async () => { ).catch(handleError) if (instances) { profiles.value.set( - selectedProfileType.value.name, - instances.map((name) => ({ name, selected: false })) - ) } else { + selectedProfileType.value.name, + instances.map((name) => ({ name, selected: false })) + ) + } else { profiles.value.set(selectedProfileType.value.name, []) } diff --git a/theseus_gui/src/components/ui/tutorial/ImportingCard.vue b/theseus_gui/src/components/ui/tutorial/ImportingCard.vue index 8eb73d793..3139b5d4a 100644 --- a/theseus_gui/src/components/ui/tutorial/ImportingCard.vue +++ b/theseus_gui/src/components/ui/tutorial/ImportingCard.vue @@ -10,7 +10,11 @@ import { UpdatedIcon, } from 'omorphia' import { ref } from 'vue' -import { get_default_launcher_path, get_importable_instances, import_instance } from '@/helpers/import.js' +import { + get_default_launcher_path, + get_importable_instances, + import_instance, +} from '@/helpers/import.js' import { open } from '@tauri-apps/api/dialog' import { handleError } from '@/store/state.js' @@ -46,7 +50,6 @@ const profileOptions = ref([ { name: 'PrismLauncher', path: '' }, ]) - // Attempt to get import profiles on default paths const promises = profileOptions.value.map(async (option) => { const path = await get_default_launcher_path(option.name).catch(handleError) @@ -54,10 +57,8 @@ const promises = profileOptions.value.map(async (option) => { // Try catch to allow failure and simply ignore default path attempt try { - const instances = await get_importable_instances( - option.name, - path) - + const instances = await get_importable_instances(option.name, path) + if (!instances) return profileOptions.value.find((profile) => profile.name === option.name).path = path profiles.value.set( diff --git a/theseus_gui/src/pages/instance/Mods.vue b/theseus_gui/src/pages/instance/Mods.vue index f91a2f0e4..9011bd85e 100644 --- a/theseus_gui/src/pages/instance/Mods.vue +++ b/theseus_gui/src/pages/instance/Mods.vue @@ -768,13 +768,12 @@ watch(selectAll, () => { } }) - const unlisten = await listen('tauri://file-drop', async (event) => { - for (const file of event.payload) { - if (file.endsWith('.mrpack')) continue - await add_project_from_path(props.instance.path, file, 'mod').catch(handleError) - } - initProjects(await get(props.instance.path).catch(handleError)) + for (const file of event.payload) { + if (file.endsWith('.mrpack')) continue + await add_project_from_path(props.instance.path, file, 'mod').catch(handleError) + } + initProjects(await get(props.instance.path).catch(handleError)) }) onUnmounted(() => { unlisten() From ef3c1d8c11a705cb71af2035c92c2ff2160440e2 Mon Sep 17 00:00:00 2001 From: Wyatt Verchere Date: Fri, 4 Aug 2023 12:09:41 -0700 Subject: [PATCH 3/9] more bugs --- theseus_gui/src-tauri/src/api/utils.rs | 20 ++++++++++++++++++++ theseus_gui/src/App.vue | 6 ++++-- theseus_gui/src/helpers/events.js | 3 ++- theseus_gui/src/helpers/utils.js | 5 +++++ theseus_gui/src/pages/instance/Index.vue | 2 +- 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/theseus_gui/src-tauri/src/api/utils.rs b/theseus_gui/src-tauri/src/api/utils.rs index ccf5628e6..8e2afb83d 100644 --- a/theseus_gui/src-tauri/src/api/utils.rs +++ b/theseus_gui/src-tauri/src/api/utils.rs @@ -1,3 +1,4 @@ +use serde::{Serialize, Deserialize}; use theseus::{handler, prelude::CommandPayload, State}; use crate::api::Result; @@ -6,6 +7,7 @@ use std::{env, process::Command}; pub fn init() -> tauri::plugin::TauriPlugin { tauri::plugin::Builder::new("utils") .invoke_handler(tauri::generate_handler![ + get_os, should_disable_mouseover, show_in_folder, progress_bars_list, @@ -16,6 +18,24 @@ pub fn init() -> tauri::plugin::TauriPlugin { .build() } +/// Gets OS +#[tauri::command] +pub fn get_os() -> OS { + #[cfg(target_os = "windows")] + let os = OS::Windows; + #[cfg(target_os = "linux")] + let os = OS::Linux; + #[cfg(target_os = "macos")] + let os = OS::MacOS; + os +} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum OS { + Windows, + Linux, + MacOS, +} + // Lists active progress bars // Create a new HashMap with the same keys // Values provided should not be used directly, as they are not guaranteed to be up-to-date diff --git a/theseus_gui/src/App.vue b/theseus_gui/src/App.vue index 5f7c7e8a1..e8e7b34c2 100644 --- a/theseus_gui/src/App.vue +++ b/theseus_gui/src/App.vue @@ -24,7 +24,7 @@ import { command_listener, warning_listener } from '@/helpers/events.js' import { MinimizeIcon, MaximizeIcon } from '@/assets/icons' import { type } from '@tauri-apps/api/os' import { appWindow } from '@tauri-apps/api/window' -import { isDev } from '@/helpers/utils.js' +import { isDev, getOS } from '@/helpers/utils.js' import mixpanel from 'mixpanel-browser' import { saveWindowState, StateFlags } from 'tauri-plugin-window-state-api' import { getVersion } from '@tauri-apps/api/app' @@ -50,7 +50,9 @@ defineExpose({ isLoading.value = false const { theme, opt_out_analytics, collapsed_navigation, advanced_rendering, onboarded_new } = await get() - videoPlaying.value = !onboarded_new + const os = await getOS() + // video should play if the user is not on linux, and has not onboarded + videoPlaying.value = !onboarded_new && os !== 'Linux' const dev = await isDev() const version = await getVersion() showOnboarding.value = !onboarded_new diff --git a/theseus_gui/src/helpers/events.js b/theseus_gui/src/helpers/events.js index 2f065940a..75fe90307 100644 --- a/theseus_gui/src/helpers/events.js +++ b/theseus_gui/src/helpers/events.js @@ -62,7 +62,8 @@ export async function process_listener(callback) { ProfilePayload { uuid: unique identification of the process in the state (currently identified by path, but that will change) name: name of the profile - path: path to profile + profile_path: relative path to profile (used for path identification) + path: path to profile (used for opening the profile in the OS file explorer) event: event type ("Created", "Added", "Edited", "Removed") } */ diff --git a/theseus_gui/src/helpers/utils.js b/theseus_gui/src/helpers/utils.js index 8163d9c38..8f1e8b827 100644 --- a/theseus_gui/src/helpers/utils.js +++ b/theseus_gui/src/helpers/utils.js @@ -11,6 +11,11 @@ export async function isDev() { return await invoke('is_dev') } +// One of 'Windows', 'Linux', 'MacOS' +export async function getOS() { + return await invoke('plugin:utils|get_os') +} + export async function showInFolder(path) { return await invoke('plugin:utils|show_in_folder', { path }) } diff --git a/theseus_gui/src/pages/instance/Index.vue b/theseus_gui/src/pages/instance/Index.vue index 06f71864c..7351b9cfb 100644 --- a/theseus_gui/src/pages/instance/Index.vue +++ b/theseus_gui/src/pages/instance/Index.vue @@ -277,7 +277,7 @@ const handleOptionsClick = async (args) => { } const unlistenProfiles = await profile_listener(async (event) => { - if (event.path === route.params.id) { + if (event.profile_path_id === route.params.id) { if (event.event === 'removed') { await router.push({ path: '/', From 3822f386a397a2a953fd2a9b4a735f15a3e403a3 Mon Sep 17 00:00:00 2001 From: Wyatt Verchere Date: Fri, 4 Aug 2023 12:12:45 -0700 Subject: [PATCH 4/9] changes --- theseus/src/api/pack/import/curseforge.rs | 14 +++++++--- theseus/src/api/profile/create.rs | 2 +- theseus/src/api/profile/mod.rs | 33 ++++++++++++----------- theseus/src/api/profile/update.rs | 4 +-- theseus/src/event/emit.rs | 7 ++--- theseus/src/event/mod.rs | 2 ++ theseus/src/state/profiles.rs | 11 +++++--- 7 files changed, 43 insertions(+), 30 deletions(-) diff --git a/theseus/src/api/pack/import/curseforge.rs b/theseus/src/api/pack/import/curseforge.rs index 485ae6587..fe50354e6 100644 --- a/theseus/src/api/pack/import/curseforge.rs +++ b/theseus/src/api/pack/import/curseforge.rs @@ -9,7 +9,7 @@ use crate::{ State, }; -use super::copy_dotminecraft; +use super::{copy_dotminecraft, recache_icon}; #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -35,6 +35,7 @@ pub struct FlameModLoader { #[serde(rename_all = "camelCase")] pub struct MinecraftInstance { pub name: Option, + pub profile_image_path: Option, pub game_version: String, // Minecraft game version. Non-prioritized, use this if Vanilla } @@ -53,9 +54,6 @@ pub async fn import_curseforge( curseforge_instance_folder: PathBuf, // instance's folder profile_path: ProfilePathId, // path to profile ) -> crate::Result<()> { - // TODO: recache curseforge instance icon - let icon: Option = None; - // Load minecraftinstance.json let minecraft_instance: String = io::read_to_string( &curseforge_instance_folder.join("minecraftinstance.json"), @@ -72,6 +70,14 @@ pub async fn import_curseforge( .unwrap_or("Unknown".to_string()) ); + // Recache Curseforge Icon if it exists + let icon = if let Some(icon_path) = minecraft_instance.profile_image_path.clone() { + recache_icon(icon_path).await? + } else { + None + }; + + // Curseforge vanilla profile may not have a manifest.json, so we allow it to not exist if curseforge_instance_folder.join("manifest.json").exists() { // Load manifest.json diff --git a/theseus/src/api/profile/create.rs b/theseus/src/api/profile/create.rs index ab280ee7a..e6204d713 100644 --- a/theseus/src/api/profile/create.rs +++ b/theseus/src/api/profile/create.rs @@ -104,7 +104,7 @@ pub async fn profile_create( emit_profile( uuid, - profile.get_profile_full_path().await?, + &profile.profile_id(), &profile.metadata.name, ProfilePayloadType::Created, ) diff --git a/theseus/src/api/profile/mod.rs b/theseus/src/api/profile/mod.rs index 4c619d09f..37d1e4290 100644 --- a/theseus/src/api/profile/mod.rs +++ b/theseus/src/api/profile/mod.rs @@ -45,7 +45,7 @@ pub async fn remove(path: &ProfilePathId) -> crate::Result<()> { if let Some(profile) = profiles.remove(path).await? { emit_profile( profile.uuid, - profile.get_profile_full_path().await?, + path, &profile.metadata.name, ProfilePayloadType::Removed, ) @@ -124,7 +124,7 @@ where emit_profile( profile.uuid, - profile.get_profile_full_path().await?, + path, &profile.metadata.name, ProfilePayloadType::Edited, ) @@ -162,7 +162,7 @@ pub async fn edit_icon( emit_profile( profile.uuid, - profile.get_profile_full_path().await?, + &path, &profile.metadata.name, ProfilePayloadType::Edited, ) @@ -285,7 +285,6 @@ pub async fn update_all_projects( ) .await?; - let profile_base_path = profile.get_profile_full_path().await?; let keys = profile .projects .into_iter() @@ -331,7 +330,7 @@ pub async fn update_all_projects( emit_profile( profile.uuid, - profile_base_path, + &profile_path, &profile.metadata.name, ProfilePayloadType::Edited, ) @@ -378,10 +377,12 @@ pub async fn update_project( if let Some(mut project) = value { if let ProjectMetadata::Modrinth { ref mut version, + ref mut update_version, .. } = project.metadata { *version = Box::new(new_version); + *update_version = None; } profile.projects.insert(path.clone(), project); } @@ -391,7 +392,7 @@ pub async fn update_project( if !skip_send_event.unwrap_or(false) { emit_profile( profile.uuid, - profile.get_profile_full_path().await?, + &profile_path, &profile.metadata.name, ProfilePayloadType::Edited, ) @@ -427,7 +428,7 @@ pub async fn add_project_from_version( emit_profile( profile.uuid, - profile.get_profile_full_path().await?, + &profile_path, &profile.metadata.name, ProfilePayloadType::Edited, ) @@ -467,7 +468,7 @@ pub async fn add_project_from_path( emit_profile( profile.uuid, - profile.get_profile_full_path().await?, + &profile_path, &profile.metadata.name, ProfilePayloadType::Edited, ) @@ -488,15 +489,15 @@ pub async fn add_project_from_path( /// returns the new state, relative to the profile #[tracing::instrument] pub async fn toggle_disable_project( - profile: &ProfilePathId, + profile_path: &ProfilePathId, project: &ProjectPathId, ) -> crate::Result { - if let Some(profile) = get(profile, None).await? { + if let Some(profile) = get(profile_path, None).await? { let res = profile.toggle_disable_project(project).await?; emit_profile( profile.uuid, - profile.get_profile_full_path().await?, + &profile_path, &profile.metadata.name, ProfilePayloadType::Edited, ) @@ -505,7 +506,7 @@ pub async fn toggle_disable_project( Ok(res) } else { - Err(crate::ErrorKind::UnmanagedProfileError(profile.to_string()) + Err(crate::ErrorKind::UnmanagedProfileError(profile_path.to_string()) .as_error()) } } @@ -514,15 +515,15 @@ pub async fn toggle_disable_project( /// Uses and returns the relative path to the project #[tracing::instrument] pub async fn remove_project( - profile: &ProfilePathId, + profile_path: &ProfilePathId, project: &ProjectPathId, ) -> crate::Result<()> { - if let Some(profile) = get(profile, None).await? { + if let Some(profile) = get(profile_path, None).await? { profile.remove_project(project, None).await?; emit_profile( profile.uuid, - profile.get_profile_full_path().await?, + profile_path, &profile.metadata.name, ProfilePayloadType::Edited, ) @@ -531,7 +532,7 @@ pub async fn remove_project( Ok(()) } else { - Err(crate::ErrorKind::UnmanagedProfileError(profile.to_string()) + Err(crate::ErrorKind::UnmanagedProfileError(profile_path.to_string()) .as_error()) } } diff --git a/theseus/src/api/profile/update.rs b/theseus/src/api/profile/update.rs index 952d5587d..bc39fc563 100644 --- a/theseus/src/api/profile/update.rs +++ b/theseus/src/api/profile/update.rs @@ -57,7 +57,7 @@ pub async fn update_managed_modrinth( emit_profile( profile.uuid, - profile.path, + profile_path, &profile.metadata.name, ProfilePayloadType::Edited, ) @@ -133,7 +133,7 @@ pub async fn repair_managed_modrinth( emit_profile( profile.uuid, - profile.path, + profile_path, &profile.metadata.name, ProfilePayloadType::Edited, ) diff --git a/theseus/src/event/emit.rs b/theseus/src/event/emit.rs index 54cb1968c..0618b447f 100644 --- a/theseus/src/event/emit.rs +++ b/theseus/src/event/emit.rs @@ -4,10 +4,9 @@ use crate::{ CommandPayload, EventError, LoadingBar, LoadingBarType, ProcessPayloadType, ProfilePayloadType, }, - state::{ProcessType, SafeProcesses}, + state::{ProcessType, SafeProcesses}, prelude::ProfilePathId, }; use futures::prelude::*; -use std::path::PathBuf; #[cfg(feature = "tauri")] use crate::event::{ @@ -282,12 +281,13 @@ pub async fn emit_process( #[allow(unused_variables)] pub async fn emit_profile( uuid: Uuid, - path: PathBuf, + profile_path_id : &ProfilePathId, name: &str, event: ProfilePayloadType, ) -> crate::Result<()> { #[cfg(feature = "tauri")] { + let path = profile_path_id.get_full_path().await?; let event_state = crate::EventState::get().await?; event_state .app @@ -295,6 +295,7 @@ pub async fn emit_profile( "profile", ProfilePayload { uuid, + profile_path_id: profile_path_id.clone(), path, name: name.to_string(), event, diff --git a/theseus/src/event/mod.rs b/theseus/src/event/mod.rs index f2706f7a3..cf7f2053c 100644 --- a/theseus/src/event/mod.rs +++ b/theseus/src/event/mod.rs @@ -5,6 +5,7 @@ use tokio::sync::OnceCell; use tokio::sync::RwLock; use uuid::Uuid; +use crate::prelude::ProfilePathId; use crate::state::SafeProcesses; pub mod emit; @@ -235,6 +236,7 @@ pub enum ProcessPayloadType { #[derive(Serialize, Clone)] pub struct ProfilePayload { pub uuid: Uuid, + pub profile_path_id: ProfilePathId, pub path: PathBuf, pub name: String, pub event: ProfilePayloadType, diff --git a/theseus/src/state/profiles.rs b/theseus/src/state/profiles.rs index 1e13e6467..83ab831dd 100644 --- a/theseus/src/state/profiles.rs +++ b/theseus/src/state/profiles.rs @@ -303,7 +303,10 @@ impl Profile { let profile = crate::api::profile::get(&path, None).await?; if let Some(profile) = profile { - emit_warning(&format!("Profile {} has crashed! Visit the logs page to see a crash report.", profile.metadata.name)).await?; + // Hide warning if profile is not yet installed + if profile.install_stage == ProfileInstallStage::Installed { + emit_warning(&format!("Profile {} has crashed! Visit the logs page to see a crash report.", profile.metadata.name)).await?; + } } Ok::<(), crate::Error>(()) @@ -354,7 +357,7 @@ impl Profile { } emit_profile( profile.uuid, - profile.get_profile_full_path().await?, + &profile_path_id, &profile.metadata.name, ProfilePayloadType::Synced, ) @@ -856,7 +859,7 @@ impl Profiles { pub async fn insert(&mut self, profile: Profile) -> crate::Result<&Self> { emit_profile( profile.uuid, - profile.get_profile_full_path().await?, + &profile.profile_id(), &profile.metadata.name, ProfilePayloadType::Added, ) @@ -943,7 +946,7 @@ impl Profiles { // if path exists in the state but no longer in the filesystem, remove it from the state list emit_profile( profile.uuid, - profile.get_profile_full_path().await?, + &profile_path_id, &profile.metadata.name, ProfilePayloadType::Removed, ) From 43d4a25e108eab73344dc87ca9535decfe212b07 Mon Sep 17 00:00:00 2001 From: Wyatt Verchere Date: Fri, 4 Aug 2023 15:30:25 -0700 Subject: [PATCH 5/9] more fixes --- .../src/components/ui/InstanceCreationModal.vue | 2 +- theseus_gui/src/components/ui/ModInstallModal.vue | 2 +- theseus_gui/src/pages/instance/Options.vue | 13 +++++++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/theseus_gui/src/components/ui/InstanceCreationModal.vue b/theseus_gui/src/components/ui/InstanceCreationModal.vue index 34a0ab653..56e5b4310 100644 --- a/theseus_gui/src/components/ui/InstanceCreationModal.vue +++ b/theseus_gui/src/components/ui/InstanceCreationModal.vue @@ -12,7 +12,7 @@ Select icon - diff --git a/theseus_gui/src/components/ui/ModInstallModal.vue b/theseus_gui/src/components/ui/ModInstallModal.vue index 3db24d713..f78598bcf 100644 --- a/theseus_gui/src/components/ui/ModInstallModal.vue +++ b/theseus_gui/src/components/ui/ModInstallModal.vue @@ -264,7 +264,7 @@ const check_valid = computed(() => { Select icon - diff --git a/theseus_gui/src/pages/instance/Options.vue b/theseus_gui/src/pages/instance/Options.vue index ebc8f6a05..34ab629f8 100644 --- a/theseus_gui/src/pages/instance/Options.vue +++ b/theseus_gui/src/pages/instance/Options.vue @@ -42,7 +42,7 @@ - @@ -631,6 +631,15 @@ const isValid = computed(() => { ) }) +const isChanged = computed(() => { + return ( + loader.value != props.instance.metadata.loader || + gameVersion.value != props.instance.metadata.game_version || + selectableLoaderVersions.value[loaderVersionIndex.value] != + props.instance.metadata.loader_version + ) +}) + watch(loader, () => (loaderVersionIndex.value = 0)) const editing = ref(false) From 1ea7871b4a71682dd5ad066d718bda0b06f8e868 Mon Sep 17 00:00:00 2001 From: Wyatt Verchere Date: Fri, 4 Aug 2023 15:37:17 -0700 Subject: [PATCH 6/9] prettier, fmt, clippy --- theseus/src/api/pack/import/atlauncher.rs | 8 ++- theseus/src/api/pack/import/curseforge.rs | 54 +++++++++++++++---- theseus/src/api/pack/import/gdlauncher.rs | 8 ++- theseus/src/api/pack/import/mmc.rs | 8 ++- theseus/src/api/pack/import/mod.rs | 19 +++++-- theseus/src/api/profile/mod.rs | 26 +++++---- theseus/src/event/emit.rs | 5 +- theseus/src/util/fetch.rs | 24 +++++++++ theseus/src/util/io.rs | 4 +- theseus_gui/src-tauri/src/api/utils.rs | 2 +- .../src/components/ui/ModInstallModal.vue | 2 +- theseus_gui/src/pages/instance/Options.vue | 6 ++- 12 files changed, 132 insertions(+), 34 deletions(-) diff --git a/theseus/src/api/pack/import/atlauncher.rs b/theseus/src/api/pack/import/atlauncher.rs index a162e5620..e54908bfc 100644 --- a/theseus/src/api/pack/import/atlauncher.rs +++ b/theseus/src/api/pack/import/atlauncher.rs @@ -229,7 +229,13 @@ async fn import_atlauncher_unmanaged( .await?; // Moves .minecraft folder over (ie: overrides such as resourcepacks, mods, etc) - copy_dotminecraft(profile_path.clone(), minecraft_folder).await?; + let state = State::get().await?; + copy_dotminecraft( + profile_path.clone(), + minecraft_folder, + &state.io_semaphore, + ) + .await?; if let Some(profile_val) = crate::api::profile::get(&profile_path, None).await? diff --git a/theseus/src/api/pack/import/curseforge.rs b/theseus/src/api/pack/import/curseforge.rs index fe50354e6..9d94c0a6d 100644 --- a/theseus/src/api/pack/import/curseforge.rs +++ b/theseus/src/api/pack/import/curseforge.rs @@ -5,7 +5,10 @@ use serde::{Deserialize, Serialize}; use crate::{ prelude::{ModLoader, ProfilePathId}, state::ProfileInstallStage, - util::io, + util::{ + fetch::{fetch, write_cached_icon}, + io, + }, State, }; @@ -31,13 +34,20 @@ pub struct FlameModLoader { pub primary: bool, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct MinecraftInstance { pub name: Option, pub profile_image_path: Option, + pub installed_modpack: Option, pub game_version: String, // Minecraft game version. Non-prioritized, use this if Vanilla } +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] + +pub struct InstalledModpack { + pub thumbnail_url: Option, +} // Check if folder has a minecraftinstance.json that parses pub async fn is_valid_curseforge(instance_folder: PathBuf) -> bool { @@ -70,13 +80,33 @@ pub async fn import_curseforge( .unwrap_or("Unknown".to_string()) ); + let state = State::get().await?; // Recache Curseforge Icon if it exists - let icon = if let Some(icon_path) = minecraft_instance.profile_image_path.clone() { - recache_icon(icon_path).await? - } else { - None - }; - + let mut icon = None; + println!("{:?}", minecraft_instance); + + if let Some(icon_path) = minecraft_instance.profile_image_path.clone() { + icon = recache_icon(icon_path).await?; + } else if let Some(InstalledModpack { + thumbnail_url: Some(thumbnail_url), + }) = minecraft_instance.installed_modpack.clone() + { + println!("Downloading icon from {}", thumbnail_url); + let icon_bytes = + fetch(&thumbnail_url, None, &state.fetch_semaphore).await?; + let filename = thumbnail_url.rsplit('/').last(); + if let Some(filename) = filename { + icon = Some( + write_cached_icon( + filename, + &state.directories.caches_dir(), + icon_bytes, + &state.io_semaphore, + ) + .await?, + ); + } + } // Curseforge vanilla profile may not have a manifest.json, so we allow it to not exist if curseforge_instance_folder.join("manifest.json").exists() { @@ -152,7 +182,13 @@ pub async fn import_curseforge( } // Copy in contained folders as overrides - copy_dotminecraft(profile_path.clone(), curseforge_instance_folder).await?; + let state = State::get().await?; + copy_dotminecraft( + profile_path.clone(), + curseforge_instance_folder, + &state.io_semaphore, + ) + .await?; if let Some(profile_val) = crate::api::profile::get(&profile_path, None).await? diff --git a/theseus/src/api/pack/import/gdlauncher.rs b/theseus/src/api/pack/import/gdlauncher.rs index 2d9c86e18..f7317b675 100644 --- a/theseus/src/api/pack/import/gdlauncher.rs +++ b/theseus/src/api/pack/import/gdlauncher.rs @@ -100,7 +100,13 @@ pub async fn import_gdlauncher( .await?; // Copy in contained folders as overrides - copy_dotminecraft(profile_path.clone(), gdlauncher_instance_folder).await?; + let state = State::get().await?; + copy_dotminecraft( + profile_path.clone(), + gdlauncher_instance_folder, + &state.io_semaphore, + ) + .await?; if let Some(profile_val) = crate::api::profile::get(&profile_path, None).await? diff --git a/theseus/src/api/pack/import/mmc.rs b/theseus/src/api/pack/import/mmc.rs index f4e00b22a..101e8588c 100644 --- a/theseus/src/api/pack/import/mmc.rs +++ b/theseus/src/api/pack/import/mmc.rs @@ -280,7 +280,13 @@ async fn import_mmc_unmanaged( .await?; // Moves .minecraft folder over (ie: overrides such as resourcepacks, mods, etc) - copy_dotminecraft(profile_path.clone(), minecraft_folder).await?; + let state = State::get().await?; + copy_dotminecraft( + profile_path.clone(), + minecraft_folder, + &state.io_semaphore, + ) + .await?; if let Some(profile_val) = crate::api::profile::get(&profile_path, None).await? diff --git a/theseus/src/api/pack/import/mod.rs b/theseus/src/api/pack/import/mod.rs index 62bc6073d..6b28f73a7 100644 --- a/theseus/src/api/pack/import/mod.rs +++ b/theseus/src/api/pack/import/mod.rs @@ -9,7 +9,10 @@ use serde::{Deserialize, Serialize}; use crate::{ prelude::ProfilePathId, state::Profiles, - util::{fetch, io}, + util::{ + fetch::{self, IoSemaphore}, + io, + }, }; pub mod atlauncher; @@ -237,6 +240,7 @@ pub async fn recache_icon( async fn copy_dotminecraft( profile_path: ProfilePathId, dotminecraft: PathBuf, + io_semaphore: &IoSemaphore, ) -> crate::Result<()> { // Get full path to profile let profile_path = profile_path.get_full_path().await?; @@ -257,6 +261,7 @@ async fn copy_dotminecraft( &path.display() )) })?), + io_semaphore, ) .await?; } @@ -268,9 +273,13 @@ async fn copy_dotminecraft( #[theseus_macros::debug_pin] #[async_recursion::async_recursion] #[tracing::instrument] -async fn copy_dir_to(src: &Path, dst: &Path) -> crate::Result<()> { +async fn copy_dir_to( + src: &Path, + dst: &Path, + io_semaphore: &IoSemaphore, +) -> crate::Result<()> { if !src.is_dir() { - io::copy(src, dst).await?; + fetch::copy(src, dst, io_semaphore).await?; return Ok(()); } @@ -294,10 +303,10 @@ async fn copy_dir_to(src: &Path, dst: &Path) -> crate::Result<()> { if src_child.is_dir() { // Recurse into sub-directory - copy_dir_to(&src_child, &dst_child).await?; + copy_dir_to(&src_child, &dst_child, io_semaphore).await?; } else { // Copy file - io::copy(&src_child, &dst_child).await?; + fetch::copy(&src_child, &dst_child, io_semaphore).await?; } } diff --git a/theseus/src/api/profile/mod.rs b/theseus/src/api/profile/mod.rs index 37d1e4290..1fc712c50 100644 --- a/theseus/src/api/profile/mod.rs +++ b/theseus/src/api/profile/mod.rs @@ -162,7 +162,7 @@ pub async fn edit_icon( emit_profile( profile.uuid, - &path, + path, &profile.metadata.name, ProfilePayloadType::Edited, ) @@ -330,7 +330,7 @@ pub async fn update_all_projects( emit_profile( profile.uuid, - &profile_path, + profile_path, &profile.metadata.name, ProfilePayloadType::Edited, ) @@ -392,7 +392,7 @@ pub async fn update_project( if !skip_send_event.unwrap_or(false) { emit_profile( profile.uuid, - &profile_path, + profile_path, &profile.metadata.name, ProfilePayloadType::Edited, ) @@ -428,7 +428,7 @@ pub async fn add_project_from_version( emit_profile( profile.uuid, - &profile_path, + profile_path, &profile.metadata.name, ProfilePayloadType::Edited, ) @@ -468,7 +468,7 @@ pub async fn add_project_from_path( emit_profile( profile.uuid, - &profile_path, + profile_path, &profile.metadata.name, ProfilePayloadType::Edited, ) @@ -497,7 +497,7 @@ pub async fn toggle_disable_project( emit_profile( profile.uuid, - &profile_path, + profile_path, &profile.metadata.name, ProfilePayloadType::Edited, ) @@ -506,8 +506,10 @@ pub async fn toggle_disable_project( Ok(res) } else { - Err(crate::ErrorKind::UnmanagedProfileError(profile_path.to_string()) - .as_error()) + Err( + crate::ErrorKind::UnmanagedProfileError(profile_path.to_string()) + .as_error(), + ) } } @@ -532,8 +534,10 @@ pub async fn remove_project( Ok(()) } else { - Err(crate::ErrorKind::UnmanagedProfileError(profile_path.to_string()) - .as_error()) + Err( + crate::ErrorKind::UnmanagedProfileError(profile_path.to_string()) + .as_error(), + ) } } @@ -1033,5 +1037,5 @@ pub async fn build_folder( } pub fn sanitize_profile_name(input: &str) -> String { - input.replace(['/', '\\'], "_") + input.replace(['/', '\\', ':'], "_") } diff --git a/theseus/src/event/emit.rs b/theseus/src/event/emit.rs index 0618b447f..b96d962c5 100644 --- a/theseus/src/event/emit.rs +++ b/theseus/src/event/emit.rs @@ -4,7 +4,8 @@ use crate::{ CommandPayload, EventError, LoadingBar, LoadingBarType, ProcessPayloadType, ProfilePayloadType, }, - state::{ProcessType, SafeProcesses}, prelude::ProfilePathId, + prelude::ProfilePathId, + state::{ProcessType, SafeProcesses}, }; use futures::prelude::*; @@ -281,7 +282,7 @@ pub async fn emit_process( #[allow(unused_variables)] pub async fn emit_profile( uuid: Uuid, - profile_path_id : &ProfilePathId, + profile_path_id: &ProfilePathId, name: &str, event: ProfilePayloadType, ) -> crate::Result<()> { diff --git a/theseus/src/util/fetch.rs b/theseus/src/util/fetch.rs index 97cd01cbf..e874414de 100644 --- a/theseus/src/util/fetch.rs +++ b/theseus/src/util/fetch.rs @@ -221,6 +221,30 @@ pub async fn write<'a>( Ok(()) } +pub async fn copy( + src: impl AsRef, + dest: impl AsRef, + semaphore: &IoSemaphore, +) -> crate::Result<()> { + let src: &Path = src.as_ref(); + let dest = dest.as_ref(); + + let io_semaphore = semaphore.0.read().await; + let _permit = io_semaphore.acquire().await?; + + if let Some(parent) = dest.parent() { + io::create_dir_all(parent).await?; + } + + io::copy(src, dest).await?; + tracing::trace!( + "Done copying file {} to {}", + src.display(), + dest.display() + ); + Ok(()) +} + // Writes a icon to the cache and returns the absolute path of the icon within the cache directory #[tracing::instrument(skip(bytes, semaphore))] pub async fn write_cached_icon( diff --git a/theseus/src/util/io.rs b/theseus/src/util/io.rs index b915372a4..840130159 100644 --- a/theseus/src/util/io.rs +++ b/theseus/src/util/io.rs @@ -1,6 +1,8 @@ // IO error // A wrapper around the tokio IO functions that adds the path to the error message, instead of the uninformative std::io::Error. +use std::path::Path; + #[derive(Debug, thiserror::Error)] pub enum IOError { #[error("{source}, path: {path}")] @@ -140,7 +142,7 @@ pub async fn copy( from: impl AsRef, to: impl AsRef, ) -> Result { - let from = from.as_ref(); + let from: &Path = from.as_ref(); let to = to.as_ref(); tokio::fs::copy(from, to) .await diff --git a/theseus_gui/src-tauri/src/api/utils.rs b/theseus_gui/src-tauri/src/api/utils.rs index 8e2afb83d..a86feb58a 100644 --- a/theseus_gui/src-tauri/src/api/utils.rs +++ b/theseus_gui/src-tauri/src/api/utils.rs @@ -1,4 +1,4 @@ -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use theseus::{handler, prelude::CommandPayload, State}; use crate::api::Result; diff --git a/theseus_gui/src/components/ui/ModInstallModal.vue b/theseus_gui/src/components/ui/ModInstallModal.vue index f78598bcf..c9d61c1f5 100644 --- a/theseus_gui/src/components/ui/ModInstallModal.vue +++ b/theseus_gui/src/components/ui/ModInstallModal.vue @@ -264,7 +264,7 @@ const check_valid = computed(() => { Select icon - diff --git a/theseus_gui/src/pages/instance/Options.vue b/theseus_gui/src/pages/instance/Options.vue index 34ab629f8..12fd76051 100644 --- a/theseus_gui/src/pages/instance/Options.vue +++ b/theseus_gui/src/pages/instance/Options.vue @@ -71,7 +71,11 @@ Select icon - From a0427af9a9d8fe8a4e260203ce6230482dd95408 Mon Sep 17 00:00:00 2001 From: Wyatt Verchere Date: Fri, 4 Aug 2023 15:52:51 -0700 Subject: [PATCH 7/9] fix regressed error --- theseus_gui/src/pages/instance/Options.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/theseus_gui/src/pages/instance/Options.vue b/theseus_gui/src/pages/instance/Options.vue index 12fd76051..108d665c4 100644 --- a/theseus_gui/src/pages/instance/Options.vue +++ b/theseus_gui/src/pages/instance/Options.vue @@ -639,8 +639,8 @@ const isChanged = computed(() => { return ( loader.value != props.instance.metadata.loader || gameVersion.value != props.instance.metadata.game_version || - selectableLoaderVersions.value[loaderVersionIndex.value] != - props.instance.metadata.loader_version + JSON.stringify(selectableLoaderVersions.value[loaderVersionIndex.value]) != + JSON.stringify(props.instance.metadata.loader_version) ) }) From be1f36626e086551109f6f4abefd493b9a082f25 Mon Sep 17 00:00:00 2001 From: Wyatt Verchere Date: Fri, 4 Aug 2023 16:01:53 -0700 Subject: [PATCH 8/9] println, console.log --- theseus/src/api/pack/import/curseforge.rs | 2 -- theseus_gui/src/components/ui/InstanceCreationModal.vue | 3 --- theseus_gui/src/components/ui/ModInstallModal.vue | 1 - 3 files changed, 6 deletions(-) diff --git a/theseus/src/api/pack/import/curseforge.rs b/theseus/src/api/pack/import/curseforge.rs index 9d94c0a6d..b1d9c2e64 100644 --- a/theseus/src/api/pack/import/curseforge.rs +++ b/theseus/src/api/pack/import/curseforge.rs @@ -83,7 +83,6 @@ pub async fn import_curseforge( let state = State::get().await?; // Recache Curseforge Icon if it exists let mut icon = None; - println!("{:?}", minecraft_instance); if let Some(icon_path) = minecraft_instance.profile_image_path.clone() { icon = recache_icon(icon_path).await?; @@ -91,7 +90,6 @@ pub async fn import_curseforge( thumbnail_url: Some(thumbnail_url), }) = minecraft_instance.installed_modpack.clone() { - println!("Downloading icon from {}", thumbnail_url); let icon_bytes = fetch(&thumbnail_url, None, &state.fetch_semaphore).await?; let filename = thumbnail_url.rsplit('/').last(); diff --git a/theseus_gui/src/components/ui/InstanceCreationModal.vue b/theseus_gui/src/components/ui/InstanceCreationModal.vue index 56e5b4310..8fb06648e 100644 --- a/theseus_gui/src/components/ui/InstanceCreationModal.vue +++ b/theseus_gui/src/components/ui/InstanceCreationModal.vue @@ -274,7 +274,6 @@ defineExpose({ const unlistener = ref(null) const hide = () => { - console.log('hiding nicely') isShowing.value = false modal.value.hide() if (unlistener.value) { @@ -473,8 +472,6 @@ const reload = async () => { } else { profiles.value.set(selectedProfileType.value.name, []) } - - console.log(instances) } const setPath = () => { diff --git a/theseus_gui/src/components/ui/ModInstallModal.vue b/theseus_gui/src/components/ui/ModInstallModal.vue index c9d61c1f5..de0dcc502 100644 --- a/theseus_gui/src/components/ui/ModInstallModal.vue +++ b/theseus_gui/src/components/ui/ModInstallModal.vue @@ -65,7 +65,6 @@ const profiles = ref([]) async function install(instance) { instance.installing = true - console.log(versions.value) const version = versions.value.find((v) => { return ( v.game_versions.includes(instance.metadata.game_version) && From eea0baa599a23212c11508a105eb44742cddc928 Mon Sep 17 00:00:00 2001 From: Jai A Date: Fri, 4 Aug 2023 20:03:40 -0700 Subject: [PATCH 9/9] fix imports --- theseus_gui/src/App.vue | 7 ++++++- theseus_gui/src/pages/instance/Options.vue | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/theseus_gui/src/App.vue b/theseus_gui/src/App.vue index 2abf35f88..a37541d1e 100644 --- a/theseus_gui/src/App.vue +++ b/theseus_gui/src/App.vue @@ -25,7 +25,12 @@ import { MinimizeIcon, MaximizeIcon } from '@/assets/icons' import { type } from '@tauri-apps/api/os' import { appWindow } from '@tauri-apps/api/window' import { isDev, getOS, isOffline } from '@/helpers/utils.js' -import mixpanel from 'mixpanel-browser' +import { + mixpanel_track, + mixpanel_init, + mixpanel_opt_out_tracking, + mixpanel_is_loaded, +} from '@/helpers/mixpanel' import { saveWindowState, StateFlags } from 'tauri-plugin-window-state-api' import { getVersion } from '@tauri-apps/api/app' import { window as TauriWindow } from '@tauri-apps/api' diff --git a/theseus_gui/src/pages/instance/Options.vue b/theseus_gui/src/pages/instance/Options.vue index 7172a7655..6f1e38fe3 100644 --- a/theseus_gui/src/pages/instance/Options.vue +++ b/theseus_gui/src/pages/instance/Options.vue @@ -97,8 +97,8 @@