Skip to content

Commit

Permalink
Merge #4103 Install from .ckan file option for ConsoleUI
Browse files Browse the repository at this point in the history
  • Loading branch information
HebaruSan committed Jun 6, 2024
2 parents ea40db1 + 27dffe6 commit 0c35797
Show file tree
Hide file tree
Showing 11 changed files with 124 additions and 39 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ All notable changes to this project will be documented in this file.
- [Multiple] Treat mods with missing files as upgradeable/reinstallable (#4067 by: HebaruSan)
- [ConsoleUI] Conflicting recommendations check for ConsoleUI (#4085 by: HebaruSan)
- [Build] Linux: Improve desktop entries (#4092 by: mmvanheusden; reviewed: HebaruSan)
- [ConsoleUI] Install from .ckan file option for ConsoleUI (#4103 by: HebaruSan)

### Bugfixes

Expand Down
14 changes: 1 addition & 13 deletions Cmdline/Action/Upgrade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ private void UpgradeModules(GameInstanceManager manager,
.ToHashSet();
// The modules we'll have after upgrading as aggressively as possible
var limiters = identsAndVersions.Select(req => CkanModule.FromIDandVersion(registry, req, crit)
?? DefaultIfThrows(
?? Utilities.DefaultIfThrows(
() => registry.LatestAvailable(req, crit))
?? registry.GetInstalledVersion(req))
.Concat(heldIdents.Select(ident => registry.GetInstalledVersion(ident)))
Expand Down Expand Up @@ -254,18 +254,6 @@ private void UpgradeModules(GameInstanceManager manager,
m => identsAndVersions.Add(m.identifier));
}

public static T DefaultIfThrows<T>(Func<T> func)
{
try
{
return func();
}
catch
{
return default;
}
}

private static string UpToFirst(string orig, char toFind)
=> UpTo(orig, orig.IndexOf(toFind));

Expand Down
1 change: 1 addition & 0 deletions ConsoleUI/DownloadImportDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public static void ImportDownloads(ConsoleTheme theme, GameInstance gameInst, Re
Properties.Resources.ImportSelectTitle,
FindDownloadsPath(gameInst),
"*.zip",
Properties.Resources.ImportSelectHeader,
Properties.Resources.ImportSelectHeader
);
HashSet<FileInfo> files = cfmsd.Run(theme);
Expand Down
50 changes: 50 additions & 0 deletions ConsoleUI/InstallFromCkanDialog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.IO;

using CKAN.ConsoleUI.Toolkit;
using System.Linq;

namespace CKAN.ConsoleUI {

/// <summary>
/// A popup to let the user import manually downloaded zip files into the mod cache.
/// </summary>
public static class InstallFromCkanDialog {

/// <summary>
/// Let the user choose some zip files, then import them to the mod cache.
/// </summary>
/// <param name="theme">The visual theme to use to draw the dialog</param>
/// <param name="gameInst">Game instance to import into</param>
public static CkanModule[] ChooseCkanFiles(ConsoleTheme theme,
GameInstance gameInst)
{
var cfmsd = new ConsoleFileMultiSelectDialog(
Properties.Resources.CkanFileSelectTitle,
FindDownloadsPath(gameInst),
"*.ckan",
Properties.Resources.CkanFileSelectHeader,
Properties.Resources.CkanFileSelectHeader);
return cfmsd.Run(theme)
.Select(f => CkanModule.FromFile(f.FullName))
.ToArray();
}

private static readonly string[] downloadPaths = new string[] {
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads"),
Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
};

private static string FindDownloadsPath(GameInstance gameInst)
{
foreach (string p in downloadPaths) {
if (!string.IsNullOrEmpty(p) && Directory.Exists(p)) {
return p;
}
}
return gameInst.GameDir();
}

}

}
15 changes: 8 additions & 7 deletions ConsoleUI/InstallScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,14 @@ public override void Run(ConsoleTheme theme, Action<ConsoleTheme> process = null
NetAsyncModulesDownloader dl = new NetAsyncModulesDownloader(this, manager.Cache);
if (plan.Install.Count > 0) {
var iList = plan.Install
.Select(m => registry.LatestAvailable(m.identifier,
manager.CurrentInstance.VersionCriteria(),
null,
registry.InstalledModules
.Select(im => im.Module)
.ToArray(),
plan.Install)
.Select(m => Utilities.DefaultIfThrows(() =>
registry.LatestAvailable(m.identifier,
manager.CurrentInstance.VersionCriteria(),
null,
registry.InstalledModules
.Select(im => im.Module)
.ToArray(),
plan.Install))
?? m)
.ToArray();
inst.InstallList(iList, resolvOpts, regMgr, ref possibleConfigOnlyDirs, dl);
Expand Down
32 changes: 28 additions & 4 deletions ConsoleUI/ModListScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,9 @@ public ModListScreen(GameInstanceManager mgr, RepositoryDataManager repoData, Re
new ConsoleMenuOption(Properties.Resources.ModListExportMenu, "",
Properties.Resources.ModListExportMenuTip,
true, ExportInstalled),
new ConsoleMenuOption(Properties.Resources.ModListInstallFromCkanMenu, "",
Properties.Resources.ModListInstallFromCkanMenuTip,
true, InstallFromCkan),
null,
new ConsoleMenuOption(Properties.Resources.ModListInstanceSettingsMenu, "",
Properties.Resources.ModListInstanceSettingsMenuTip,
Expand Down Expand Up @@ -597,10 +600,7 @@ private List<CkanModule> GetAllMods(ConsoleTheme theme, bool force = false)
var crit = manager.CurrentInstance.VersionCriteria();
allMods = new List<CkanModule>(registry.CompatibleModules(crit));
foreach (InstalledModule im in registry.InstalledModules) {
CkanModule m = null;
try {
m = registry.LatestAvailable(im.identifier, crit);
} catch (ModuleNotFoundKraken) { }
var m = Utilities.DefaultIfThrows(() => registry.LatestAvailable(im.identifier, crit));
if (m == null) {
// Add unavailable installed mods to the list
allMods.Add(im.Module);
Expand Down Expand Up @@ -629,6 +629,30 @@ private bool ExportInstalled(ConsoleTheme theme)
return true;
}

private bool InstallFromCkan(ConsoleTheme theme)
{
var modules = InstallFromCkanDialog.ChooseCkanFiles(theme, manager.CurrentInstance);
if (modules.Length > 0) {
var crit = manager.CurrentInstance.VersionCriteria();
var installed = regMgr.registry.InstalledModules.Select(inst => inst.Module).ToList();
var cp = new ChangePlan();
cp.Install.UnionWith(
modules.Concat(
modules.Where(m => m.IsMetapackage && m.depends != null)
.SelectMany(m => m.depends.Where(rel => !rel.MatchesAny(installed, null, null))
.Select(rel =>
// If there's a compatible match, return it
// Metapackages aren't intending to prompt users to choose providing mods
rel.ExactMatch(regMgr.registry, crit, installed, modules)
// Otherwise look for incompatible
?? rel.ExactMatch(regMgr.registry, null, installed, modules))
.Where(mod => mod != null))));
LaunchSubScreen(theme, new InstallScreen(manager, repoData, cp, debug));
RefreshList(theme);
}
return true;
}

private bool Help(ConsoleTheme theme)
{
ModListHelpDialog hd = new ModListHelpDialog();
Expand Down
7 changes: 6 additions & 1 deletion ConsoleUI/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@
<data name="Details" xml:space="preserve"><value>Details</value></data>
<data name="Up" xml:space="preserve"><value>Up</value></data>
<data name="Down" xml:space="preserve"><value>Down</value></data>
<data name="FileSelectDirectory" xml:space="preserve"><value>Directory</value></data>
<data name="FileSelectDirectory" xml:space="preserve"><value>Directory:</value></data>
<data name="FileSelectCountFooter" xml:space="preserve"><value>{0} selected, {1}</value></data>
<data name="FileSelectNameHeader" xml:space="preserve"><value>Name</value></data>
<data name="FileSelectSizeHeader" xml:space="preserve"><value>Size</value></data>
Expand Down Expand Up @@ -341,6 +341,11 @@ If you uninstall it, CKAN will not be able to re-install it.</value></data>
<data name="ModListImportMenuTip" xml:space="preserve"><value>Select manually downloaded mods to import into CKAN</value></data>
<data name="ModListExportMenu" xml:space="preserve"><value>Export installed...</value></data>
<data name="ModListExportMenuTip" xml:space="preserve"><value>Save your mod list</value></data>
<data name="ModListInstallFromCkanMenu" xml:space="preserve"><value>Install from .ckan file...</value></data>
<data name="ModListInstallFromCkanMenuTip" xml:space="preserve"><value>Install modpacks or custom modules</value></data>
<data name="ModListInstallFromCkanFailed" xml:space="preserve"><value>Install from .ckan file failed!</value></data>
<data name="CkanFileSelectTitle" xml:space="preserve"><value>Choose .ckan Files to Install</value></data>
<data name="CkanFileSelectHeader" xml:space="preserve"><value>Install</value></data>
<data name="ModListInstanceSettingsMenu" xml:space="preserve"><value>Game instance settings...</value></data>
<data name="ModListInstanceSettingsMenuTip" xml:space="preserve"><value>Configure the current game instance</value></data>
<data name="ModListSelectInstanceMenu" xml:space="preserve"><value>Select game instance...</value></data>
Expand Down
27 changes: 15 additions & 12 deletions ConsoleUI/Toolkit/ConsoleFileMultiSelectDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ public class ConsoleFileMultiSelectDialog : ConsoleDialog {
/// <param name="startPath">Path of directory to start in</param>
/// <param name="filPat">Glob-style wildcard string for matching files to show</param>
/// <param name="toggleHeader">Header for the column with checkmarks for selected files</param>
public ConsoleFileMultiSelectDialog(string title, string startPath, string filPat, string toggleHeader)
/// <param name="acceptTip">Description of the F9 action to accept selections</param>
public ConsoleFileMultiSelectDialog(string title,
string startPath,
string filPat,
string toggleHeader,
string acceptTip)
: base()
{
CenterHeader = () => title;
Expand All @@ -40,7 +45,7 @@ public ConsoleFileMultiSelectDialog(string title, string startPath, string filPa
));

pathField = new ConsoleField(
left + 2 + labelW, top + 2, right - 2,
left + 2 + labelW + 1, top + 2, right - 2,
curDir.FullName
);
pathField.OnChange += pathFieldChanged;
Expand Down Expand Up @@ -128,10 +133,8 @@ public ConsoleFileMultiSelectDialog(string title, string startPath, string filPa
return true;
});

AddTip("F9", Properties.Resources.FileSelectImport, () => chosenFiles.Count > 0);
AddBinding(Keys.F9, (object sender, ConsoleTheme theme) => {
return false;
});
AddTip("F9", acceptTip, () => chosenFiles.Count > 0);
AddBinding(Keys.F9, (object sender, ConsoleTheme theme) => false);
}

private bool selectRow()
Expand All @@ -141,7 +144,7 @@ private bool selectRow()
{
curDir = di;
pathField.Value = curDir.FullName;
fileList.SetData(getFileList());
fileList.SetData(getFileList(), true);
}
} else {
if (fileList.Selection is FileInfo fi)
Expand Down Expand Up @@ -300,11 +303,11 @@ private int compareNames(FileSystemInfo a, FileSystemInfo b)

private static readonly string chosen = Symbols.checkmark;

private const int idealW = 76;
private int labelW => Properties.Resources.FileSelectDirectory.Length;
private const int hPad = 2;
private const int top = 2;
private const int bottom = -2;
private const int idealW = 76;
private static int labelW => Properties.Resources.FileSelectDirectory.Length;
private const int hPad = 2;
private const int top = 2;
private const int bottom = -2;
}

}
2 changes: 1 addition & 1 deletion ConsoleUI/Toolkit/ConsoleListBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public override void Draw(ConsoleTheme theme, bool focused)
topRow = selectedRow - h + 2;
}

var remainingWidth = contentR - l + 1
var remainingWidth = contentR - l - 1
- columns.Select(col => col.Width ?? 0)
.Sum()
- (padding.Length * (columns.Count - 1));
Expand Down
2 changes: 1 addition & 1 deletion Core/Types/RelationshipDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public override CkanModule ExactMatch(IRegistryQuerier registry,
GameVersionCriteria crit,
ICollection<CkanModule> installed = null,
ICollection<CkanModule> toInstall = null)
=> registry.LatestAvailable(name, crit, this, installed, toInstall);
=> Utilities.DefaultIfThrows(() => registry.LatestAvailable(name, crit, this, installed, toInstall));

public override bool Equals(RelationshipDescriptor other)
=> Equals(other as ModuleRelationshipDescriptor);
Expand Down
12 changes: 12 additions & 0 deletions Core/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ public static class Utilities
"nl-NL",
};

public static T DefaultIfThrows<T>(Func<T> func)
{
try
{
return func();
}
catch
{
return default;
}
}

/// <summary>
/// Copies a directory and optionally its subdirectories as a transaction.
/// </summary>
Expand Down

0 comments on commit 0c35797

Please sign in to comment.