You've already forked AstralRinth
forked from didirus/AstralRinth
Misc settings (#137)
* Initial bug fixes * fix compile error on non-mac * Fix even more bugs * Fix more * fix more * fix build * fix build * Search fixes * Fix small instance ui * working basic * fix javaw issue * removed zip * working functions * merge fixes * fixed loadintg bar bug * menu fix * wait for settings to sync * safety expanded and for loading bars * swtiching to windows * minimize * default landing page * test link registry * url redirection * fix formatting * .mrpack windows * working mrpack reader * changed to one layer deep * working .mrpack + command handling for both opening and existing process * forge version numbers * working mac opening mrpack * reverted changes * prettier/fmt * missed debug statement * improvements + refactoring * renamed things to fit plugin * fixed bugs * removed println * overrides dont include mrpack * merge * fixes * fixes * fixed deletion * merge errors * force sync before export * removed testing * missed line * removed console log * mac error reverted * incoreclty named helper * additional fixes * added removed merges * fixed mislabled invokes * mac * added to new register method * comments, cleanup * mac clippy change * review changes * minor changes * moved create pack * removed playground compilation bug * fixed linux bug; other add ons * fixed review commets * cicd fix * mistaken import for prod * cicd fix --------- Co-authored-by: Jai A <jaiagr+gpg@pm.me>
This commit is contained in:
@@ -13,7 +13,6 @@ pub mod profile_create;
|
||||
pub mod settings;
|
||||
pub mod tags;
|
||||
pub mod utils;
|
||||
pub mod window_ext;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, TheseusSerializableError>;
|
||||
|
||||
@@ -33,6 +32,10 @@ pub enum TheseusSerializableError {
|
||||
|
||||
#[error("IO error: {0}")]
|
||||
IO(#[from] std::io::Error),
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[error("Callback error: {0}")]
|
||||
Callback(String),
|
||||
}
|
||||
|
||||
// Generic implementation of From<T> for ErrorTypeA
|
||||
@@ -80,6 +83,12 @@ macro_rules! impl_serialize {
|
||||
}
|
||||
|
||||
// Use the macro to implement Serialize for TheseusSerializableError
|
||||
#[cfg(target_os = "macos")]
|
||||
impl_serialize! {
|
||||
IO
|
||||
IO,
|
||||
Callback
|
||||
}
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
impl_serialize! {
|
||||
IO,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use theseus::{handler, prelude::CommandPayload, State};
|
||||
|
||||
use crate::api::Result;
|
||||
use std::process::Command;
|
||||
use std::{env, process::Command};
|
||||
|
||||
pub fn init<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> {
|
||||
tauri::plugin::Builder::new("utils")
|
||||
@@ -7,6 +9,9 @@ pub fn init<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> {
|
||||
should_disable_mouseover,
|
||||
show_in_folder,
|
||||
progress_bars_list,
|
||||
safety_check_safe_loading_bars,
|
||||
get_opening_command,
|
||||
await_sync,
|
||||
])
|
||||
.build()
|
||||
}
|
||||
@@ -21,6 +26,12 @@ pub async fn progress_bars_list(
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
// Check if there are any safe loading bars running
|
||||
#[tauri::command]
|
||||
pub async fn safety_check_safe_loading_bars() -> Result<bool> {
|
||||
Ok(theseus::safety::check_safe_loading_bars().await?)
|
||||
}
|
||||
|
||||
// cfg only on mac os
|
||||
// disables mouseover and fixes a random crash error only fixed by recent versions of macos
|
||||
#[cfg(target_os = "macos")]
|
||||
@@ -83,3 +94,34 @@ pub fn show_in_folder(path: String) -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Get opening command
|
||||
// For example, if a user clicks on an .mrpack to open the app.
|
||||
// This should be called once and only when the app is done booting up and ready to receive a command
|
||||
// Returns a Command struct- see events.js
|
||||
#[tauri::command]
|
||||
pub async fn get_opening_command() -> Result<Option<CommandPayload>> {
|
||||
// Tauri is not CLI, we use arguments as path to file to call
|
||||
let cmd_arg = env::args_os().nth(1);
|
||||
|
||||
let cmd_arg = cmd_arg.map(|path| path.to_string_lossy().to_string());
|
||||
if let Some(cmd) = cmd_arg {
|
||||
tracing::debug!("Opening command: {:?}", cmd);
|
||||
return Ok(Some(handler::parse_command(&cmd).await?));
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
// helper function called when redirected by a weblink (ie: modrith://do-something) or when redirected by a .mrpack file (in which case its a filepath)
|
||||
// We hijack the deep link library (which also contains functionality for instance-checking)
|
||||
pub async fn handle_command(command: String) -> Result<()> {
|
||||
Ok(theseus::handler::parse_and_emit_command(&command).await?)
|
||||
}
|
||||
|
||||
// Waits for state to be synced
|
||||
#[tauri::command]
|
||||
pub async fn await_sync() -> Result<()> {
|
||||
State::sync().await?;
|
||||
tracing::info!("State synced");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
98
theseus_gui/src-tauri/src/macos/delegate.rs
Normal file
98
theseus_gui/src-tauri/src/macos/delegate.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
use cocoa::{
|
||||
base::{id, nil},
|
||||
foundation::NSAutoreleasePool,
|
||||
};
|
||||
use objc::{
|
||||
class,
|
||||
declare::ClassDecl,
|
||||
msg_send,
|
||||
runtime::{Class, Object, Sel},
|
||||
sel, sel_impl,
|
||||
};
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
use crate::api::TheseusSerializableError;
|
||||
|
||||
type Callback = OnceCell<Box<dyn Fn(String) + Send + Sync + 'static>>;
|
||||
|
||||
static CALLBACK: Callback = OnceCell::new();
|
||||
|
||||
pub struct AppDelegateClass(pub *const Class);
|
||||
unsafe impl Send for AppDelegateClass {}
|
||||
unsafe impl Sync for AppDelegateClass {}
|
||||
|
||||
// Obj C class for the app delegate
|
||||
// This inherits from the TaoAppDelegate (used by tauri) so we do not accidentally override any functionality
|
||||
// The application_open_file method is the only method we override, as it is currently unimplemented in tauri
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref THESEUS_APP_DELEGATE_CLASS: AppDelegateClass = unsafe {
|
||||
let superclass = class!(TaoAppDelegate);
|
||||
let mut decl = ClassDecl::new("TheseusAppDelegate", superclass).unwrap();
|
||||
|
||||
// Add the method to the class
|
||||
decl.add_method(
|
||||
sel!(application:openFile:),
|
||||
application_open_file as extern "C" fn(&Object, Sel, id, id) -> bool,
|
||||
);
|
||||
|
||||
// Other methods are inherited
|
||||
|
||||
AppDelegateClass(decl.register())
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" fn application_open_file(
|
||||
_: &Object,
|
||||
_: Sel,
|
||||
_: id,
|
||||
file: id,
|
||||
) -> bool {
|
||||
let file = nsstring_to_string(file);
|
||||
callback(file)
|
||||
}
|
||||
|
||||
pub fn callback(file: String) -> bool {
|
||||
if let Some(callback) = CALLBACK.get() {
|
||||
callback(file);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_open_file<T>(
|
||||
callback: T,
|
||||
) -> Result<(), TheseusSerializableError>
|
||||
where
|
||||
T: Fn(String) + Send + Sync + 'static,
|
||||
{
|
||||
unsafe {
|
||||
// Modified from tao: https://github.com/tauri-apps/tao
|
||||
// sets the current app delegate to be the inherited app delegate rather than the default tauri/tao one
|
||||
let app: id = msg_send![class!(TaoApp), sharedApplication];
|
||||
|
||||
let delegate: id = msg_send![THESEUS_APP_DELEGATE_CLASS.0, new];
|
||||
let pool = NSAutoreleasePool::new(nil);
|
||||
let _: () = msg_send![app, setDelegate: delegate];
|
||||
let _: () = msg_send![pool, drain];
|
||||
}
|
||||
CALLBACK.set(Box::new(callback)).map_err(|_| {
|
||||
TheseusSerializableError::Callback("Callback already set".to_string())
|
||||
})
|
||||
}
|
||||
|
||||
/// Convert an NSString to a Rust `String`
|
||||
/// From 'fruitbasket' https://github.com/mrmekon/fruitbasket/
|
||||
#[allow(clippy::cmp_null)]
|
||||
pub fn nsstring_to_string(nsstring: *mut Object) -> String {
|
||||
unsafe {
|
||||
let cstr: *const i8 = msg_send![nsstring, UTF8String];
|
||||
if cstr != std::ptr::null() {
|
||||
std::ffi::CStr::from_ptr(cstr)
|
||||
.to_string_lossy()
|
||||
.into_owned()
|
||||
} else {
|
||||
"".into()
|
||||
}
|
||||
}
|
||||
}
|
||||
2
theseus_gui/src-tauri/src/macos/mod.rs
Normal file
2
theseus_gui/src-tauri/src/macos/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod delegate;
|
||||
pub mod window_ext;
|
||||
@@ -12,7 +12,6 @@ pub trait WindowExt {
|
||||
impl<R: Runtime> WindowExt for Window<R> {
|
||||
fn set_transparent_titlebar(&self, transparent: bool) {
|
||||
use cocoa::appkit::{NSWindow, NSWindowTitleVisibility};
|
||||
|
||||
let window = self.ns_window().unwrap() as cocoa::base::id;
|
||||
|
||||
unsafe {
|
||||
@@ -3,16 +3,15 @@
|
||||
windows_subsystem = "windows"
|
||||
)]
|
||||
|
||||
use theseus::prelude::*;
|
||||
|
||||
use tauri::Manager;
|
||||
|
||||
use tracing_error::ErrorLayer;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use theseus::prelude::*;
|
||||
|
||||
mod api;
|
||||
mod error;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mod macos;
|
||||
|
||||
// Should be called in launcher initialization
|
||||
#[tauri::command]
|
||||
async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> {
|
||||
@@ -27,89 +26,95 @@ fn is_dev() -> bool {
|
||||
cfg!(debug_assertions)
|
||||
}
|
||||
|
||||
use tracing_subscriber::prelude::*;
|
||||
|
||||
#[derive(Clone, serde::Serialize)]
|
||||
struct Payload {
|
||||
args: Vec<String>,
|
||||
cwd: String,
|
||||
}
|
||||
|
||||
// if Tauri app is called with arguments, then those arguments will be treated as commands
|
||||
// ie: deep links or filepaths for .mrpacks
|
||||
fn main() {
|
||||
//let client = sentry::init("https://19a14416dafc4b4a858fa1a38db3b704@o485889.ingest.sentry.io/4505349067374592");
|
||||
tauri_plugin_deep_link::prepare("com.modrinth.theseus");
|
||||
|
||||
//let _guard = sentry_rust_minidump::init(&client);
|
||||
/*
|
||||
tracing is set basd on the environment variable RUST_LOG=xxx, depending on the amount of logs to show
|
||||
ERROR > WARN > INFO > DEBUG > TRACE
|
||||
eg. RUST_LOG=info will show info, warn, and error logs
|
||||
RUST_LOG="theseus=trace" will show *all* messages but from theseus only (and not dependencies using similar crates)
|
||||
RUST_LOG="theseus=trace" will show *all* messages but from theseus only (and not dependencies using similar crates)
|
||||
tracing is set basd on the environment variable RUST_LOG=xxx, depending on the amount of logs to show
|
||||
ERROR > WARN > INFO > DEBUG > TRACE
|
||||
eg. RUST_LOG=info will show info, warn, and error logs
|
||||
RUST_LOG="theseus=trace" will show *all* messages but from theseus only (and not dependencies using similar crates)
|
||||
RUST_LOG="theseus=trace" will show *all* messages but from theseus only (and not dependencies using similar crates)
|
||||
|
||||
Error messages returned to Tauri will display as traced error logs if they return an error.
|
||||
This will also include an attached span trace if the error is from a tracing error, and the level is set to info, debug, or trace
|
||||
Error messages returned to Tauri will display as traced error logs if they return an error.
|
||||
This will also include an attached span trace if the error is from a tracing error, and the level is set to info, debug, or trace
|
||||
|
||||
on unix:
|
||||
RUST_LOG="theseus=trace" {run command}
|
||||
on unix:
|
||||
RUST_LOG="theseus=trace" {run command}
|
||||
|
||||
*/
|
||||
let filter = EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| EnvFilter::new("theseus=info"));
|
||||
let _log_guard = theseus::start_logger();
|
||||
|
||||
let subscriber = tracing_subscriber::registry()
|
||||
.with(tracing_subscriber::fmt::layer())
|
||||
.with(filter)
|
||||
.with(ErrorLayer::default());
|
||||
tracing::info!("Initialized tracing subscriber. Loading Modrinth App!");
|
||||
|
||||
tracing::subscriber::set_global_default(subscriber)
|
||||
.expect("setting default subscriber failed");
|
||||
|
||||
let mut builder = tauri::Builder::default()
|
||||
let mut builder = tauri::Builder::default();
|
||||
builder = builder
|
||||
.plugin(tauri_plugin_single_instance::init(|app, argv, cwd| {
|
||||
app.emit_all("single-instance", Payload { args: argv, cwd })
|
||||
.unwrap();
|
||||
}))
|
||||
.plugin(tauri_plugin_window_state::Builder::default().build());
|
||||
.plugin(tauri_plugin_window_state::Builder::default().build())
|
||||
.setup(|app| {
|
||||
// Register deep link handler, allowing reading of modrinth:// links
|
||||
if let Err(e) = tauri_plugin_deep_link::register(
|
||||
"modrinth",
|
||||
|request: String| {
|
||||
tauri::async_runtime::spawn(api::utils::handle_command(
|
||||
request,
|
||||
));
|
||||
},
|
||||
) {
|
||||
// Allow it to fail- see https://github.com/FabianLars/tauri-plugin-deep-link/issues/19
|
||||
tracing::error!("Error registering deep link handler: {}", e);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
builder = builder.setup(|app| {
|
||||
let win = app.get_window("main").unwrap();
|
||||
win.set_decorations(false).unwrap();
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
use window_shadows::set_shadow;
|
||||
set_shadow(&win, true).unwrap();
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
use macos::window_ext::WindowExt;
|
||||
win.set_transparent_titlebar(true);
|
||||
win.position_traffic_lights(9.0, 16.0);
|
||||
}
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
win.set_decorations(false).unwrap();
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
macos::delegate::register_open_file(|filename| {
|
||||
tauri::async_runtime::spawn(api::utils::handle_command(
|
||||
filename,
|
||||
));
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
use window_shadows::set_shadow;
|
||||
|
||||
builder = builder.setup(|app| {
|
||||
let win = app.get_window("main").unwrap();
|
||||
set_shadow(&win, true).unwrap();
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
use tauri::WindowEvent;
|
||||
|
||||
builder = builder
|
||||
.setup(|app| {
|
||||
use api::window_ext::WindowExt;
|
||||
let win = app.get_window("main").unwrap();
|
||||
win.set_transparent_titlebar(true);
|
||||
builder = builder.on_window_event(|e| {
|
||||
use macos::window_ext::WindowExt;
|
||||
if let WindowEvent::Resized(..) = e.event() {
|
||||
let win = e.window();
|
||||
win.position_traffic_lights(9.0, 16.0);
|
||||
Ok(())
|
||||
})
|
||||
.on_window_event(|e| {
|
||||
use api::window_ext::WindowExt;
|
||||
if let WindowEvent::Resized(..) = e.event() {
|
||||
let win = e.window();
|
||||
win.position_traffic_lights(9.0, 16.0);
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
let builder = builder
|
||||
.plugin(api::auth::init())
|
||||
|
||||
Reference in New Issue
Block a user