Skip to content

Commit 99baacc

Browse files
yaira2tsvietOK
andauthored
Auto-Detect and List Windows Terminal (#903)
* Auto-Detect and List Windows Terminal Co-authored-by: Vladyslav <[email protected]>
1 parent 3b41d8e commit 99baacc

File tree

8 files changed

+116
-62
lines changed

8 files changed

+116
-62
lines changed

Files/Assets/terminal/terminal.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"version": 1,
3+
"defaultTerminalId": 1,
34
"terminals": [
45
{
56
"id": 1,

Files/DataModels/TerminalFileModel.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,27 @@
1-
using System.Collections.Generic;
1+
using Newtonsoft.Json;
2+
using System.Collections.Generic;
3+
using System.Linq;
24

35
namespace Files.DataModels
46
{
5-
internal class TerminalFileModel
7+
public class TerminalFileModel
68
{
9+
[JsonProperty("version")]
710
public int Version { get; set; }
811

9-
public List<TerminalModel> Terminals { get; set; }
12+
[JsonProperty("defaultTerminalId")]
13+
public int DefaultTerminalId { get; set; }
14+
15+
[JsonProperty("terminals")]
16+
public List<TerminalModel> Terminals { get; set; } = new List<TerminalModel>();
17+
18+
public TerminalModel GetDefaultTerminal()
19+
{
20+
if (DefaultTerminalId != 0)
21+
{
22+
return Terminals.Single(x => x.Id == DefaultTerminalId);
23+
}
24+
return Terminals.First();
25+
}
1026
}
1127
}

Files/DataModels/TerminalModel.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
1-
namespace Files.DataModels
1+
using Newtonsoft.Json;
2+
using System.ComponentModel.DataAnnotations;
3+
4+
namespace Files.DataModels
25
{
36
public class TerminalModel
47
{
8+
[JsonProperty("id")]
59
public int Id { get; set; }
610

11+
[JsonProperty("name")]
712
public string Name { get; set; }
813

14+
[JsonProperty("path")]
915
public string Path { get; set; }
1016

11-
public string icon { get; set; }
17+
[JsonProperty("arguments")]
18+
public string Arguments { get; set; }
1219

13-
public string arguments { get; set; }
20+
[JsonProperty("icon")]
21+
public string Icon { get; set; }
1422
}
1523
}

Files/Interacts/Interaction.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,19 +127,13 @@ public async void OpenPathInNewWindow(string path)
127127

128128
public async void OpenDirectoryInTerminal(object sender, RoutedEventArgs e)
129129
{
130-
var localSettings = ApplicationData.Current.LocalSettings;
131-
132-
var terminalId = 1;
133-
134-
if (localSettings.Values["terminal_id"] != null) terminalId = (int)localSettings.Values["terminal_id"];
135-
136-
var terminal = App.AppSettings.Terminals.Single(p => p.Id == terminalId);
130+
var terminal = App.AppSettings.TerminalsModel.GetDefaultTerminal();
137131

138132
if (App.Connection != null)
139133
{
140134
var value = new ValueSet();
141135
value.Add("Application", terminal.Path);
142-
value.Add("Arguments", String.Format(terminal.arguments, CurrentInstance.ViewModel.WorkingDirectory));
136+
value.Add("Arguments", string.Format(terminal.Arguments, CurrentInstance.ViewModel.WorkingDirectory));
143137
await App.Connection.SendMessageAsync(value);
144138
}
145139
}

Files/UserControls/NavigationToolbar/ModernNavigationToolbar.xaml.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -248,17 +248,15 @@ public async void CheckPathInput(ItemViewModel instance, string CurrentInput)
248248
catch (Exception ex) // Not a file or not accessible
249249
{
250250
// Launch terminal application if possible
251-
var localSettings = ApplicationData.Current.LocalSettings;
252-
253-
foreach (var item in App.AppSettings.Terminals)
251+
foreach (var item in App.AppSettings.TerminalsModel.Terminals)
254252
{
255253
if (item.Path.Equals(CurrentInput, StringComparison.OrdinalIgnoreCase) || item.Path.Equals(CurrentInput + ".exe", StringComparison.OrdinalIgnoreCase))
256254
{
257255
if (App.Connection != null)
258256
{
259257
var value = new ValueSet();
260258
value.Add("Application", item.Path);
261-
value.Add("Arguments", String.Format(item.arguments, App.CurrentInstance.ViewModel.WorkingDirectory));
259+
value.Add("Arguments", String.Format(item.Arguments, App.CurrentInstance.ViewModel.WorkingDirectory));
262260
await App.Connection.SendMessageAsync(value);
263261
}
264262
return;

Files/View Models/SettingsViewModel.cs

Lines changed: 69 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
using System.Linq;
1515
using System.Reflection;
1616
using System.Runtime.CompilerServices;
17+
using System.Threading.Tasks;
1718
using Windows.Foundation.Collections;
1819
using Windows.Storage;
20+
using Windows.System;
1921

2022
namespace Files.View_Models
2123
{
@@ -275,66 +277,95 @@ public TimeStyle DisplayedTimeStyle
275277
}
276278
}
277279

280+
private static readonly Uri dummyUri = new Uri("mailto:[email protected]");
281+
282+
/// <summary>
283+
/// Check if target <paramref name="packageName"/> is installed on this device.
284+
/// </summary>
285+
/// <param name="packageName">Package name in format: "949FFEAB.Email.cz_refxrrjvvv3cw"</param>
286+
/// <returns>True is app is installed on this device, false otherwise.</returns>
287+
public static async Task<bool> IsAppInstalledAsync(string packageName)
288+
{
289+
try
290+
{
291+
bool appInstalled;
292+
LaunchQuerySupportStatus result = await Launcher.QueryUriSupportAsync(dummyUri, LaunchQuerySupportType.Uri, packageName);
293+
switch (result)
294+
{
295+
case LaunchQuerySupportStatus.Available:
296+
case LaunchQuerySupportStatus.NotSupported:
297+
appInstalled = true;
298+
break;
299+
//case LaunchQuerySupportStatus.AppNotInstalled:
300+
//case LaunchQuerySupportStatus.AppUnavailable:
301+
//case LaunchQuerySupportStatus.Unknown:
302+
default:
303+
appInstalled = false;
304+
break;
305+
}
306+
307+
Debug.WriteLine($"App {packageName}, query status: {result}, installed: {appInstalled}");
308+
return appInstalled;
309+
}
310+
catch (Exception ex)
311+
{
312+
Debug.WriteLine($"Error checking if app {packageName} is installed. Error: {ex}");
313+
return false;
314+
}
315+
}
316+
317+
public TerminalFileModel TerminalsModel { get; set; }
318+
319+
public StorageFile TerminalsModelFile;
320+
278321
private async void LoadTerminalApps()
279322
{
280323
var localFolder = ApplicationData.Current.LocalFolder;
281324
var localSettingsFolder = await localFolder.CreateFolderAsync("settings", CreationCollisionOption.OpenIfExists);
282-
StorageFile file;
283325
try
284326
{
285-
file = await localSettingsFolder.GetFileAsync("terminal.json");
327+
TerminalsModelFile = await localSettingsFolder.GetFileAsync("terminal.json");
286328
}
287329
catch (FileNotFoundException)
288330
{
289331
var defaultFile = StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/terminal/terminal.json"));
290332

291-
file = await localSettingsFolder.CreateFileAsync("terminal.json");
292-
await FileIO.WriteBufferAsync(file, await FileIO.ReadBufferAsync(await defaultFile));
333+
TerminalsModelFile = await localSettingsFolder.CreateFileAsync("terminal.json");
334+
await FileIO.WriteBufferAsync(TerminalsModelFile, await FileIO.ReadBufferAsync(await defaultFile));
293335
}
294336

295-
var content = await FileIO.ReadTextAsync(file);
296-
TerminalFileModel terminalsFileModel = null;
337+
var content = await FileIO.ReadTextAsync(TerminalsModelFile);
338+
297339
try
298340
{
299-
terminalsFileModel = JsonConvert.DeserializeObject<TerminalFileModel>(content);
341+
TerminalsModel = JsonConvert.DeserializeObject<TerminalFileModel>(content);
300342
}
301343
catch (JsonSerializationException)
302344
{
303345
var defaultFile = StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/terminal/terminal.json"));
304346

305-
file = await localSettingsFolder.CreateFileAsync("terminal.json", CreationCollisionOption.ReplaceExisting);
306-
await FileIO.WriteBufferAsync(file, await FileIO.ReadBufferAsync(await defaultFile));
307-
var defaultContent = await FileIO.ReadTextAsync(file);
308-
terminalsFileModel = JsonConvert.DeserializeObject<TerminalFileModel>(defaultContent);
347+
TerminalsModelFile = await localSettingsFolder.CreateFileAsync("terminal.json", CreationCollisionOption.ReplaceExisting);
348+
await FileIO.WriteBufferAsync(TerminalsModelFile, await FileIO.ReadBufferAsync(await defaultFile));
349+
var defaultContent = await FileIO.ReadTextAsync(TerminalsModelFile);
350+
TerminalsModel = JsonConvert.DeserializeObject<TerminalFileModel>(defaultContent);
309351
}
310352

311-
// Ensure Windows Terminal is not already in List
312-
//if (terminalsFileModel.Terminals.FirstOrDefault(x => x.Path.Equals("wt.exe", StringComparison.OrdinalIgnoreCase)) == null)
313-
//{
314-
// PackageManager packageManager = new PackageManager();
315-
// var terminalPackage = packageManager.FindPackagesForUser(string.Empty, "Microsoft.WindowsTerminal_8wekyb3d8bbwe");
316-
// if (terminalPackage != null)
317-
// {
318-
// terminalsFileModel.Terminals.Add(new TerminalModel()
319-
// {
320-
// Id = terminalsFileModel.Terminals.Count + 1,
321-
// Name = "Windows Terminal",
322-
// Path = "wt.exe",
323-
// arguments = "-d {0}",
324-
// icon = ""
325-
// });
326-
// await FileIO.WriteTextAsync(file, JsonConvert.SerializeObject(terminalsFileModel, Formatting.Indented));
327-
// }
328-
//}
329-
Terminals = terminalsFileModel?.Terminals ?? new List<TerminalModel>();
330-
}
331-
332-
private IList<TerminalModel> _Terminals = null;
333-
334-
public IList<TerminalModel> Terminals
335-
{
336-
get => _Terminals;
337-
set => Set(ref _Terminals, value);
353+
//Ensure Windows Terminal is not already in List
354+
if (TerminalsModel.Terminals.FirstOrDefault(x => x.Path.Equals("wt.exe", StringComparison.OrdinalIgnoreCase)) == null)
355+
{
356+
if (await IsAppInstalledAsync("Microsoft.WindowsTerminal_8wekyb3d8bbwe"))
357+
{
358+
TerminalsModel.Terminals.Add(new TerminalModel()
359+
{
360+
Id = TerminalsModel.Terminals.Count + 1,
361+
Name = "Windows Terminal",
362+
Path = "wt.exe",
363+
Arguments = "-d {0}",
364+
Icon = ""
365+
});
366+
await FileIO.WriteTextAsync(TerminalsModelFile, JsonConvert.SerializeObject(TerminalsModel, Formatting.Indented));
367+
}
368+
}
338369
}
339370

340371
private FormFactorMode _FormFactor = FormFactorMode.Regular;

Files/Views/SettingsPages/Preferences.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@
132132
MinWidth="120"
133133
MaxWidth="185"
134134
HorizontalAlignment="Stretch"
135-
ItemsSource="{x:Bind local2:App.AppSettings.Terminals}"
135+
ItemsSource="{x:Bind local2:App.AppSettings.TerminalsModel.Terminals}"
136136
SelectionChanged="TerminalApp_SelectionChanged">
137137
<ComboBox.ItemTemplate>
138138
<DataTemplate x:DataType="datamodels:TerminalModel">

Files/Views/SettingsPages/Preferences.xaml.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Files.DataModels;
2+
using Newtonsoft.Json;
23
using System;
34
using System.Linq;
45
using Windows.Storage;
@@ -32,10 +33,7 @@ protected override void OnNavigatedTo(NavigationEventArgs e)
3233
{
3334
base.OnNavigatedTo(e);
3435

35-
var terminalId = 1;
36-
if (localSettings.Values["terminal_id"] != null) terminalId = (int)localSettings.Values["terminal_id"];
37-
38-
TerminalApplicationsComboBox.SelectedItem = App.AppSettings.Terminals.Single(p => p.Id == terminalId);
36+
TerminalApplicationsComboBox.SelectedItem = App.AppSettings.TerminalsModel.GetDefaultTerminal();
3937
}
4038

4139
private void EditTerminalApplications_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
@@ -54,7 +52,15 @@ private void TerminalApp_SelectionChanged(object sender, SelectionChangedEventAr
5452

5553
var selectedTerminal = (TerminalModel)comboBox.SelectedItem;
5654

57-
localSettings.Values["terminal_id"] = selectedTerminal.Id;
55+
App.AppSettings.TerminalsModel.DefaultTerminalId = selectedTerminal.Id;
56+
57+
SaveTerminalSettings();
58+
}
59+
60+
private async void SaveTerminalSettings()
61+
{
62+
await FileIO.WriteTextAsync(App.AppSettings.TerminalsModelFile,
63+
JsonConvert.SerializeObject(App.AppSettings.TerminalsModel, Formatting.Indented));
5864
}
5965

6066
private void OneDrivePin_Toggled(object sender, Windows.UI.Xaml.RoutedEventArgs e)

0 commit comments

Comments
 (0)