2022-02-21 21:01:45 -08:00
#![ cfg_attr(
2022-03-28 18:41:35 -07:00
all ( not ( debug_assertions ) , target_os = " windows " ) ,
windows_subsystem = " windows "
2022-02-21 21:01:45 -08:00
) ]
2024-08-23 13:50:02 -05:00
use native_dialog ::{ MessageDialog , MessageType } ;
2024-08-20 17:53:14 -07:00
use tauri ::{ Manager , PhysicalSize } ;
2024-08-23 13:50:02 -05:00
use tauri_plugin_window_state ::{ StateFlags , WindowExt } ;
2023-06-30 08:11:32 -07:00
use theseus ::prelude ::* ;
2023-05-08 12:14:08 -07:00
2023-03-31 11:00:43 -07:00
mod api ;
2023-05-08 12:14:08 -07:00
mod error ;
2023-03-31 11:00:43 -07:00
2023-06-30 08:11:32 -07:00
#[ cfg(target_os = " macos " ) ]
mod macos ;
2023-03-31 11:00:43 -07:00
// Should be called in launcher initialization
2023-09-12 09:27:03 -07:00
#[ tracing::instrument(skip_all) ]
2023-03-31 11:00:43 -07:00
#[ tauri::command ]
2023-04-16 10:12:37 -07:00
async fn initialize_state ( app : tauri ::AppHandle ) -> api ::Result < ( ) > {
2024-08-16 23:20:11 -07:00
theseus ::EventState ::init ( app . clone ( ) ) . await ? ;
2024-07-24 11:03:19 -07:00
State ::init ( ) . await ? ;
2023-09-12 09:27:03 -07:00
2024-08-16 23:20:11 -07:00
let state = State ::get ( ) . await ? ;
app . asset_protocol_scope ( )
. allow_directory ( state . directories . caches_dir ( ) , true ) ? ;
2023-03-31 11:00:43 -07:00
Ok ( ( ) )
}
2024-08-16 23:20:11 -07:00
// Should be call once Vue has mounted the app
#[ tracing::instrument(skip_all) ]
#[ tauri::command ]
fn show_window ( app : tauri ::AppHandle ) {
let win = app . get_window ( " main " ) . unwrap ( ) ;
2024-08-23 13:50:02 -05:00
if let Err ( e ) = win . show ( ) {
MessageDialog ::new ( )
. set_type ( MessageType ::Error )
. set_title ( " Initialization error " )
. set_text ( & format! (
" Cannot display application window due to an error: \n {} " ,
e
) )
. show_alert ( )
. unwrap ( ) ;
panic! ( " cannot display application window " )
} else {
let _ = win . restore_state ( StateFlags ::all ( ) ) ;
let _ = win . set_focus ( ) ;
// fix issue where window shows as extremely small
if let Ok ( size ) = win . inner_size ( ) {
let width = if size . width < 1100 { 1280 } else { size . width } ;
let height = if size . height < 700 { 800 } else { size . height } ;
let _ = win . set_size ( PhysicalSize ::new ( width , height ) ) ;
}
2024-08-20 17:53:14 -07:00
}
2024-08-16 23:20:11 -07:00
}
2023-06-19 14:59:06 -07:00
#[ tauri::command ]
fn is_dev ( ) -> bool {
2023-06-26 14:29:53 -07:00
cfg! ( debug_assertions )
2023-06-19 14:59:06 -07:00
}
2023-07-28 19:56:49 -07:00
// Toggles decorations
#[ tauri::command ]
async fn toggle_decorations ( b : bool , window : tauri ::Window ) -> api ::Result < ( ) > {
window . set_decorations ( b ) . map_err ( | e | {
theseus ::Error ::from ( theseus ::ErrorKind ::OtherError ( format! (
" Failed to toggle decorations: {} " ,
e
) ) )
} ) ? ;
Ok ( ( ) )
}
2023-06-02 07:09:46 -07:00
#[ derive(Clone, serde::Serialize) ]
struct Payload {
args : Vec < String > ,
cwd : String ,
}
2023-06-30 08:11:32 -07:00
// if Tauri app is called with arguments, then those arguments will be treated as commands
// ie: deep links or filepaths for .mrpacks
2022-02-21 21:01:45 -08:00
fn main ( ) {
2024-07-24 11:03:19 -07:00
tauri_plugin_deep_link ::prepare ( " ModrinthApp " ) ;
2023-06-19 14:59:06 -07:00
2023-05-08 12:14:08 -07:00
/*
2023-06-30 08:11:32 -07:00
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 )
2023-05-08 12:14:08 -07:00
2023-06-30 08:11:32 -07:00
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
2023-05-08 12:14:08 -07:00
2023-06-30 08:11:32 -07:00
on unix :
RUST_LOG = " theseus=trace " { run command }
2023-05-08 12:14:08 -07:00
* /
2023-06-30 08:11:32 -07:00
let _log_guard = theseus ::start_logger ( ) ;
2023-05-08 12:14:08 -07:00
2023-06-30 08:11:32 -07:00
tracing ::info! ( " Initialized tracing subscriber. Loading Modrinth App! " ) ;
2023-05-08 12:14:08 -07:00
2023-06-30 08:11:32 -07:00
let mut builder = tauri ::Builder ::default ( ) ;
builder = builder
2023-06-02 07:09:46 -07:00
. plugin ( tauri_plugin_single_instance ::init ( | app , argv , cwd | {
app . emit_all ( " single-instance " , Payload { args : argv , cwd } )
. unwrap ( ) ;
} ) )
2023-06-30 08:11:32 -07:00
. plugin ( tauri_plugin_window_state ::Builder ::default ( ) . build ( ) )
. setup ( | app | {
2024-08-16 23:20:11 -07:00
#[ cfg(target_os = " macos " ) ]
let res = {
use macos ::deep_link ::InitialPayload ;
let mtx = std ::sync ::Arc ::new ( tokio ::sync ::Mutex ::new ( None ) ) ;
app . manage ( InitialPayload {
payload : mtx . clone ( ) ,
} ) ;
let mtx_copy = mtx . clone ( ) ;
macos ::delegate ::register_open_file ( move | filename | {
let mtx_copy = mtx_copy . clone ( ) ;
tauri ::async_runtime ::spawn ( async move {
tracing ::info! ( " Handling file open {filename} " ) ;
let mut payload = mtx_copy . lock ( ) . await ;
if payload . is_none ( ) {
* payload = Some ( filename . clone ( ) ) ;
}
let _ = api ::utils ::handle_command ( filename ) . await ;
} ) ;
} )
. unwrap ( ) ;
let mtx_copy = mtx . clone ( ) ;
tauri_plugin_deep_link ::register (
" modrinth " ,
move | request : String | {
let mtx_copy = mtx_copy . clone ( ) ;
tauri ::async_runtime ::spawn ( async move {
tracing ::info! ( " Handling deep link {request} " ) ;
let mut payload = mtx_copy . lock ( ) . await ;
if payload . is_none ( ) {
* payload = Some ( request . clone ( ) ) ;
}
let _ = api ::utils ::handle_command ( request ) . await ;
} ) ;
} ,
)
} ;
#[ cfg(not(target_os = " macos " )) ]
let res = tauri_plugin_deep_link ::register (
2023-06-30 08:11:32 -07:00
" modrinth " ,
| request : String | {
2024-08-16 23:20:11 -07:00
tracing ::info! ( " Handling deep link {request} " ) ;
2023-06-30 08:11:32 -07:00
tauri ::async_runtime ::spawn ( api ::utils ::handle_command (
request ,
) ) ;
} ,
2024-08-16 23:20:11 -07:00
) ;
2023-06-14 20:16:16 -04:00
2024-08-16 23:20:11 -07:00
if let Err ( e ) = res {
tracing ::error! ( " Error registering deep link handler: {} " , e ) ;
2023-06-30 08:11:32 -07:00
}
2023-07-28 19:56:49 -07:00
2024-08-16 23:20:11 -07:00
if let Some ( window ) = app . get_window ( " main " ) {
// Hide window to prevent white flash on startup
2024-08-23 13:50:02 -05:00
let _ = window . hide ( ) ;
2024-08-16 23:20:11 -07:00
#[ cfg(not(target_os = " linux " )) ]
{
use window_shadows ::set_shadow ;
set_shadow ( & window , true ) . unwrap ( ) ;
}
#[ cfg(target_os = " macos " ) ]
{
use macos ::window_ext ::WindowExt ;
window . set_transparent_titlebar ( true ) ;
window . position_traffic_lights ( 9.0 , 16.0 ) ;
}
2023-06-30 08:11:32 -07:00
}
2023-06-20 22:04:17 -07:00
Ok ( ( ) )
} ) ;
2023-06-20 22:03:59 -04:00
2023-06-14 20:16:16 -04:00
#[ cfg(target_os = " macos " ) ]
{
2023-06-20 22:03:59 -04:00
use tauri ::WindowEvent ;
2023-06-30 08:11:32 -07:00
builder = builder . on_window_event ( | e | {
use macos ::window_ext ::WindowExt ;
if let WindowEvent ::Resized ( .. ) = e . event ( ) {
let win = e . window ( ) ;
2023-06-20 00:09:03 -04:00
win . position_traffic_lights ( 9.0 , 16.0 ) ;
2023-06-30 08:11:32 -07:00
}
} )
2023-06-14 20:16:16 -04:00
}
2024-07-24 11:03:19 -07:00
2023-06-28 09:58:58 -07:00
let builder = builder
. plugin ( api ::auth ::init ( ) )
2023-08-04 23:38:34 -07:00
. plugin ( api ::mr_auth ::init ( ) )
2023-07-22 12:37:19 -07:00
. plugin ( api ::import ::init ( ) )
2023-06-28 09:58:58 -07:00
. plugin ( api ::logs ::init ( ) )
. plugin ( api ::jre ::init ( ) )
. plugin ( api ::metadata ::init ( ) )
. plugin ( api ::pack ::init ( ) )
. plugin ( api ::process ::init ( ) )
. plugin ( api ::profile ::init ( ) )
. plugin ( api ::profile_create ::init ( ) )
. plugin ( api ::settings ::init ( ) )
. plugin ( api ::tags ::init ( ) )
. plugin ( api ::utils ::init ( ) )
2024-07-24 11:03:19 -07:00
. plugin ( api ::cache ::init ( ) )
2023-07-28 19:56:49 -07:00
. invoke_handler ( tauri ::generate_handler! [
initialize_state ,
is_dev ,
2023-08-05 17:44:02 -04:00
toggle_decorations ,
2024-04-15 13:58:20 -07:00
api ::auth ::auth_login ,
2024-07-24 11:03:19 -07:00
api ::mr_auth ::modrinth_auth_login ,
2024-08-16 23:20:11 -07:00
show_window ,
2023-07-28 19:56:49 -07:00
] ) ;
2023-06-14 20:16:16 -04:00
2024-08-23 13:50:02 -05:00
if let Err ( e ) = builder . run ( tauri ::generate_context! ( ) ) {
#[ cfg(target_os = " windows " ) ]
{
// tauri doesn't expose runtime errors, so matching a string representation seems like the only solution
if format! ( " {:?} " , e )
. contains ( " Runtime(CreateWebview(WebView2Error(WindowsError " )
{
MessageDialog ::new ( )
. set_type ( MessageType ::Error )
. set_title ( " Initialization error " )
. set_text ( " Your Microsoft Edge WebView2 installation is corrupt. \n \n Microsoft Edge WebView2 is required to run Modrinth App. \n \n Learn how to repair it at https://docs.modrinth.com/faq/app/webview2 " )
. show_alert ( )
. unwrap ( ) ;
panic! ( " webview2 initialization failed " )
}
}
MessageDialog ::new ( )
. set_type ( MessageType ::Error )
. set_title ( " Initialization error " )
. set_text ( & format! (
" Cannot initialize application due to an error: \n {:?} " ,
e
) )
. show_alert ( )
. unwrap ( ) ;
panic! ( " {1} : {:?} " , e , " error while running tauri application " )
}
2022-03-28 18:41:35 -07:00
}