mirror of
				https://github.com/yuzu-emu/liftinstall.git
				synced 2025-11-04 15:34:52 +00:00 
			
		
		
		
	Launch app on fresh install exit. Add desktop shortcuts
This commit is contained in:
		
							parent
							
								
									9b58c273d1
								
							
						
					
					
						commit
						732e344605
					
				| 
						 | 
				
			
			@ -12,6 +12,35 @@ auth_url = "https://api.yuzu-emu.org/jwt/installer/"
 | 
			
		|||
    iss = "citra-core"
 | 
			
		||||
    aud = "installer"
 | 
			
		||||
 | 
			
		||||
[[packages]]
 | 
			
		||||
name = "yuzu Early Access"
 | 
			
		||||
description = "Preview release with the newest features for the supporters."
 | 
			
		||||
icon = "thicc_logo_installer__ea_shadow.png"
 | 
			
		||||
requires_authorization = true
 | 
			
		||||
# puts a "new" ribbon the package select
 | 
			
		||||
is_new = true
 | 
			
		||||
    [packages.extended_description]
 | 
			
		||||
    no_action_description = "Thank you for your support!"
 | 
			
		||||
    # Displayed when the package has no authentication for the user
 | 
			
		||||
    need_authentication_description = "Click here to sign in with your yuzu account for Early Access"
 | 
			
		||||
    # Displayed when the package has an authentication, but the user has not linked their account
 | 
			
		||||
    need_link_description = "You are signed in, but you need to link your Patreon account! Click here for more details"
 | 
			
		||||
    # Displayed when the package has an authentication, but the user has not linked their account
 | 
			
		||||
    need_subscription_description = "You are signed in, but you need to link your Patreon account! Click here for more details"
 | 
			
		||||
    # Displayed when the package has an authentication, but the user has not linked their account
 | 
			
		||||
    need_reward_tier_description = "You are signed in, but are not backing an eligible reward tier! Click here for more details"
 | 
			
		||||
 | 
			
		||||
    [packages.source]
 | 
			
		||||
    name = "patreon"
 | 
			
		||||
    match = "^yuzu-windows-msvc-[0-9]*-[0-9a-f]*.tar.xz$"
 | 
			
		||||
        [packages.source.config]
 | 
			
		||||
        repo = "earlyaccess"
 | 
			
		||||
    [[packages.shortcuts]]
 | 
			
		||||
    name = "yuzu Early Access"
 | 
			
		||||
    relative_path = "yuzu-windows-msvc-early-access/yuzu.exe"
 | 
			
		||||
    description = "Launch yuzu Early Access"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[packages]]
 | 
			
		||||
name = "yuzu"
 | 
			
		||||
description = "Includes frequent updates to yuzu with all the latest reviewed and tested features."
 | 
			
		||||
| 
						 | 
				
			
			@ -27,28 +56,3 @@ default = true
 | 
			
		|||
    relative_path = "yuzu-windows-msvc/yuzu.exe"
 | 
			
		||||
    description = "Launch yuzu"
 | 
			
		||||
 | 
			
		||||
[[packages]]
 | 
			
		||||
name = "yuzu Early Access"
 | 
			
		||||
description = "Bonus preview release for project supporters. Thanks for your support!"
 | 
			
		||||
icon = "thicc_logo_installer__ea_shadow.png"
 | 
			
		||||
# Displayed when the package has no authentication for the user
 | 
			
		||||
need_authentication_description = "Click here to sign in with your yuzu account for Early Access"
 | 
			
		||||
# Displayed when the package has an authentication, but the user has not linked their account
 | 
			
		||||
need_link_description = "You are signed in, but you need to link your Patreon account! Click here for more details"
 | 
			
		||||
# Displayed when the package has an authentication, but the user has not linked their account
 | 
			
		||||
need_subscription_description = "You are signed in, but you need to link your Patreon account! Click here for more details"
 | 
			
		||||
# Displayed when the package has an authentication, but the user has not linked their account
 | 
			
		||||
need_reward_tier_description = "You are signed in, but are not backing an eligible reward tier! Click here for more details"
 | 
			
		||||
requires_authorization = true
 | 
			
		||||
# puts a "new" ribbon the package select
 | 
			
		||||
