You've already forked AstralRinth
forked from didirus/AstralRinth
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:
@@ -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,
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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(['/', '\\'], "_")
|
||||||
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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![
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
19
theseus_gui/src-tauri/tauri.macos.conf.json
Normal file
19
theseus_gui/src-tauri/tauri.macos.conf.json
Normal 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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user