Editor/Launcher/HotCodeInstallUi.cs
using Sandbox;
using Editor;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
/// <summary>
/// The confirmations and messages around <see cref="HotCodeInstaller"/>, shared by the launcher and the editor.
/// </summary>
public static class HotCodeInstallUi
{
/// <summary>
/// Where this copy of HotCode lives: the loaded project whose .sbproj is HotCode's.
/// </summary>
public static string SourceRoot
{
get
{
var loaded = EditorUtility.Projects.GetAll()
.Where( p => p.ConfigFilePath is not null && HotCodeInstaller.IsHotCode( p.ConfigFilePath ) )
.Select( p => Path.GetDirectoryName( p.ConfigFilePath ) )
.FirstOrDefault();
if ( loaded is not null ) return loaded;
// Libraries might not be in the project list: look in the open project's Libraries folder
var current = Project.Current?.GetRootPath();
return string.IsNullOrEmpty( current ) ? null : HotCodeInstaller.FindInstalled( current );
}
}
public enum State
{
/// <summary>Not a project HotCode can go in (a solution, or HotCode's own source).</summary>
NotApplicable,
NotInstalled,
Installed
}
public static State StateOf( HotCodeEntry entry )
{
if ( entry.Kind != HotCodeEntryKind.Project ) return State.NotApplicable;
var source = SourceRoot;
if ( source is not null && (ProjectFiles.IsUnder( entry.Directory, source ) || ProjectFiles.IsUnder( source, entry.Directory )) )
return State.NotApplicable;
try
{
return HotCodeInstaller.FindInstalled( entry.Directory ) is null ? State.NotInstalled : State.Installed;
}
catch ( Exception e ) when ( e is IOException or UnauthorizedAccessException )
{
return State.NotApplicable;
}
}
/// <summary>
/// Adds the install/update/remove options for a project to a menu.
/// </summary>
public static void AddMenuOptions( Menu menu, HotCodeEntry entry, Action changed )
{
switch ( StateOf( entry ) )
{
case State.NotInstalled:
menu.AddOption( "Add HotCode to This Project", HotCodeLogo.IconName, () => AskInstall( entry, changed ) );
break;
case State.Installed:
menu.AddOption( "Update HotCode in This Project", "system_update_alt", () => AskInstall( entry, changed ) );
menu.AddOption( "Remove HotCode from This Project", "remove_circle_outline", () => AskUninstall( entry, changed ) );
break;
}
}
public static void AskInstall( HotCodeEntry entry, Action changed = null )
{
var source = SourceRoot;
if ( source is null )
{
Show( "Add HotCode", "Couldn't find HotCode's own files. Open HotCode's project (or one that has it) in s&box first." );
return;
}
var updating = StateOf( entry ) == State.Installed;
var question = updating
? $"Update the copy of HotCode in '{entry.Title}' to this version?\n\nThe old copy goes to the Recycle Bin."
: $"Add HotCode to '{entry.Title}'?\n\nThis copies HotCode into its Libraries folder, the same place the Library Manager puts libraries. Next time you open that project in s&box, HotCode will be there.";
Dialog.AskConfirm( () =>
{
try
{
var folder = HotCodeInstaller.Install( source, entry.Directory, ProjectFiles.Delete );
Log.Info( $"[HotCode] {(updating ? "Updated" : "Added")} HotCode in {folder}" );
Show( updating ? "HotCode Updated" : "HotCode Added",
$"HotCode is now in '{entry.Title}'.\n\n{folder}\n\nOpen (or reopen) that project in s&box to use it." );
changed?.Invoke();
}
catch ( Exception e ) when ( e is InvalidOperationException or IOException or UnauthorizedAccessException )
{
Show( "Couldn't Add HotCode", e.Message );
}
}, question, updating ? "Update HotCode" : "Add HotCode", updating ? "Update" : "Add", "Cancel" );
}
public static void AskUninstall( HotCodeEntry entry, Action changed = null )
{
var source = SourceRoot ?? "";
Dialog.AskConfirm( () =>
{
try
{
if ( HotCodeInstaller.Uninstall( source, entry.Directory, ProjectFiles.Delete ) )
Log.Info( $"[HotCode] Removed HotCode from {entry.Directory}" );
changed?.Invoke();
}
catch ( Exception e ) when ( e is InvalidOperationException or IOException or UnauthorizedAccessException )
{
Show( "Couldn't Remove HotCode", e.Message );
}
}, $"Remove HotCode from '{entry.Title}'?\n\nIts copy goes to the Recycle Bin.", "Remove HotCode", "Remove", "Cancel" );
}
private static void Show( string title, string message ) =>
new PopupWindow( title, message, "OK", new Dictionary<string, Action>() ).Show();
}