is_new = true
 | 
			
		||||
    [packages.source]
 | 
			
		||||
    name = "patreon"
 | 
			
		||||
    match = "^yuzu-windows-msvc-[0-9]*-[0-9a-f]*.tar.xz$"
 | 
			
		||||
        [packages.source.config]
 | 
			
		||||
        repo = "earlyaccess"
 | 
			
		||||
    [[packages.shortcuts]]
 | 
			
		||||
    name = "yuzu Early Access"
 | 
			
		||||
    relative_path = "yuzu-windows-msvc-early-access/yuzu.exe"
 | 
			
		||||
    description = "Launch yuzu Early Access"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,23 @@ pub struct PackageShortcut {
 | 
			
		|||
    pub name: String,
 | 
			
		||||
    pub relative_path: String,
 | 
			
		||||
    pub description: String,
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub has_desktop_shortcut: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Extra description for authentication and authorization state for a package
 | 
			
		||||
#[derive(Debug, Deserialize, Serialize, Clone)]
 | 
			
		||||
pub struct PackageExtendedDescription {
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub no_action_description: Option<String>,
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub need_authentication_description: Option<String>,
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub need_link_description: Option<String>,
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub need_subscription_description: Option<String>,
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub need_reward_tier_description: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Describes a overview of a individual package.
 | 
			
		||||
| 
						 | 
				
			
			@ -43,13 +60,7 @@ pub struct PackageDescription {
 | 
			
		|||
    #[serde(default)]
 | 
			
		||||
    pub is_new: Option<bool>,
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub need_authentication_description: Option<String>,
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub need_link_description: Option<String>,
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub need_subscription_description: Option<String>,
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub need_reward_tier_description: Option<String>,
 | 
			
		||||
    pub extended_description: Option<PackageExtendedDescription>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Configuration for validating the JWT token
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,18 +2,15 @@
 | 
			
		|||
//!
 | 
			
		||||
//! The /api/exit closes down the application.
 | 
			
		||||
 | 
			
		||||
use frontend::rest::services::default_future;
 | 
			
		||||
use frontend::rest::services::Future;
 | 
			
		||||
use frontend::rest::services::Request;
 | 
			
		||||
use frontend::rest::services::Response;
 | 
			
		||||
use frontend::rest::services::WebService;
 | 
			
		||||
use frontend::rest::services::Future as InternalFuture;
 | 
			
		||||
use frontend::rest::services::{default_future, Request, Response, WebService};
 | 
			
		||||
 | 
			
		||||
use hyper::header::ContentType;
 | 
			
		||||
use hyper::StatusCode;
 | 
			
		||||
 | 
			
		||||
use std::process::exit;
 | 
			
		||||
 | 
			
		||||
pub fn handle(service: &WebService, _req: Request) -> Future {
 | 
			
		||||
pub fn handle(service: &WebService, _req: Request) -> InternalFuture {
 | 
			
		||||
    match service.get_framework_write().shutdown() {
 | 
			
		||||
        Ok(_) => {
 | 
			
		||||
            exit(0);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,12 +28,17 @@ pub fn handle(service: &WebService, req: Request) -> Future {
 | 
			
		|||
 | 
			
		||||
        let mut to_install = Vec::new();
 | 
			
		||||
        let mut path: Option<String> = None;
 | 
			
		||||
        let mut install_desktop_shortcut= false;
 | 
			
		||||
 | 
			
		||||
        // Transform results into just an array of stuff to install
 | 
			
		||||
        for (key, value) in &results {
 | 
			
		||||
            if key == "path" {
 | 
			
		||||
                path = Some(value.to_owned());
 | 
			
		||||
                continue;
 | 
			
		||||
            } else if key == "installDesktopShortcut" {
 | 
			
		||||
                info!("Found installDesktopShortcut {:?}", value);
 | 
			
		||||
                install_desktop_shortcut = value == "true";
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if value == "true" {
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +60,7 @@ pub fn handle(service: &WebService, req: Request) -> Future {
 | 
			
		|||
                framework.set_install_dir(&path);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if let Err(v) = framework.install(to_install, &sender, new_install) {
 | 
			
		||||
            if let Err(v) = framework.install(to_install, &sender, new_install, install_desktop_shortcut) {
 | 
			
		||||
                error!("Install error occurred: {:?}", v);
 | 
			
		||||
                if let Err(v) = sender.send(InstallMessage::Error(v)) {
 | 
			
		||||
                    error!("Failed to send install error: {:?}", v);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -136,7 +136,7 @@ impl Service for WebService {
 | 
			
		|||
            (Method::Get, "/api/config") => config::handle(self, req),
 | 
			
		||||
            (Method::Get, "/api/dark-mode") => dark_mode::handle(self, req),
 | 
			
		||||
            (Method::Get, "/api/default-path") => default_path::handle(self, req),
 | 
			
		||||
            (Method::Get, "/api/exit") => exit::handle(self, req),
 | 
			
		||||
            (Method::Post, "/api/exit") => exit::handle(self, req),
 | 
			
		||||
            (Method::Get, "/api/packages") => packages::handle(self, req),
 | 
			
		||||
            (Method::Get, "/api/installation-status") => installation_status::handle(self, req),
 | 
			
		||||
            (Method::Post, "/api/check-auth") => authentication::handle(self, req),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -179,6 +179,7 @@ impl InstallerFramework {
 | 
			
		|||
        items: Vec<String>,
 | 
			
		||||
        messages: &Sender<InstallMessage>,
 | 
			
		||||
        fresh_install: bool,
 | 
			
		||||
        create_desktop_shortcuts: bool,
 | 
			
		||||
    ) -> Result<(), String> {
 | 
			
		||||
        info!(
 | 
			
		||||
            "Framework: Installing {:?} to {:?}",
 | 
			
		||||
| 
						 | 
				
			
			@ -207,6 +208,7 @@ impl InstallerFramework {
 | 
			
		|||
            items,
 | 
			
		||||
            uninstall_items,
 | 
			
		||||
            fresh_install,
 | 
			
		||||
            create_desktop_shortcuts,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let mut tree = DependencyTree::build(task);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -164,3 +164,15 @@ extern "C" HRESULT getSystemFolder(wchar_t *out_path)
 | 
			
		|||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern "C" HRESULT getDesktopFolder(wchar_t *out_path)
 | 
			
		||||
{
 | 
			
		||||
    PWSTR path = NULL;
 | 
			
		||||
    HRESULT result = SHGetKnownFolderPath(FOLDERID_Desktop, 0, NULL, &path);
 | 
			
		||||
    if (result == S_OK)
 | 
			
		||||
    {
 | 
			
		||||
        wcscpy_s(out_path, MAX_PATH + 1, path);
 | 
			
		||||
        CoTaskMemFree(path);
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ mod natives {
 | 
			
		|||
        HANDLE, PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE, PROCESS_VM_READ,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    use widestring::U16CString;
 | 
			
		||||
    use widestring::{U16CString, U16CStr};
 | 
			
		||||
 | 
			
		||||
    extern "C" {
 | 
			
		||||
        pub fn saveShortcut(
 | 
			
		||||
| 
						 | 
				
			
			@ -50,6 +50,28 @@ mod natives {
 | 
			
		|||
        ) -> ::std::os::raw::c_int;
 | 
			
		||||
 | 
			
		||||
        pub fn getSystemFolder(out_path: *mut ::std::os::raw::c_ushort) -> HRESULT;
 | 
			
		||||
 | 
			
		||||
        pub fn getDesktopFolder(out_path: *mut ::std::os::raw::c_ushort) -> HRESULT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Needed here for Windows interop
 | 
			
		||||
    #[allow(unsafe_code)]
 | 
			
		||||
    pub fn create_desktop_shortcut(
 | 
			
		||||
        name: &str,
 | 
			
		||||
        description: &str,
 | 
			
		||||
        target: &str,
 | 
			
		||||
        args: &str,
 | 
			
		||||
        working_dir: &str,
 | 
			
		||||
        exe_path: &str,
 | 
			
		||||
    ) -> Result<String, String> {
 | 
			
		||||
        let mut cmd_path = [0u16; MAX_PATH + 1];
 | 
			
		||||
        let result = unsafe { getDesktopFolder(cmd_path.as_mut_ptr()) };
 | 
			
		||||
        let source_path = format!(
 | 
			
		||||
            "{}\\{}.lnk",
 | 
			
		||||
            String::from_utf16_lossy(&cmd_path[..count_u16(&cmd_path)]).as_str(),
 | 
			
		||||
            name
 | 
			
		||||
        );
 | 
			
		||||
        create_shortcut_inner(source_path, name, description, target, args, working_dir, exe_path)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Needed here for Windows interop
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +89,20 @@ mod natives {
 | 
			
		|||
            env::var("APPDATA").log_expect("APPDATA is bad, apparently"),
 | 
			
		||||
            name
 | 
			
		||||
        );
 | 
			
		||||
        create_shortcut_inner(source_file, name, description, target, args, working_dir, exe_path)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Needed here for Windows interop
 | 
			
		||||
    #[allow(unsafe_code)]
 | 
			
		||||
    fn create_shortcut_inner(
 | 
			
		||||
        source_file: String,
 | 
			
		||||
        name: &str,
 | 
			
		||||
        description: &str,
 | 
			
		||||
        target: &str,
 | 
			
		||||
        args: &str,
 | 
			
		||||
        working_dir: &str,
 | 
			
		||||
        exe_path: &str,
 | 
			
		||||
    ) -> Result<String, String> {
 | 
			
		||||
 | 
			
		||||
        info!("Generating shortcut @ {:?}", source_file);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -103,6 +139,17 @@ mod natives {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn count_u16(u16str: &[u16]) -> usize {
 | 
			
		||||
        let mut pos = 0;
 | 
			
		||||
        for x in u16str.iter() {
 | 
			
		||||
            if *x == 0 {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            pos += 1;
 | 
			
		||||
        }
 | 
			
		||||
        pos
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Cleans up the installer
 | 
			
		||||
    pub fn burn_on_exit(app_name: &str) {
 | 
			
		||||
        let current_exe = env::current_exe().log_expect("Current executable could not be found");
 | 
			
		||||
| 
						 | 
				
			
			@ -132,20 +179,13 @@ mod natives {
 | 
			
		|||
        let spawn_result: i32 = unsafe {
 | 
			
		||||
            let mut cmd_path = [0u16; MAX_PATH + 1];
 | 
			
		||||
            let result = getSystemFolder(cmd_path.as_mut_ptr());
 | 
			
		||||
            let mut pos = 0;
 | 
			
		||||
            for x in cmd_path.iter() {
 | 
			
		||||
                if *x == 0 {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                pos += 1;
 | 
			
		||||
            }
 | 
			
		||||
            if result != winapi::shared::winerror::S_OK {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            spawnDetached(
 | 
			
		||||
                U16CString::from_str(
 | 
			
		||||
                    format!("{}\\cmd.exe", String::from_utf16_lossy(&cmd_path[..pos])).as_str(),
 | 
			
		||||
                    format!("{}\\cmd.exe", String::from_utf16_lossy(&cmd_path[..count_u16(&cmd_path)])).as_str(),
 | 
			
		||||
                )
 | 
			
		||||
                .log_expect("Unable to convert string to wchar_t")
 | 
			
		||||
                .as_ptr(),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ impl Task for CheckAuthorizationTask {
 | 
			
		|||
    ) -> Result<TaskParamType, String> {
 | 
			
		||||
        assert_eq!(input.len(), 1);
 | 
			
		||||
 | 
			
		||||
        let params = input.pop().log_expect("Should have input from resolver!");
 | 
			
		||||
        let params = input.pop().log_expect("Check Authorization Task should have input from resolver!");
 | 
			
		||||
        let (version, file) = match params {
 | 
			
		||||
            TaskParamType::File(v, f) => Ok((v, f)),
 | 
			
		||||
            _ => Err("Unexpected TaskParamType in CheckAuthorization: {:?}"),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ impl Task for DownloadPackageTask {
 | 
			
		|||
    ) -> Result<TaskParamType, String> {
 | 
			
		||||
        assert_eq!(input.len(), 1);
 | 
			
		||||
 | 
			
		||||
        let file = input.pop().log_expect("Should have input from resolver!");
 | 
			
		||||
        let file = input.pop().log_expect("Download Package Task should have input from resolver!");
 | 
			
		||||
        let (version, file, auth) = match file {
 | 
			
		||||
            TaskParamType::Authentication(v, f, auth) => (v, f, auth),
 | 
			
		||||
            _ => return Err("Unexpected param type to download package".to_string()),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@ use tasks::install_global_shortcut::InstallGlobalShortcutsTask;
 | 
			
		|||
use tasks::install_pkg::InstallPackageTask;
 | 
			
		||||
use tasks::save_executable::SaveExecutableTask;
 | 
			
		||||
use tasks::uninstall_pkg::UninstallPackageTask;
 | 
			
		||||
use tasks::launch_installed_on_exit::LaunchOnExitTask;
 | 
			
		||||
 | 
			
		||||
use tasks::Task;
 | 
			
		||||
use tasks::TaskDependency;
 | 
			
		||||
| 
						 | 
				
			
			@ -19,6 +20,7 @@ pub struct InstallTask {
 | 
			
		|||
    pub items: Vec<String>,
 | 
			
		||||
    pub uninstall_items: Vec<String>,
 | 
			
		||||
    pub fresh_install: bool,
 | 
			
		||||
    pub create_desktop_shortcuts: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Task for InstallTask {
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +62,7 @@ impl Task for InstallTask {
 | 
			
		|||
        for item in &self.items {
 | 
			
		||||
            elements.push(TaskDependency::build(
 | 
			
		||||
                TaskOrdering::Pre,
 | 
			
		||||
                Box::new(InstallPackageTask { name: item.clone() }),
 | 
			
		||||
                Box::new(InstallPackageTask { name: item.clone(), create_desktop_shortcuts: self.create_desktop_shortcuts }),
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -74,6 +76,11 @@ impl Task for InstallTask {
 | 
			
		|||
                TaskOrdering::Pre,
 | 
			
		||||
                Box::new(InstallGlobalShortcutsTask {}),
 | 
			
		||||
            ));
 | 
			
		||||
 | 
			
		||||
            elements.push(TaskDependency::build(
 | 
			
		||||
                TaskOrdering::Post,
 | 
			
		||||
                Box::new(LaunchOnExitTask {})
 | 
			
		||||
            ))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        elements
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										113
									
								
								src/tasks/install_desktop_shortcut.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/tasks/install_desktop_shortcut.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,113 @@
 | 
			
		|||
//! Generates shortcuts for a specified file.
 | 
			
		||||
 | 
			
		||||
use installer::InstallerFramework;
 | 
			
		||||
 | 
			
		||||
use tasks::Task;
 | 
			
		||||
use tasks::TaskDependency;
 | 
			
		||||
use tasks::TaskMessage;
 | 
			
		||||
use tasks::TaskParamType;
 | 
			
		||||
 | 
			
		||||
use config::PackageDescription;
 | 
			
		||||
 | 
			
		||||
use logging::LoggingErrors;
 | 
			
		||||
 | 
			
		||||
use native::create_desktop_shortcut;
 | 
			
		||||
 | 
			
		||||
pub struct InstallDesktopShortcutTask {
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub should_run: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Task for InstallDesktopShortcutTask {
 | 
			
		||||
    fn execute(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        _: Vec<TaskParamType>,
 | 
			
		||||
        context: &mut InstallerFramework,
 | 
			
		||||
        messenger: &dyn Fn(&TaskMessage),
 | 
			
		||||
    ) -> Result<TaskParamType, String> {
 | 
			
		||||
        if !self.should_run {
 | 
			
		||||
            return Ok(TaskParamType::GeneratedShortcuts(Vec::new()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        messenger(&TaskMessage::DisplayMessage(
 | 
			
		||||
            &format!("Generating desktop shortcuts for package {:?}...", self.name),
 | 
			
		||||
            0.0,
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        let path = context
 | 
			
		||||
            .install_path
 | 
			
		||||
            .as_ref()
 | 
			
		||||
            .log_expect("No install path specified");
 | 
			
		||||
 | 
			
		||||
        let starting_dir = path
 | 
			
		||||
            .to_str()
 | 
			
		||||
            .log_expect("Unable to build shortcut metadata (startingdir)");
 | 
			
		||||
 | 
			
		||||
        let mut installed_files = Vec::new();
 | 
			
		||||
 | 
			
		||||
        let mut metadata: Option<PackageDescription> = None;
 | 
			
		||||
        for description in &context
 | 
			
		||||
            .config
 | 
			
		||||
            .as_ref()
 | 
			
		||||
            .log_expect("Should have packages by now")
 | 
			
		||||
            .packages
 | 
			
		||||
            {
 | 
			
		||||
                if self.name == description.name {
 | 
			
		||||
                    metadata = Some(description.clone());
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        let package = match metadata {
 | 
			
		||||
            Some(v) => v,
 | 
			
		||||
            None => return Err(format!("Package {:?} could not be found.", self.name)),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Generate installer path
 | 
			
		||||
        let platform_extension = if cfg!(windows) {
 | 
			
		||||
            "maintenancetool.exe"
 | 
			
		||||
        } else {
 | 
			
		||||
            "maintenancetool"
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        for shortcut in package.shortcuts {
 | 
			
		||||
            let tool_path = path.join(platform_extension);
 | 
			
		||||
            let tool_path = tool_path
 | 
			
		||||
                .to_str()
 | 
			
		||||
                .log_expect("Unable to build shortcut metadata (tool)");
 | 
			
		||||
 | 
			
		||||
            let exe_path = path.join(shortcut.relative_path);
 | 
			
		||||
            let exe_path = exe_path
 | 
			
		||||
                .to_str()
 | 
			
		||||
                .log_expect("Unable to build shortcut metadata (exe)");
 | 
			
		||||
 | 
			
		||||
            installed_files.push(create_desktop_shortcut(
 | 
			
		||||
                &shortcut.name,
 | 
			
		||||
                &shortcut.description,
 | 
			
		||||
                tool_path,
 | 
			
		||||
                // TODO: Send by list
 | 
			
		||||
                &format!("--launcher \"{}\"", exe_path),
 | 
			
		||||
                &starting_dir,
 | 
			
		||||
                exe_path,
 | 
			
		||||
            )?);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Update the installed packages shortcuts information in the database
 | 
			
		||||
        let packages = &mut context.database.packages;
 | 
			
		||||
        for pack in packages {
 | 
			
		||||
            if pack.name == self.name {
 | 
			
		||||
                pack.shortcuts.append(&mut installed_files);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(TaskParamType::GeneratedShortcuts(installed_files))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn dependencies(&self) -> Vec<TaskDependency> {
 | 
			
		||||
        vec![]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn name(&self) -> String {
 | 
			
		||||
        format!("InstallDesktopShortcutTask (for {:?}, should_run = {:?})", self.name, self.should_run)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -24,9 +24,11 @@ use archives;
 | 
			
		|||
 | 
			
		||||
use std::fs::OpenOptions;
 | 
			
		||||
use std::path::Path;
 | 
			
		||||
use tasks::install_desktop_shortcut::InstallDesktopShortcutTask;
 | 
			
		||||
 | 
			
		||||
pub struct InstallPackageTask {
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub create_desktop_shortcuts: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Task for InstallPackageTask {
 | 
			
		||||
| 
						 | 
				
			
			@ -66,20 +68,15 @@ impl Task for InstallPackageTask {
 | 
			
		|||
            None => return Err(format!("Package {:?} could not be found.", self.name)),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Grab data from the shortcut generator
 | 
			
		||||
        let shortcuts = input.pop().log_expect("Should have input from resolver!");
 | 
			
		||||
        let shortcuts = match shortcuts {
 | 
			
		||||
            TaskParamType::GeneratedShortcuts(files) => files,
 | 
			
		||||
            // If the resolver returned early, we need to unwind
 | 
			
		||||
        // Ignore input from the uninstaller - no useful information passed
 | 
			
		||||
        // If a previous task Breaks, then just early exit
 | 
			
		||||
        match input.pop().log_expect("Install Package Task should have guaranteed output!") {
 | 
			
		||||
            TaskParamType::Break => return Ok(TaskParamType::None),
 | 
			
		||||
            _ => return Err("Unexpected shortcuts param type to install package".to_string()),
 | 
			
		||||
            _ => (),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Ignore input from the uninstaller - no useful information passed
 | 
			
		||||
        input.pop();
 | 
			
		||||
 | 
			
		||||
        // Grab data from the resolver
 | 
			
		||||
        let data = input.pop().log_expect("Should have input from resolver!");
 | 
			
		||||
        let data = input.pop().log_expect("Install Package Task should have input from resolver!");
 | 
			
		||||
        let (version, file, data) = match data {
 | 
			
		||||
            TaskParamType::FileContents(version, file, data) => (version, file, data),
 | 
			
		||||
            _ => return Err("Unexpected file contents param type to install package".to_string()),
 | 
			
		||||
| 
						 | 
				
			
			@ -170,7 +167,7 @@ impl Task for InstallPackageTask {
 | 
			
		|||
        context.database.packages.push(LocalInstallation {
 | 
			
		||||
            name: package.name.to_owned(),
 | 
			
		||||
            version,
 | 
			
		||||
            shortcuts,
 | 
			
		||||
            shortcuts: Vec::new(),
 | 
			
		||||
            files: installed_files,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -195,11 +192,18 @@ impl Task for InstallPackageTask {
 | 
			
		|||
                }),
 | 
			
		||||
            ),
 | 
			
		||||
            TaskDependency::build(
 | 
			
		||||
                TaskOrdering::Pre,
 | 
			
		||||
                TaskOrdering::Post,
 | 
			
		||||
                Box::new(InstallShortcutsTask {
 | 
			
		||||
                    name: self.name.clone(),
 | 
			
		||||
                }),
 | 
			
		||||
            ),
 | 
			
		||||
            TaskDependency::build(
 | 
			
		||||
                TaskOrdering::Post,
 | 
			
		||||
                Box::new(InstallDesktopShortcutTask {
 | 
			
		||||
                    name: self.name.clone(),
 | 
			
		||||
                    should_run: self.create_desktop_shortcuts
 | 
			
		||||
                }),
 | 
			
		||||
            ),
 | 
			
		||||
            TaskDependency::build(TaskOrdering::Post, Box::new(SaveDatabaseTask {})),
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -87,6 +87,14 @@ impl Task for InstallShortcutsTask {
 | 
			
		|||
            )?);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Update the installed packages shortcuts information in the database
 | 
			
		||||
        let packages = &mut context.database.packages;
 | 
			
		||||
        for pack in packages {
 | 
			
		||||
            if pack.name == self.name {
 | 
			
		||||
                pack.shortcuts.append(&mut installed_files);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(TaskParamType::GeneratedShortcuts(installed_files))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										76
									
								
								src/tasks/launch_installed_on_exit.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/tasks/launch_installed_on_exit.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
//! Configures lift to launch the new package on fresh install after its closed
 | 
			
		||||
//! If theres multiple launchable packages, then choose the first listed in config
 | 
			
		||||
//! If there are multiple shortcuts for the first package, then launch the first.
 | 
			
		||||
 | 
			
		||||
use installer::InstallerFramework;
 | 
			
		||||
 | 
			
		||||
use tasks::Task;
 | 
			
		||||
use tasks::TaskDependency;
 | 
			
		||||
use tasks::TaskMessage;
 | 
			
		||||
use tasks::TaskParamType;
 | 
			
		||||
 | 
			
		||||
use config::PackageDescription;
 | 
			
		||||
 | 
			
		||||
use logging::LoggingErrors;
 | 
			
		||||
 | 
			
		||||
use native::create_desktop_shortcut;
 | 
			
		||||
 | 
			
		||||
pub struct LaunchOnExitTask {}
 | 
			
		||||
 | 
			
		||||
impl Task for LaunchOnExitTask {
 | 
			
		||||
 | 
			
		||||
    fn execute(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        mut input: Vec<TaskParamType>,
 | 
			
		||||
        context: &mut InstallerFramework,
 | 
			
		||||
        messenger: &dyn Fn(&TaskMessage),
 | 
			
		||||
    ) -> Result<TaskParamType, String> {
 | 
			
		||||
        let pkg = &context.database.packages.first();
 | 
			
		||||
        if pkg.is_none() {
 | 
			
		||||
            return Ok(TaskParamType::None)
 | 
			
		||||
        }
 | 
			
		||||
        let pkg = pkg.unwrap();
 | 
			
		||||
 | 
			
		||||
        // look up the first shortcut for the first listed package in the database
 | 
			
		||||
        let path = context
 | 
			
		||||
            .install_path
 | 
			
		||||
            .as_ref()
 | 
			
		||||
            .log_expect("No install path specified");
 | 
			
		||||
 | 
			
		||||
        let mut metadata: Option<PackageDescription> = None;
 | 
			
		||||
        for description in &context
 | 
			
		||||
            .config
 | 
			
		||||
            .as_ref()
 | 
			
		||||
            .log_expect("Should have packages by now")
 | 
			
		||||
            .packages
 | 
			
		||||
            {
 | 
			
		||||
                if pkg.name == description.name {
 | 
			
		||||
                    metadata = Some(description.clone());
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        let package_desc = match metadata {
 | 
			
		||||
            Some(v) => v,
 | 
			
		||||
            // Package metadata is missing. Dunno what went wrong but we can skip this then
 | 
			
		||||
            None => return Ok(TaskParamType::None),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let shortcut = package_desc.shortcuts.first();
 | 
			
		||||
 | 
			
		||||
        // copy the path to the actual exe into launcher_path so it'll load it on exit
 | 
			
		||||
        context.launcher_path = shortcut.map(|s| {
 | 
			
		||||
            path.join(s.relative_path.clone()).to_str().map(|t| { t.to_string() }).unwrap()
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Ok(TaskParamType::None)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn dependencies(&self) -> Vec<TaskDependency> {
 | 
			
		||||
        vec![]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn name(&self) -> String {
 | 
			
		||||
        "LaunchOnExitTask".to_string()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -13,10 +13,12 @@ pub mod check_authorization;
 | 
			
		|||
pub mod download_pkg;
 | 
			
		||||
pub mod ensure_only_instance;
 | 
			
		||||
pub mod install;
 | 
			
		||||
pub mod install_desktop_shortcut;
 | 
			
		||||
pub mod install_dir;
 | 
			
		||||
pub mod install_global_shortcut;
 | 
			
		||||
pub mod install_pkg;
 | 
			
		||||
pub mod install_shortcuts;
 | 
			
		||||
pub mod launch_installed_on_exit;
 | 
			
		||||
pub mod resolver;
 | 
			
		||||
pub mod save_database;
 | 
			
		||||
pub mod save_executable;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -115,7 +115,8 @@ var app = new Vue({
 | 
			
		|||
                '\n\nPlease upload the log file (in ' + search_location + ') to ' +
 | 
			
		||||
                'the ' + app.attrs.name + ' team'
 | 
			
		||||
          }});
 | 
			
		||||
        }
 | 
			
		||||
        },
 | 
			
		||||
        {} // pass in nothing to cause `ajax` to post instead of get
 | 
			
		||||
      )
 | 
			
		||||
    },
 | 
			
		||||
    check_authentication: function (success, error) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ export default new Router({
 | 
			
		|||
      component: SelectPackages
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: '/install/:kind',
 | 
			
		||||
      path: '/install/:kind/:desktop_shortcut',
 | 
			
		||||
      name: 'install',
 | 
			
		||||
      component: InstallPackages
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,12 +46,12 @@ export default {
 | 
			
		|||
      was_install: !this.$route.params.uninstall,
 | 
			
		||||
      was_update: this.$route.params.update,
 | 
			
		||||
      was_migrate: this.$route.params.migrate,
 | 
			
		||||
      has_installed: this.$route.params.packages_installed > 0
 | 
			
		||||
      has_installed: this.$route.params.packages_installed > 0,
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    exit: function () {
 | 
			
		||||
      this.$root.exit()
 | 
			
		||||
      this.$root.exit();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,7 +31,7 @@ export default {
 | 
			
		|||
 | 
			
		||||
        // Update the updater if needed
 | 
			
		||||
        if (that.$root.config.new_tool) {
 | 
			
		||||
          this.$router.push('/install/updater')
 | 
			
		||||
          this.$router.push('/install/updater/false')
 | 
			
		||||
          return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +70,7 @@ export default {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        this.$router.replace({ name: 'migrate',
 | 
			
		||||
          params: { next: app.metadata.is_launcher ? '/install/regular' : '/modify' } })
 | 
			
		||||
          params: { next: app.metadata.is_launcher ? '/install/regular/false' : '/modify' } })
 | 
			
		||||
      } else {
 | 
			
		||||
        for (var x = 0; x < app.config.packages.length; x++) {
 | 
			
		||||
          app.config.packages[x].installed = false
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@
 | 
			
		|||
    <b-message title="An error occurred" type="is-danger" :closable="false">
 | 
			
		||||
      <div id="error_msg" v-html="msg"></div>
 | 
			
		||||
    </b-message>
 | 
			
		||||
    <div class="field is-grouped is-right-floating" v-bind:class="{ 'is-bottom-floating': !$root.$data.metadata.is_launcher, 'is-top-floating': $root.$data.metadata.is_launcher }">
 | 
			
		||||
    <div class="field is-grouped is-right-floating is-bottom-floating">
 | 
			
		||||
      <p class="control">
 | 
			
		||||
        <a class="button is-primary is-medium" v-if="remaining && !$root.$data.metadata.is_launcher" v-on:click="go_back">Back</a>
 | 
			
		||||
        <a class="button is-primary is-medium" v-if="$root.$data.metadata.is_launcher" v-on:click="exit">Exit</a>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@ export default {
 | 
			
		|||
      is_uninstall: false,
 | 
			
		||||
      is_updater_update: false,
 | 
			
		||||
      is_update: false,
 | 
			
		||||
      install_desktop_shortcut: false,
 | 
			
		||||
      failed_with_error: false,
 | 
			
		||||
      authorization_required: false,
 | 
			
		||||
      packages_installed: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +34,9 @@ export default {
 | 
			
		|||
    this.is_uninstall = this.$route.params.kind === 'uninstall'
 | 
			
		||||
    this.is_updater_update = this.$route.params.kind === 'updater'
 | 
			
		||||
    this.is_update = this.$route.params.kind === 'update'
 | 
			
		||||
    this.install_desktop_shortcut = this.$route.params.desktop_shortcut === 'true'
 | 
			
		||||
    console.log('Installer kind: ' + this.$route.params.kind)
 | 
			
		||||
    console.log('Installing desktop shortcut: ' + this.$route.params.desktop_shortcut)
 | 
			
		||||
    this.install()
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
| 
						 | 
				
			
			@ -53,6 +56,7 @@ export default {
 | 
			
		|||
      }
 | 
			
		||||
 | 
			
		||||
      results['path'] = app.install_location
 | 
			
		||||
      results['installDesktopShortcut'] = that.install_desktop_shortcut
 | 
			
		||||
 | 
			
		||||
      var targetUrl = '/api/start-install'
 | 
			
		||||
      if (this.is_uninstall) {
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +92,7 @@ export default {
 | 
			
		|||
        if (that.is_updater_update) {
 | 
			
		||||
          // Continue with what we were doing
 | 
			
		||||
          if (app.metadata.is_launcher) {
 | 
			
		||||
            that.$router.replace('/install/regular')
 | 
			
		||||
            that.$router.replace('/install/regular/' + that.install_desktop_shortcut.toString())
 | 
			
		||||
          } else {
 | 
			
		||||
            if (app.metadata.preexisting_install) {
 | 
			
		||||
              that.$router.replace('/modify')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,7 +43,7 @@ export default {
 | 
			
		|||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    update: function () {
 | 
			
		||||
      this.$router.push('/install/update')
 | 
			
		||||
      this.$router.push('/install/update/false')
 | 
			
		||||
    },
 | 
			
		||||
    modify_packages: function () {
 | 
			
		||||
      this.$router.push('/packages')
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +55,7 @@ export default {
 | 
			
		|||
      this.show_uninstall = false
 | 
			
		||||
    },
 | 
			
		||||
    uninstall: function () {
 | 
			
		||||
      this.$router.push('/install/uninstall')
 | 
			
		||||
      this.$router.push('/install/uninstall/false')
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,160 +1,151 @@
 | 
			
		|||
<template>
 | 
			
		||||
    <div class="column has-padding">
 | 
			
		||||
          <h4 class="subtitle">Select which packages you want to install:</h4>
 | 
			
		||||
 | 
			
		||||
          <!-- Build options -->
 | 
			
		||||
          <div class="tile is-ancestor">
 | 
			
		||||
              <div class="tile is-parent" v-for="Lpackage in $root.$data.config.packages" :key="Lpackage.name" :index="Lpackage.name">
 | 
			
		||||
                  <div class="tile is-child">
 | 
			
		||||
                      <div class="box clickable-box" v-if="!Lpackage.requires_authorization || (Lpackage.requires_authorization && $root.$data.has_reward_tier)" v-on:click.capture.stop="Lpackage.default = !Lpackage.default">
 | 
			
		||||
                          <div class="ribbon" v-if="Lpackage.is_new"><span>New!</span></div>
 | 
			
		||||
                          <label class="checkbox">
 | 
			
		||||
                              <b-checkbox v-model="Lpackage.default">
 | 
			
		||||
                                  {{ Lpackage.name }}
 | 
			
		||||
                              </b-checkbox>
 | 
			
		||||
                              <span v-if="Lpackage.installed"><i>(installed)</i></span>
 | 
			
		||||
                          </label>
 | 
			
		||||
                          <div>
 | 
			
		||||
                              <img class="package-icon" :src="`${publicPath + Lpackage.icon}`"/>
 | 
			
		||||
                              <p class="package-description">
 | 
			
		||||
                                  {{ Lpackage.description }}
 | 
			
		||||
                              </p>
 | 
			
		||||
                          </div>
 | 
			
		||||
                      </div>
 | 
			
		||||
                      <div class="box clickable-box" v-else-if="Lpackage.requires_authorization && !$root.$data.is_authenticated" v-on:click="show_authentication">
 | 
			
		||||
                          <div class="ribbon" v-if="Lpackage.is_new"><span>New!</span></div>
 | 
			
		||||
                          <b-checkbox>
 | 
			
		||||
                              {{ Lpackage.name }}
 | 
			
		||||
                          </b-checkbox>
 | 
			
		||||
                          <div>
 | 
			
		||||
                              <img class="package-icon" :src="`${publicPath + Lpackage.icon}`"/>
 | 
			
		||||
                              <p class="package-description">
 | 
			
		||||
                                  {{ Lpackage.description }}
 | 
			
		||||
                              </p>
 | 
			
		||||
                          </div>
 | 
			
		||||
                      </div>
 | 
			
		||||
                      <div class="box clickable-box" v-else-if="Lpackage.requires_authorization && !$root.$data.is_linked" v-on:click="show_authorization">
 | 
			
		||||
                          <div class="ribbon" v-if="Lpackage.is_new"><span>New!</span></div>
 | 
			
		||||
                          <b-checkbox>
 | 
			
		||||
                              {{ Lpackage.name }}
 | 
			
		||||
                          </b-checkbox>
 | 
			
		||||
                          <div>
 | 
			
		||||
                              <img class="package-icon" :src="`${publicPath + Lpackage.icon}`"/>
 | 
			
		||||
                              <p class="package-description">
 | 
			
		||||
                                  {{ Lpackage.description }}
 | 
			
		||||
                              </p>
 | 
			
		||||
                          </div>
 | 
			
		||||
                      </div>
 | 
			
		||||
                      <div class="box clickable-box" v-else-if="Lpackage.requires_authorization && !$root.$data.is_subscribed" v-on:click="show_authorization">
 | 
			
		||||
                          <div class="ribbon" v-if="Lpackage.is_new"><span>New!</span></div>
 | 
			
		||||
                          <b-checkbox>
 | 
			
		||||
                              {{ Lpackage.name }}
 | 
			
		||||
                          </b-checkbox>
 | 
			
		||||
                          <div>
 | 
			
		||||
                              <img class="package-icon" :src="`${publicPath + Lpackage.icon}`"/>
 | 
			
		||||
                              <p class="package-description">
 | 
			
		||||
                                  {{ Lpackage.description }}
 | 
			
		||||
                              </p>
 | 
			
		||||
                          </div>
 | 
			
		||||
                      </div>
 | 
			
		||||
                      <div class="box clickable-box" v-else v-on:click="show_authorization">
 | 
			
		||||
                          <div class="ribbon" v-if="Lpackage.is_new"><span>New!</span></div>
 | 
			
		||||
                          <b-checkbox>
 | 
			
		||||
                              {{ Lpackage.name }}
 | 
			
		||||
                          </b-checkbox>
 | 
			
		||||
                          <div>
 | 
			
		||||
                              <img class="package-icon" :src="`${publicPath + Lpackage.icon}`"/>
 | 
			
		||||
                              <p class="package-description">
 | 
			
		||||
                                  {{ Lpackage.description }}
 | 
			
		||||
                              </p>
 | 
			
		||||
                          </div>
 | 
			
		||||
                      </div>
 | 
			
		||||
                  </div>
 | 
			
		||||
              </div>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div class="subtitle is-6" v-if="!$root.$data.metadata.preexisting_install && advanced">Install Location</div>
 | 
			
		||||
          <div class="field has-addons" v-if="!$root.$data.metadata.preexisting_install && advanced">
 | 
			
		||||
              <div class="control is-expanded">
 | 
			
		||||
                  <input class="input" type="text" v-model="$root.$data.install_location"
 | 
			
		||||
                         placeholder="Enter a install path here">
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="control">
 | 
			
		||||
                  <a class="button is-dark" v-on:click="select_file">
 | 
			
		||||
                      Select
 | 
			
		||||
                  </a>
 | 
			
		||||
              </div>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div class="is-right-floating is-bottom-floating">
 | 
			
		||||
              <div class="field is-grouped">
 | 
			
		||||
                  <p class="control">
 | 
			
		||||
                      <a class="button is-medium" v-if="!$root.$data.config.hide_advanced && !$root.$data.metadata.preexisting_install && !advanced"
 | 
			
		||||
                         v-on:click="advanced = true">Advanced...</a>
 | 
			
		||||
                  </p>
 | 
			
		||||
                  <p class="control">
 | 
			
		||||
                      <a class="button is-dark is-medium" v-if="!$root.$data.metadata.preexisting_install"
 | 
			
		||||
                         v-on:click="install">Install</a>
 | 
			
		||||
                  </p>
 | 
			
		||||
                  <p class="control">
 | 
			
		||||
                      <a class="button is-dark is-medium" v-if="$root.$data.metadata.preexisting_install"
 | 
			
		||||
                         v-on:click="install">Modify</a>
 | 
			
		||||
                  </p>
 | 
			
		||||
              </div>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div class="field is-grouped is-left-floating is-bottom-floating">
 | 
			
		||||
              <p class="control">
 | 
			
		||||
                  <a class="button is-medium" v-if="$root.$data.metadata.preexisting_install"
 | 
			
		||||
                     v-on:click="go_back">Back</a>
 | 
			
		||||
              </p>
 | 
			
		||||
  <div class="column has-padding">
 | 
			
		||||
    <!-- Build options -->
 | 
			
		||||
    <div class="tile is-ancestor">
 | 
			
		||||
      <div class="tile is-parent is-vertical">
 | 
			
		||||
        <div class="tile is-child is-12 box clickable-box" v-for="Lpackage in $root.$data.config.packages" :key="Lpackage.name" :index="Lpackage.name" v-on:click.capture.stop="clicked_box(Lpackage)">
 | 
			
		||||
          <div class="ribbon" v-if="Lpackage.is_new"><span>New!</span></div>
 | 
			
		||||
          <label class="checkbox">
 | 
			
		||||
            <b-checkbox v-model="Lpackage.default">
 | 
			
		||||
              <span v-if="!Lpackage.installed">Install</span> {{ Lpackage.name }}
 | 
			
		||||
            </b-checkbox>
 | 
			
		||||
            <span v-if="Lpackage.installed"><i>(installed)</i></span>
 | 
			
		||||
          </label>
 | 
			
		||||
          <div>
 | 
			
		||||
            <img class="package-icon" :src="`${publicPath + Lpackage.icon}`"/>
 | 
			
		||||
            <p class="package-description">
 | 
			
		||||
              {{ Lpackage.description }}
 | 
			
		||||
            </p>
 | 
			
		||||
            <p class="package-description">
 | 
			
		||||
              {{ get_extended_description(Lpackage) }}
 | 
			
		||||
            </p>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="tile is-child is-6 box clickable-box" v-if="!$root.$data.metadata.preexisting_install"  v-on:click.capture.stop="installDesktopShortcut = !installDesktopShortcut">
 | 
			
		||||
          <h4>Install Options</h4>
 | 
			
		||||
          <b-checkbox v-model="installDesktopShortcut">
 | 
			
		||||
            Create Desktop Shortcut
 | 
			
		||||
          </b-checkbox>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="subtitle is-6" v-if="!$root.$data.metadata.preexisting_install && advanced">
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <div class="subtitle is-6" v-if="!$root.$data.metadata.preexisting_install && advanced">Install Location</div>
 | 
			
		||||
    <div class="field has-addons" v-if="!$root.$data.metadata.preexisting_install && advanced">
 | 
			
		||||
      <div class="control is-expanded">
 | 
			
		||||
        <input class="input" type="text" v-model="$root.$data.install_location"
 | 
			
		||||
               placeholder="Enter a install path here">
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="control">
 | 
			
		||||
        <a class="button is-dark" v-on:click="select_file">
 | 
			
		||||
          Select
 | 
			
		||||
        </a>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="is-right-floating is-bottom-floating">
 | 
			
		||||
      <div class="field is-grouped">
 | 
			
		||||
        <p class="control">
 | 
			
		||||
          <a class="button is-medium" v-if="!$root.$data.config.hide_advanced && !$root.$data.metadata.preexisting_install && !advanced"
 | 
			
		||||
             v-on:click="advanced = true">Advanced...</a>
 | 
			
		||||
        </p>
 | 
			
		||||
        <p class="control">
 | 
			
		||||
          <a class="button is-dark is-medium" v-if="!$root.$data.metadata.preexisting_install"
 | 
			
		||||
             v-on:click="install">Install</a>
 | 
			
		||||
        </p>
 | 
			
		||||
        <p class="control">
 | 
			
		||||
          <a class="button is-dark is-medium" v-if="$root.$data.metadata.preexisting_install"
 | 
			
		||||
             v-on:click="install">Modify</a>
 | 
			
		||||
        </p>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="field is-grouped is-left-floating is-bottom-floating">
 | 
			
		||||
      <p class="control">
 | 
			
		||||
        <a class="button is-medium" v-if="$root.$data.metadata.preexisting_install"
 | 
			
		||||
           v-on:click="go_back">Back</a>
 | 
			
		||||
      </p>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'SelectPackages',
 | 
			
		||||
  created: function() {
 | 
			
		||||
    if (this.$root.$data.has_reward_tier) {
 | 
			
		||||
      for (let package_index = 0; package_index < this.$root.config.packages.length; package_index++) {
 | 
			
		||||
        let current_package = this.$root.config.packages[package_index];
 | 
			
		||||
        // If they are authorized, make the packages that require authorization default
 | 
			
		||||
        if (current_package.requires_authorization) {
 | 
			
		||||
          current_package.default = true;
 | 
			
		||||
        } else {
 | 
			
		||||
          // And unselect any other packages
 | 
			
		||||
          current_package.default = false;
 | 
			
		||||
  export default {
 | 
			
		||||
    name: 'SelectPackages',
 | 
			
		||||
    created: function() {
 | 
			
		||||
      // If they are authorized, make the packages that require authorization default
 | 
			
		||||
      // and also deselect any packages that don't use authorization
 | 
			
		||||
      if (this.$root.$data.has_reward_tier) {
 | 
			
		||||
        for (let package_index = 0; package_index < this.$root.config.packages.length; package_index++) {
 | 
			
		||||
          let current_package = this.$root.config.packages[package_index];
 | 
			
		||||
          current_package.default = current_package.requires_authorization;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    data: function () {
 | 
			
		||||
      return {
 | 
			
		||||
        publicPath: process.env.BASE_URL,
 | 
			
		||||
        advanced: false,
 | 
			
		||||
        installDesktopShortcut: true
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      select_file: function () {
 | 
			
		||||
        window.external.invoke(JSON.stringify({
 | 
			
		||||
          SelectInstallDir: {
 | 
			
		||||
            callback_name: 'selectFileCallback'
 | 
			
		||||
          }
 | 
			
		||||
        }))
 | 
			
		||||
      },
 | 
			
		||||
      install: function () {
 | 
			
		||||
        this.$router.push('/install/regular/' + this.installDesktopShortcut.toString())
 | 
			
		||||
      },
 | 
			
		||||
      go_back: function () {
 | 
			
		||||
        this.$router.go(-1)
 | 
			
		||||
      },
 | 
			
		||||
      show_authentication: function () {
 | 
			
		||||
        this.$router.push('/authentication')
 | 
			
		||||
      },
 | 
			
		||||
      show_authorization: function () {
 | 
			
		||||
        this.$router.push('/authentication')
 | 
			
		||||
      },
 | 
			
		||||
      installable: function (pkg) {
 | 
			
		||||
        return !pkg.requires_authorization || (pkg.requires_authorization && this.$root.$data.has_reward_tier);
 | 
			
		||||
      },
 | 
			
		||||
      clicked_box: function (pkg) {
 | 
			
		||||
        if (this.installable(pkg)) {
 | 
			
		||||
          pkg.default = !pkg.default;
 | 
			
		||||
        } else if (pkg.requires_authorization && !this.$root.$data.is_authenticated) {
 | 
			
		||||
          this.show_authentication()
 | 
			
		||||
        } else if (pkg.requires_authorization && !this.$root.$data.is_linked) {
 | 
			
		||||
          this.show_authorization()
 | 
			
		||||
        } else if (pkg.requires_authorization && !this.$root.$data.is_subscribed) {
 | 
			
		||||
          this.show_authorization()
 | 
			
		||||
        } else { // need_reward_tier_description
 | 
			
		||||
          this.show_authorization()
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      get_extended_description: function(pkg) {
 | 
			
		||||
        if (!pkg.extended_description) {
 | 
			
		||||
          return "";
 | 
			
		||||
        }
 | 
			
		||||
        if (this.installable(pkg)) {
 | 
			
		||||
          return pkg.extended_description.no_action_description;
 | 
			
		||||
        } else if (pkg.requires_authorization && !this.$root.$data.is_authenticated) {
 | 
			
		||||
          return pkg.extended_description.need_authentication_description;
 | 
			
		||||
        } else if (pkg.requires_authorization && !this.$root.$data.is_linked) {
 | 
			
		||||
          return pkg.extended_description.need_link_description;
 | 
			
		||||
        } else if (pkg.requires_authorization && !this.$root.$data.is_subscribed) {
 | 
			
		||||
          return pkg.extended_description.need_subscription_description;
 | 
			
		||||
        } else { // need_reward_tier_description
 | 
			
		||||
          return pkg.extended_description.need_reward_tier_description;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      publicPath: process.env.BASE_URL,
 | 
			
		||||
      advanced: false
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    select_file: function () {
 | 
			
		||||
      window.external.invoke(JSON.stringify({
 | 
			
		||||
        SelectInstallDir: {
 | 
			
		||||
          callback_name: 'selectFileCallback'
 | 
			
		||||
        }
 | 
			
		||||
      }))
 | 
			
		||||
    },
 | 
			
		||||
    install: function () {
 | 
			
		||||
      this.$router.push('/install/regular')
 | 
			
		||||
    },
 | 
			
		||||
    go_back: function () {
 | 
			
		||||
      this.$router.go(-1)
 | 
			
		||||
    },
 | 
			
		||||
    show_authentication: function () {
 | 
			
		||||
        this.$router.push('/authentication')
 | 
			
		||||
    },
 | 
			
		||||
    show_authorization: function () {
 | 
			
		||||
        this.$router.push('/authentication')
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue