Bug fixes (#406)

* skip duplicates

* slash, exports

* fullscreen, exports

* more bugs

* fixed mac title bar

* filters should go to top of page when changed

* mac err, loading bars

* temporary comments

* moving to mac

* bug fixes, fmt, prettier

* review fixes

* rev fixes
This commit is contained in:
Wyatt Verchere
2023-08-03 10:29:58 -07:00
committed by GitHub
parent ddbd08bc8c
commit b772f916b1
15 changed files with 133 additions and 87 deletions

View File

@@ -29,7 +29,7 @@ pub mod prelude {
profile::{self, create, Profile}, profile::{self, create, Profile},
settings, settings,
state::JavaGlobals, state::JavaGlobals,
state::{ProfilePathId, ProjectPathId}, state::{Dependency, ProfilePathId, ProjectPathId},
util::{ util::{
io::{canonicalize, IOError}, io::{canonicalize, IOError},
jre::JavaVersion, jre::JavaVersion,

View File

@@ -155,7 +155,7 @@ pub fn get_profile_from_pack(
}, },
CreatePackLocation::FromFile { path } => { CreatePackLocation::FromFile { path } => {
let file_name = path let file_name = path
.file_name() .file_stem()
.unwrap_or_default() .unwrap_or_default()
.to_string_lossy() .to_string_lossy()
.to_string(); .to_string();

View File

@@ -1,6 +1,7 @@
//! Theseus profile management interface //! Theseus profile management interface
use crate::pack::install_from::CreatePackProfile; use crate::pack::install_from::CreatePackProfile;
use crate::prelude::ProfilePathId; use crate::prelude::ProfilePathId;
use crate::profile;
use crate::state::LinkedData; use crate::state::LinkedData;
use crate::util::io::{self, canonicalize}; use crate::util::io::{self, canonicalize};
use crate::{ use crate::{
@@ -32,11 +33,14 @@ pub async fn profile_create(
linked_data: Option<LinkedData>, // the linked project ID (mainly for modpacks)- used for updating linked_data: Option<LinkedData>, // the linked project ID (mainly for modpacks)- used for updating
skip_install_profile: Option<bool>, skip_install_profile: Option<bool>,
) -> crate::Result<ProfilePathId> { ) -> crate::Result<ProfilePathId> {
name = profile::sanitize_profile_name(&name);
trace!("Creating new profile. {}", name); trace!("Creating new profile. {}", name);
let state = State::get().await?; let state = State::get().await?;
let uuid = Uuid::new_v4(); let uuid = Uuid::new_v4();
let mut path = state.directories.profiles_dir().await.join(&name); let mut path = state.directories.profiles_dir().await.join(&name);
if path.exists() { if path.exists() {
let mut new_name; let mut new_name;
let mut new_path; let mut new_path;

View File

@@ -623,24 +623,22 @@ pub async fn export_mrpack(
// Get highest level folder pair ('a/b' in 'a/b/c', 'a' in 'a') // Get highest level folder pair ('a/b' in 'a/b/c', 'a' in 'a')
// We only go one layer deep for the sake of not having a huge list of overrides // We only go one layer deep for the sake of not having a huge list of overrides
let topmost_two = relative_path let topmost_two = relative_path.iter().take(2).collect::<Vec<_>>();
.iter()
.take(2)
.map(|os| os.to_string_lossy().to_string())
.collect::<Vec<_>>();
// a,b => a/b // a,b => a/b
// a => a // a => a
let topmost = match topmost_two.len() { let topmost = match topmost_two.len() {
2 => topmost_two.join("/"), 2 => PathBuf::from(topmost_two[0]).join(topmost_two[1]),
1 => topmost_two[0].clone(), 1 => PathBuf::from(topmost_two[0]),
_ => { _ => {
return Err(crate::ErrorKind::OtherError( return Err(crate::ErrorKind::OtherError(
"No topmost folder found".to_string(), "No topmost folder found".to_string(),
) )
.into()) .into())
} }
}; }
.to_string_lossy()
.to_string();
if !included_overrides.contains(&topmost) { if !included_overrides.contains(&topmost) {
continue; continue;
@@ -851,13 +849,14 @@ pub async fn run_credentials(
}; };
// Any options.txt settings that we want set, add here // Any options.txt settings that we want set, add here
let mc_set_options: Vec<(String, String)> = vec![( let mut mc_set_options: Vec<(String, String)> = vec![];
"fullscreen".to_string(), if let Some(fullscreen) = profile.fullscreen {
profile // Profile fullscreen setting takes priority
.fullscreen mc_set_options.push(("fullscreen".to_string(), fullscreen.to_string()));
.unwrap_or(settings.force_fullscreen) } else if settings.force_fullscreen {
.to_string(), // If global settings wants to force a fullscreen, do it
)]; mc_set_options.push(("fullscreen".to_string(), "true".to_string()));
}
let mc_process = crate::launcher::launch_minecraft( let mc_process = crate::launcher::launch_minecraft(
java_args, java_args,
@@ -929,15 +928,11 @@ pub async fn create_mrpack_json(
.map(|(k, v)| (k, sanitize_loader_version_string(&v).to_string())) .map(|(k, v)| (k, sanitize_loader_version_string(&v).to_string()))
.collect::<HashMap<_, _>>(); .collect::<HashMap<_, _>>();
let profile_base_path = profile.get_profile_full_path().await?;
let files: Result<Vec<PackFile>, crate::ErrorKind> = profile let files: Result<Vec<PackFile>, crate::ErrorKind> = profile
.projects .projects
.iter() .iter()
.filter_map(|(mod_path, project)| { .filter_map(|(mod_path, project)| {
let path: String = profile_base_path let path: String = mod_path.0.clone().to_string_lossy().to_string();
.join(mod_path.0.clone())
.to_string_lossy()
.to_string();
// Only Modrinth projects have a modrinth metadata field for the modrinth.json // Only Modrinth projects have a modrinth metadata field for the modrinth.json
Some(Ok(match project.metadata { Some(Ok(match project.metadata {
@@ -1035,3 +1030,7 @@ pub async fn build_folder(
} }
Ok(()) Ok(())
} }
pub fn sanitize_profile_name(input: &str) -> String {
input.replace(['/', '\\'], "_")
}

View File

@@ -6,6 +6,7 @@ use crate::util::fetch::{
fetch_json, write_cached_icon, FetchSemaphore, IoSemaphore, fetch_json, write_cached_icon, FetchSemaphore, IoSemaphore,
}; };
use crate::util::io::IOError; use crate::util::io::IOError;
use async_zip::tokio::read::fs::ZipFileReader; use async_zip::tokio::read::fs::ZipFileReader;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use futures::StreamExt; use futures::StreamExt;
@@ -49,6 +50,27 @@ impl ProjectType {
} }
} }
pub fn get_from_parent_folder(path: PathBuf) -> Option<Self> {
// Get parent folder
let path = path.parent()?.file_name()?;
match path.to_str()? {
"mods" => Some(ProjectType::Mod),
"datapacks" => Some(ProjectType::DataPack),
"resourcepacks" => Some(ProjectType::ResourcePack),
"shaderpacks" => Some(ProjectType::ShaderPack),
_ => None,
}
}
pub fn get_name(&self) -> &'static str {
match self {
ProjectType::Mod => "mod",
ProjectType::DataPack => "datapack",
ProjectType::ResourcePack => "resourcepack",
ProjectType::ShaderPack => "shaderpack",
}
}
pub fn get_folder(&self) -> &'static str { pub fn get_folder(&self) -> &'static str {
match self { match self {
ProjectType::Mod => "mods", ProjectType::Mod => "mods",
@@ -439,6 +461,8 @@ pub async fn infer_data_from_files(
)); ));
continue; continue;
}; };
// Forge
let zip_index_option = zip_file_reader let zip_index_option = zip_file_reader
.file() .file()
.entries() .entries()
@@ -512,6 +536,7 @@ pub async fn infer_data_from_files(
} }
} }
// Forge
let zip_index_option = zip_file_reader let zip_index_option = zip_file_reader
.file() .file()
.entries() .entries()
@@ -572,6 +597,7 @@ pub async fn infer_data_from_files(
} }
} }
// Fabric
let zip_index_option = zip_file_reader let zip_index_option = zip_file_reader
.file() .file()
.entries() .entries()
@@ -641,6 +667,7 @@ pub async fn infer_data_from_files(
} }
} }
// Quilt
let zip_index_option = zip_file_reader let zip_index_option = zip_file_reader
.file() .file()
.entries() .entries()
@@ -717,6 +744,7 @@ pub async fn infer_data_from_files(
} }
} }
// Other
let zip_index_option = zip_file_reader let zip_index_option = zip_file_reader
.file() .file()
.entries() .entries()
@@ -745,6 +773,10 @@ pub async fn infer_data_from_files(
io_semaphore, io_semaphore,
) )
.await?; .await?;
// Guess the project type from the filepath
let project_type =
ProjectType::get_from_parent_folder(path.clone());
return_projects.push(( return_projects.push((
path.clone(), path.clone(),
Project { Project {
@@ -757,7 +789,8 @@ pub async fn infer_data_from_files(
authors: Vec::new(), authors: Vec::new(),
version: None, version: None,
icon, icon,
project_type: None, project_type: project_type
.map(|x| x.get_name().to_string()),
}, },
}, },
)); ));
@@ -778,7 +811,6 @@ pub async fn infer_data_from_files(
} }
// Project paths should be relative // Project paths should be relative
let _profile_base_path = profile.get_profile_full_path().await?;
let mut corrected_hashmap = HashMap::new(); let mut corrected_hashmap = HashMap::new();
let mut stream = tokio_stream::iter(return_projects); let mut stream = tokio_stream::iter(return_projects);
while let Some((h, v)) = stream.next().await { while let Some((h, v)) = stream.next().await {

View File

@@ -59,5 +59,10 @@
</dict> </dict>
</dict> </dict>
</array> </array>
<key>NSCameraUsageDescription</key>
<string>A Minecraft mod wants to access your camera.</string>
<key>NSMicrophoneUsageDescription</key>
<string>A Minecraft mod wants to access your microphone.</string>
</dict> </dict>
</plist> </plist>

View File

@@ -1,27 +1,8 @@
use std::path::PathBuf; use std::path::PathBuf;
use crate::api::Result; use crate::api::Result;
use serde::{Deserialize, Serialize};
use theseus::prelude::*; use theseus::prelude::*;
// Identical to theseus::settings::Settings except for the custom_java_args field
// This allows us to split the custom_java_args string into a Vec<String> here and join it back into a string in the backend
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FrontendSettings {
pub theme: Theme,
pub memory: MemorySettings,
pub game_resolution: WindowSize,
pub custom_java_args: String,
pub custom_env_args: String,
pub java_globals: JavaGlobals,
pub default_user: Option<uuid::Uuid>,
pub hooks: Hooks,
pub max_concurrent_downloads: usize,
pub max_concurrent_writes: usize,
pub version: u32,
pub collapsed_navigation: bool,
}
pub fn init<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> { pub fn init<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> {
tauri::plugin::Builder::new("settings") tauri::plugin::Builder::new("settings")
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![

View File

@@ -35,7 +35,6 @@ async fn toggle_decorations(b: bool, window: tauri::Window) -> api::Result<()> {
e e
))) )))
})?; })?;
println!("Toggled decorations!");
Ok(()) Ok(())
} }
@@ -97,8 +96,6 @@ fn main() {
} }
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
{ {
win.set_decorations(true).unwrap();
use macos::window_ext::WindowExt; use macos::window_ext::WindowExt;
win.set_transparent_titlebar(true); win.set_transparent_titlebar(true);
win.position_traffic_lights(9.0, 16.0); win.position_traffic_lights(9.0, 16.0);

View File

@@ -0,0 +1,19 @@
{
"tauri": {
"windows": [
{
"titleBarStyle": "Overlay",
"hiddenTitle": true,
"fullscreen": false,
"height": 650,
"resizable": true,
"title": "Modrinth App",
"width": 1280,
"minHeight": 630,
"minWidth": 1100,
"visible": false,
"decorations": true
}
]
}
}

View File

@@ -98,7 +98,13 @@ const confirmClose = async () => {
} }
const handleClose = async () => { const handleClose = async () => {
const isSafe = await check_safe_loading_bars_complete() // State should respond immeiately if it's safe to close
// If not, code is deadlocked or worse, so wait 2 seconds and then ask the user to confirm closing
// (Exception: if the user is changing config directory, which takes control of the state, and it's taking a significant amount of time for some reason)
const isSafe = await Promise.race([
check_safe_loading_bars_complete(),
new Promise((r) => setTimeout(r, 2000)),
])
if (!isSafe) { if (!isSafe) {
const response = await confirmClose() const response = await confirmClose()
if (!response) { if (!response) {

View File

@@ -6,6 +6,7 @@ import { export_profile_mrpack, get_potential_override_folders } from '@/helpers
import { open } from '@tauri-apps/api/dialog' import { open } from '@tauri-apps/api/dialog'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import { sep } from '@tauri-apps/api/path' import { sep } from '@tauri-apps/api/path'
import { useTheming } from '@/store/theme'
const props = defineProps({ const props = defineProps({
instance: { instance: {
@@ -27,6 +28,8 @@ const versionInput = ref('1.0.0')
const files = ref([]) const files = ref([])
const folders = ref([]) const folders = ref([])
const themeStore = useTheming()
const initFiles = async () => { const initFiles = async () => {
const newFolders = new Map() const newFolders = new Map()
files.value = [] files.value = []
@@ -88,7 +91,7 @@ const exportPack = async () => {
</script> </script>
<template> <template>
<Modal ref="exportModal" header="Export modpack"> <Modal ref="exportModal" header="Export modpack" :noblur="!themeStore.advancedRendering">
<div class="modal-body"> <div class="modal-body">
<div class="labeled_input"> <div class="labeled_input">
<p>Modpack Name</p> <p>Modpack Name</p>

View File

@@ -141,21 +141,17 @@ async function refreshSearch() {
const base = 'https://api.modrinth.com/v2/' const base = 'https://api.modrinth.com/v2/'
const params = [`limit=${maxResults.value}`, `index=${sortType.value.name}`] const params = [`limit=${maxResults.value}`, `index=${sortType.value.name}`]
if (query.value.length > 0) { if (query.value.length > 0) {
params.push(`query=${query.value.replace(/ /g, '+')}`) params.push(`query=${query.value.replace(/ /g, '+')}`)
} }
if (instanceContext.value) { if (instanceContext.value) {
if (!ignoreInstanceLoaders.value && projectType.value === 'mod') { if (!ignoreInstanceLoaders.value && projectType.value === 'mod') {
orFacets.value = [`categories:${encodeURIComponent(instanceContext.value.metadata.loader)}`] orFacets.value = [`categories:${encodeURIComponent(instanceContext.value.metadata.loader)}`]
} }
if (!ignoreInstanceGameVersions.value) { if (!ignoreInstanceGameVersions.value) {
selectedVersions.value = [instanceContext.value.metadata.game_version] selectedVersions.value = [instanceContext.value.metadata.game_version]
} }
} }
if ( if (
facets.value.length > 0 || facets.value.length > 0 ||
orFacets.value.length > 0 || orFacets.value.length > 0 ||
@@ -167,7 +163,6 @@ async function refreshSearch() {
for (const facet of facets.value) { for (const facet of facets.value) {
formattedFacets.push([facet]) formattedFacets.push([facet])
} }
// loaders specifier // loaders specifier
if (orFacets.value.length > 0) { if (orFacets.value.length > 0) {
formattedFacets.push(orFacets.value) formattedFacets.push(orFacets.value)
@@ -186,14 +181,12 @@ async function refreshSearch() {
} }
formattedFacets.push(versionFacets) formattedFacets.push(versionFacets)
} }
if (onlyOpenSource.value) { if (onlyOpenSource.value) {
formattedFacets.push(['open_source:true']) formattedFacets.push(['open_source:true'])
} }
if (selectedEnvironments.value.length > 0) { if (selectedEnvironments.value.length > 0) {
let environmentFacets = [] let environmentFacets = []
const includesClient = selectedEnvironments.value.includes('client') const includesClient = selectedEnvironments.value.includes('client')
const includesServer = selectedEnvironments.value.includes('server') const includesServer = selectedEnvironments.value.includes('server')
if (includesClient && includesServer) { if (includesClient && includesServer) {
@@ -224,14 +217,11 @@ async function refreshSearch() {
params.push(`facets=${JSON.stringify(formattedFacets)}`) params.push(`facets=${JSON.stringify(formattedFacets)}`)
} }
const offset = (currentPage.value - 1) * maxResults.value const offset = (currentPage.value - 1) * maxResults.value
if (currentPage.value !== 1) { if (currentPage.value !== 1) {
params.push(`offset=${offset}`) params.push(`offset=${offset}`)
} }
let url = 'search' let url = 'search'
if (params.length > 0) { if (params.length > 0) {
for (let i = 0; i < params.length; i++) { for (let i = 0; i < params.length; i++) {
url += i === 0 ? `?${params[i]}` : `&${params[i]}` url += i === 0 ? `?${params[i]}` : `&${params[i]}`
@@ -257,12 +247,15 @@ async function onSearchChange(newPageNumber) {
if (query.value === null) { if (query.value === null) {
return return
} }
await refreshSearch() await refreshSearch()
const obj = getSearchUrl((currentPage.value - 1) * maxResults.value, true) const obj = getSearchUrl((currentPage.value - 1) * maxResults.value, true)
await router.replace({ path: route.path, query: obj })
breadcrumbs.setContext({ name: 'Browse', link: route.path, query: obj }) // Only replace in router if the query is different
if (JSON.stringify(obj) != JSON.stringify(route.query)) {
await router.replace({ path: route.path, query: obj })
breadcrumbs.setContext({ name: 'Browse', link: route.path, query: obj })
}
} }
const searchWrapper = ref(null) const searchWrapper = ref(null)
@@ -363,7 +356,6 @@ const sortedCategories = computed(() => {
// Sorts alphabetically, but correctly identifies 8x, 128x, 256x, etc // Sorts alphabetically, but correctly identifies 8x, 128x, 256x, etc
// identifier[0], then if it ties, identifier[1], etc // identifier[0], then if it ties, identifier[1], etc
async function sortByNameOrNumber(sortable, identifiers) { async function sortByNameOrNumber(sortable, identifiers) {
console.log(sortable)
sortable.sort((a, b) => { sortable.sort((a, b) => {
for (let identifier of identifiers) { for (let identifier of identifiers) {
let aNum = parseFloat(a[identifier]) let aNum = parseFloat(a[identifier])
@@ -394,11 +386,10 @@ async function clearFilters() {
for (const facet of [...orFacets.value]) { for (const facet of [...orFacets.value]) {
await toggleOrFacet(facet, true) await toggleOrFacet(facet, true)
} }
onlyOpenSource.value = false onlyOpenSource.value = false
selectedVersions.value = [] selectedVersions.value = []
selectedEnvironments.value = [] selectedEnvironments.value = []
await onSearchChange(1) await onSearchChangeToTop(1)
} }
async function toggleFacet(elementName, doNotSendRequest = false) { async function toggleFacet(elementName, doNotSendRequest = false) {
@@ -411,7 +402,7 @@ async function toggleFacet(elementName, doNotSendRequest = false) {
} }
if (!doNotSendRequest) { if (!doNotSendRequest) {
await onSearchChange(1) await onSearchChangeToTop(1)
} }
} }
@@ -424,7 +415,7 @@ async function toggleOrFacet(elementName, doNotSendRequest) {
} }
if (!doNotSendRequest) { if (!doNotSendRequest) {
await onSearchChange(1) await onSearchChangeToTop(1)
} }
} }
@@ -437,14 +428,16 @@ function toggleEnv(environment, sendRequest) {
} }
if (!sendRequest) { if (!sendRequest) {
onSearchChange(1) onSearchChangeToTop(1)
} }
} }
watch( watch(
() => route.params.projectType, () => route.params.projectType,
async (newType) => { async (newType) => {
if (!newType) return // Check if the newType is not the same as the current value
if (!newType || newType === projectType.value) return
projectType.value = newType projectType.value = newType
breadcrumbs.setContext({ name: 'Browse', link: `/browse/${projectType.value}` }) breadcrumbs.setContext({ name: 'Browse', link: `/browse/${projectType.value}` })
@@ -601,7 +594,7 @@ const showLoaders = computed(
:clear-search-on-select="false" :clear-search-on-select="false"
:show-labels="false" :show-labels="false"
placeholder="Choose versions..." placeholder="Choose versions..."
@update:model-value="onSearchChange(1)" @update:model-value="onSearchChangeToTop(1)"
/> />
</div> </div>
<div <div
@@ -648,7 +641,7 @@ const showLoaders = computed(
v-model="onlyOpenSource" v-model="onlyOpenSource"
label="Open source only" label="Open source only"
class="filter-checkbox" class="filter-checkbox"
@update:model-value="onSearchChange(1)" @update:model-value="onSearchChangeToTop(1)"
/> />
</div> </div>
</Card> </Card>

View File

@@ -1,6 +1,6 @@
<script setup> <script setup>
import { ref, watch } from 'vue' import { ref, watch } from 'vue'
import { Card, Slider, DropdownSelect, Toggle } from 'omorphia' import { Card, Slider, DropdownSelect, Checkbox, Toggle } from 'omorphia'
import { handleError, useTheming } from '@/store/state' import { handleError, useTheming } from '@/store/state'
import { get, set } from '@/helpers/settings' import { get, set } from '@/helpers/settings'
import { get_max_memory } from '@/helpers/jre' import { get_max_memory } from '@/helpers/jre'
@@ -333,10 +333,10 @@ watch(
<label for="fullscreen"> <label for="fullscreen">
<span class="label__title">Fullscreen</span> <span class="label__title">Fullscreen</span>
<span class="label__description"> <span class="label__description">
Make the game start in full screen when launched. Overwrites the option.txt file to start in full screen when launched.
</span> </span>
</label> </label>
<Toggle id="fullscreen" v-model="settings.fullscreen" /> <Checkbox id="fullscreen" v-model="settings.force_fullscreen" />
</div> </div>
<div class="adjacent-input"> <div class="adjacent-input">
<label for="width"> <label for="width">
@@ -346,7 +346,7 @@ watch(
<input <input
id="width" id="width"
v-model="settings.game_resolution[0]" v-model="settings.game_resolution[0]"
:disabled="settings.fullscreen" :disabled="settings.force_fullscreen"
autocomplete="off" autocomplete="off"
type="number" type="number"
placeholder="Enter width..." placeholder="Enter width..."
@@ -360,7 +360,7 @@ watch(
<input <input
id="height" id="height"
v-model="settings.game_resolution[1]" v-model="settings.game_resolution[1]"
:disabled="settings.fullscreen" :disabled="settings.force_fullscreen"
autocomplete="off" autocomplete="off"
type="number" type="number"
class="input" class="input"

View File

@@ -351,6 +351,7 @@ import { listen } from '@tauri-apps/api/event'
import { convertFileSrc } from '@tauri-apps/api/tauri' import { convertFileSrc } from '@tauri-apps/api/tauri'
import { showProfileInFolder } from '@/helpers/utils.js' import { showProfileInFolder } from '@/helpers/utils.js'
import { MenuIcon, ToggleIcon, TextInputIcon, AddProjectImage } from '@/assets/icons' import { MenuIcon, ToggleIcon, TextInputIcon, AddProjectImage } from '@/assets/icons'
import { install_from_file } from '@/helpers/pack'
const router = useRouter() const router = useRouter()
@@ -769,10 +770,17 @@ watch(selectAll, () => {
}) })
listen('tauri://file-drop', async (event) => { listen('tauri://file-drop', async (event) => {
for (const file of event.payload) { if (event.payload && event.payload.length > 0 && event.payload[0].endsWith('.mrpack')) {
await add_project_from_path(props.instance.path, file, 'mod').catch(handleError) await install_from_file(event.payload[0]).catch(handleError)
} else {
for (const file of event.payload) {
await add_project_from_path(props.instance.path, file, 'mod').catch(handleError)
}
initProjects(await get(props.instance.path).catch(handleError))
} }
initProjects(await get(props.instance.path).catch(handleError)) mixpanel.track('InstanceCreate', {
source: 'FileDrop',
})
}) })
</script> </script>

View File

@@ -190,7 +190,7 @@
<span class="label__title">Fullscreen</span> <span class="label__title">Fullscreen</span>
<span class="label__description"> Make the game start in full screen when launched. </span> <span class="label__description"> Make the game start in full screen when launched. </span>
</label> </label>
<Toggle id="fullscreen" v-model="fullscreen" :disabled="!overrideWindowSettings" /> <Checkbox id="fullscreen" v-model="fullscreenSetting" :disabled="!overrideWindowSettings" />
</div> </div>
<div class="adjacent-input"> <div class="adjacent-input">
<label for="width"> <label for="width">
@@ -201,7 +201,7 @@
id="width" id="width"
v-model="resolution[0]" v-model="resolution[0]"
autocomplete="off" autocomplete="off"
:disabled="!overrideWindowSettings || fullscreen" :disabled="!overrideWindowSettings || fullscreenSetting"
type="number" type="number"
placeholder="Enter width..." placeholder="Enter width..."
/> />
@@ -215,7 +215,7 @@
id="height" id="height"
v-model="resolution[1]" v-model="resolution[1]"
autocomplete="off" autocomplete="off"
:disabled="!overrideWindowSettings || fullscreen" :disabled="!overrideWindowSettings || fullscreenSetting"
type="number" type="number"
class="input" class="input"
placeholder="Enter height..." placeholder="Enter height..."
@@ -352,7 +352,6 @@ import {
HammerIcon, HammerIcon,
DownloadIcon, DownloadIcon,
ModalConfirm, ModalConfirm,
Toggle,
} from 'omorphia' } from 'omorphia'
import { Multiselect } from 'vue-multiselect' import { Multiselect } from 'vue-multiselect'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
@@ -446,12 +445,12 @@ const overrideMemorySettings = ref(!!props.instance.memory)
const memory = ref(props.instance.memory ?? globalSettings.memory) const memory = ref(props.instance.memory ?? globalSettings.memory)
const maxMemory = Math.floor((await get_max_memory().catch(handleError)) / 1024) const maxMemory = Math.floor((await get_max_memory().catch(handleError)) / 1024)
const overrideWindowSettings = ref(!!props.instance.resolution) const overrideWindowSettings = ref(!!props.instance.resolution || !!props.instance.fullscreen)
const resolution = ref(props.instance.resolution ?? globalSettings.game_resolution) const resolution = ref(props.instance.resolution ?? globalSettings.game_resolution)
const overrideHooks = ref(!!props.instance.hooks) const overrideHooks = ref(!!props.instance.hooks)
const hooks = ref(props.instance.hooks ?? globalSettings.hooks) const hooks = ref(props.instance.hooks ?? globalSettings.hooks)
const fullscreen = ref(props.instance.fullscreen) const fullscreenSetting = ref(!!props.instance.fullscreen)
watch( watch(
[ [
@@ -468,7 +467,7 @@ watch(
memory, memory,
overrideWindowSettings, overrideWindowSettings,
resolution, resolution,
fullscreen, fullscreenSetting,
overrideHooks, overrideHooks,
hooks, hooks,
], ],
@@ -514,9 +513,9 @@ watch(
} }
if (overrideWindowSettings.value) { if (overrideWindowSettings.value) {
editProfile.fullscreen = fullscreen.value editProfile.fullscreen = fullscreenSetting.value
if (!fullscreen.value) { if (!fullscreenSetting.value) {
editProfile.resolution = resolution.value editProfile.resolution = resolution.value
} }
} }