dev for workspaces

This commit is contained in:
kaitao-ms
2025-11-28 15:00:04 +08:00
parent aaf2f3e210
commit e4f8ab1193
42 changed files with 1788 additions and 506 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,8 @@
using System.Threading; // Copyright (c) Microsoft Corporation
using System.Threading.Tasks; // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Common.UI;
namespace PowerToys.ModuleContracts; namespace PowerToys.ModuleContracts;
@@ -9,7 +12,7 @@ namespace PowerToys.ModuleContracts;
public interface IModuleService public interface IModuleService
{ {
/// <summary> /// <summary>
/// Module identifier (e.g., Workspaces, Awake). /// Gets module identifier (e.g., Workspaces, Awake).
/// </summary> /// </summary>
string Key { get; } string Key { get; }
@@ -19,13 +22,26 @@ public interface IModuleService
} }
/// <summary> /// <summary>
/// Workspaces-specific operations. /// Helper base to reduce duplication for simple modules.
/// </summary> /// </summary>
public interface IWorkspaceService : IModuleService public abstract class ModuleServiceBase : IModuleService
{ {
Task<OperationResult> LaunchWorkspaceAsync(string workspaceId, CancellationToken cancellationToken = default); public abstract string Key { get; }
Task<OperationResult> LaunchEditorAsync(CancellationToken cancellationToken = default); protected abstract SettingsDeepLink.SettingsWindow SettingsWindow { get; }
Task<OperationResult> SnapshotAsync(string? targetPath = null, CancellationToken cancellationToken = default); public abstract Task<OperationResult> LaunchAsync(CancellationToken cancellationToken = default);
public virtual Task<OperationResult> OpenSettingsAsync(CancellationToken cancellationToken = default)
{
try
{
SettingsDeepLink.OpenSettings(SettingsWindow);
return Task.FromResult(OperationResult.Ok());
}
catch (Exception ex)
{
return Task.FromResult(OperationResult.Fail($"Failed to open settings for {Key}: {ex.Message}"));
}
}
} }

View File

@@ -1,3 +1,7 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace PowerToys.ModuleContracts; namespace PowerToys.ModuleContracts;
/// <summary> /// <summary>
@@ -13,9 +17,14 @@ public readonly record struct OperationResult(bool Success, string? Error = null
/// <summary> /// <summary>
/// Result type with a payload. /// Result type with a payload.
/// </summary> /// </summary>
public readonly record struct OperationResult<T>(bool Success, T? Value, string? Error = null) public readonly record struct OperationResult<T>(bool Success, T? Value, string? Error = null);
{
public static OperationResult<T> Ok(T value) => new(true, value, null);
public static OperationResult<T> Fail(string error) => new(false, default, error); /// <summary>
/// Factory helpers for creating operation results.
/// </summary>
public static class OperationResults
{
public static OperationResult<T> Ok<T>(T value) => new(true, value, null);
public static OperationResult<T> Fail<T>(string error) => new(false, default, error);
} }

View File

@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well --> <!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\Common.Dotnet.CsWinRT.props" /> <Import Project="..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup> <PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
@@ -8,4 +9,8 @@
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath> <AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Common.UI\Common.UI.csproj" />
</ItemGroup>
</Project> </Project>

View File

@@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using PowerToys.ModuleContracts;
using WorkspacesCsharpLibrary.Data;
namespace Workspaces.ModuleServices;
/// <summary>
/// Workspaces-specific operations.
/// </summary>
public interface IWorkspaceService : IModuleService
{
Task<OperationResult> LaunchWorkspaceAsync(string workspaceId, CancellationToken cancellationToken = default);
Task<OperationResult> LaunchEditorAsync(CancellationToken cancellationToken = default);
Task<OperationResult> SnapshotAsync(string? targetPath = null, CancellationToken cancellationToken = default);
[RequiresUnreferencedCode("Workspace deserialization uses reflection-based JSON serializer.")]
[RequiresDynamicCode("Workspace deserialization uses reflection-based JSON serializer.")]
Task<OperationResult<IReadOnlyList<ProjectWrapper>>> GetWorkspacesAsync(CancellationToken cancellationToken = default);
}

View File

@@ -3,21 +3,27 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Diagnostics; using System.Diagnostics;
using System.Threading; using System.Diagnostics.CodeAnalysis;
using PowerToys.ModuleContracts; using Common.UI;
using ManagedCommon;
using PowerToys.Interop; using PowerToys.Interop;
using static Common.UI.SettingsDeepLink; using PowerToys.ModuleContracts;
using WorkspacesCsharpLibrary.Data;
namespace Microsoft.CmdPal.Ext.PowerToys.Services; namespace Workspaces.ModuleServices;
/// <summary> /// <summary>
/// Implementation of workspace actions that can be reused by thin command adapters. /// Implementation of workspace actions for reuse across hosts.
/// </summary> /// </summary>
internal sealed class WorkspaceService : IWorkspaceService public sealed class WorkspaceService : ModuleServiceBase, IWorkspaceService
{ {
public string Key => SettingsWindow.Workspaces.ToString(); public static WorkspaceService Instance { get; } = new();
public Task<OperationResult> LaunchAsync(CancellationToken cancellationToken = default) public override string Key => SettingsDeepLink.SettingsWindow.Workspaces.ToString();
protected override SettingsDeepLink.SettingsWindow SettingsWindow => SettingsDeepLink.SettingsWindow.Workspaces;
public override Task<OperationResult> LaunchAsync(CancellationToken cancellationToken = default)
{ {
// Treat launch as invoking the Workspaces editor. // Treat launch as invoking the Workspaces editor.
return LaunchEditorAsync(cancellationToken); return LaunchEditorAsync(cancellationToken);
@@ -68,27 +74,25 @@ internal sealed class WorkspaceService : IWorkspaceService
} }
} }
public Task<OperationResult> OpenSettingsAsync(CancellationToken cancellationToken = default)
{
try
{
var entry = new Classes.PowerToysModuleEntry
{
Module = SettingsWindow.Workspaces,
};
entry.NavigateToSettingsPage();
return Task.FromResult(OperationResult.Ok());
}
catch (Exception ex)
{
return Task.FromResult(OperationResult.Fail($"Failed to open Workspaces settings: {ex.Message}"));
}
}
public Task<OperationResult> SnapshotAsync(string? targetPath = null, CancellationToken cancellationToken = default) public Task<OperationResult> SnapshotAsync(string? targetPath = null, CancellationToken cancellationToken = default)
{ {
// Snapshot orchestration is not yet exposed via events; provide a clear failure for now. // Snapshot orchestration is not yet exposed via events; provide a clear failure for now.
return Task.FromResult(OperationResult.Fail("Snapshot is not implemented for Workspaces.")); return Task.FromResult(OperationResult.Fail("Snapshot is not implemented for Workspaces."));
} }
[RequiresUnreferencedCode("Workspace deserialization uses reflection-based JSON serializer.")]
[RequiresDynamicCode("Workspace deserialization uses reflection-based JSON serializer.")]
public Task<OperationResult<IReadOnlyList<ProjectWrapper>>> GetWorkspacesAsync(CancellationToken cancellationToken = default)
{
try
{
var items = WorkspacesStorage.Load();
return Task.FromResult(OperationResults.Ok<IReadOnlyList<ProjectWrapper>>(items));
}
catch (Exception ex)
{
return Task.FromResult(OperationResults.Fail<IReadOnlyList<ProjectWrapper>>($"Failed to read workspaces: {ex.Message}"));
}
}
} }

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" />
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
<ProjectReference Include="..\..\..\common\PowerToys.ModuleContracts\PowerToys.ModuleContracts.csproj" />
<ProjectReference Include="..\WorkspacesCsharpLibrary\WorkspacesCsharpLibrary.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace WorkspacesCsharpLibrary.Data;
public struct ApplicationWrapper
{
public struct WindowPositionWrapper
{
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
}
public string Id { get; set; }
public string Application { get; set; }
public string ApplicationPath { get; set; }
public string Title { get; set; }
public string PackageFullName { get; set; }
public string AppUserModelId { get; set; }
public string PwaAppId { get; set; }
public string CommandLineArguments { get; set; }
public bool IsElevated { get; set; }
public bool CanLaunchElevated { get; set; }
public bool Minimized { get; set; }
public bool Maximized { get; set; }
public WindowPositionWrapper Position { get; set; }
public int Monitor { get; set; }
public string Version { get; set; }
}

View File

@@ -2,13 +2,12 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
namespace WorkspacesEditor.Data namespace WorkspacesCsharpLibrary.Data;
public enum InvokePoint
{ {
/* sync with workspaces-common */ EditorButton = 0,
public enum InvokePoint Shortcut,
{ LaunchAndEdit,
EditorButton = 0, CommandPaletteExtension,
Shortcut,
LaunchAndEdit,
}
} }

View File

@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace WorkspacesCsharpLibrary.Data;
public struct MonitorConfigurationWrapper
{
public struct MonitorRectWrapper
{
public int Top { get; set; }
public int Left { get; set; }
public int Width { get; set; }
public int Height { get; set; }
}
public string Id { get; set; }
public string InstanceId { get; set; }
public int MonitorNumber { get; set; }
public int Dpi { get; set; }
public MonitorRectWrapper MonitorRectDpiAware { get; set; }
public MonitorRectWrapper MonitorRectDpiUnaware { get; set; }
}

View File

@@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using WorkspacesCsharpLibrary.Data;
namespace WorkspacesCsharpLibrary.Data;
public class ProjectData : WorkspacesEditorData<ProjectWrapper>
{
}

View File

@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
namespace WorkspacesCsharpLibrary.Data;
public struct ProjectWrapper
{
public string Id { get; set; }
public string Name { get; set; }
public long CreationTime { get; set; }
public long LastLaunchedTime { get; set; }
public bool IsShortcutNeeded { get; set; }
public bool MoveExistingWindows { get; set; }
public List<MonitorConfigurationWrapper> MonitorConfiguration { get; set; }
public List<ApplicationWrapper> Applications { get; set; }
}

View File

@@ -2,9 +2,10 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using WorkspacesEditor.Utils; using WorkspacesCsharpLibrary.Data;
using WorkspacesCsharpLibrary.Utils;
namespace WorkspacesEditor.Data namespace WorkspacesCsharpLibrary.Data
{ {
public class TempProjectData : ProjectData public class TempProjectData : ProjectData
{ {

View File

@@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using WorkspacesCsharpLibrary.Utils;
using static WorkspacesCsharpLibrary.Data.WorkspacesData;
namespace WorkspacesCsharpLibrary.Data;
public class WorkspacesData : WorkspacesEditorData<WorkspacesListWrapper>
{
public string File => FolderUtils.DataFolder() + "\\workspaces.json";
public struct WorkspacesListWrapper
{
public List<ProjectWrapper> Workspaces { get; set; }
}
public enum OrderBy
{
LastViewed = 0,
Created = 1,
Name = 2,
Unknown = 3,
}
}

View File

@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using WorkspacesCsharpLibrary.Utils;
namespace WorkspacesCsharpLibrary.Data;
/// <summary>
/// Shared JSON serializer helper for Workspaces payloads.
/// </summary>
public class WorkspacesEditorData<T>
{
[RequiresUnreferencedCode("JSON serialization uses reflection-based serializer.")]
[RequiresDynamicCode("JSON serialization uses reflection-based serializer.")]
public T Read(string file)
{
IOUtils ioUtils = new();
string data = ioUtils.ReadFile(file);
return JsonSerializer.Deserialize<T>(data, WorkspacesJsonOptions.EditorOptions)!;
}
[RequiresUnreferencedCode("JSON serialization uses reflection-based serializer.")]
[RequiresDynamicCode("JSON serialization uses reflection-based serializer.")]
public string Serialize(T data)
{
return JsonSerializer.Serialize(data, WorkspacesJsonOptions.EditorOptions);
}
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json;
using WorkspacesCsharpLibrary.Utils;
namespace WorkspacesCsharpLibrary.Data;
internal static class WorkspacesJsonOptions
{
internal static readonly JsonSerializerOptions EditorOptions = new()
{
PropertyNamingPolicy = new DashCaseNamingPolicy(),
WriteIndented = true,
};
}

View File

@@ -0,0 +1,96 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text.Json;
using WorkspacesCsharpLibrary.Data;
namespace WorkspacesCsharpLibrary.Data;
/// <summary>
/// Lightweight reader for persisted workspaces.
/// </summary>
public static class WorkspacesStorage
{
private static readonly JsonSerializerOptions _loadOptions = new()
{
PropertyNameCaseInsensitive = true,
};
[RequiresUnreferencedCode("Workspace file deserialization uses reflection-based JSON serializer.")]
[RequiresDynamicCode("Workspace file deserialization uses reflection-based JSON serializer.")]
public static IReadOnlyList<ProjectWrapper> Load()
{
var filePath = GetDefaultFilePath();
if (!File.Exists(filePath))
{
return [];
}
try
{
var json = File.ReadAllText(filePath);
var data = JsonSerializer.Deserialize<WorkspacesFile>(json, _loadOptions);
if (data?.Workspaces == null)
{
return [];
}
return data.Workspaces
.Where(ws => !string.IsNullOrWhiteSpace(ws.Id) && !string.IsNullOrWhiteSpace(ws.Name))
.Select(ws => new ProjectWrapper
{
Id = ws.Id!,
Name = ws.Name!,
Applications = ws.Applications ?? new List<ApplicationWrapper>(),
CreationTime = ws.CreationTime,
LastLaunchedTime = ws.LastLaunchedTime,
IsShortcutNeeded = ws.IsShortcutNeeded,
MoveExistingWindows = ws.MoveExistingWindows,
MonitorConfiguration = ws.MonitorConfiguration ?? new List<MonitorConfigurationWrapper>(),
})
.ToList()
.AsReadOnly();
}
catch
{
return Array.Empty<ProjectWrapper>();
}
}
public static string GetDefaultFilePath()
{
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
return Path.Combine(localAppData, "Microsoft", "PowerToys", "Workspaces", "workspaces.json");
}
private sealed class WorkspacesFile
{
public List<WorkspaceProject> Workspaces { get; set; } = new();
}
private sealed class WorkspaceProject
{
public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public List<ApplicationWrapper> Applications { get; set; } = new();
public List<MonitorConfigurationWrapper> MonitorConfiguration { get; set; } = new();
public long CreationTime { get; set; }
public long LastLaunchedTime { get; set; }
public bool IsShortcutNeeded { get; set; }
public bool MoveExistingWindows { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json;
using WorkspacesCsharpLibrary.Utils;
namespace WorkspacesCsharpLibrary.Utils;
public class DashCaseNamingPolicy : JsonNamingPolicy
{
public static DashCaseNamingPolicy Instance { get; } = new DashCaseNamingPolicy();
public override string ConvertName(string name)
{
return name.UpperCamelCaseToDashCase();
}
}

View File

@@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
namespace WorkspacesCsharpLibrary.Utils;
public class FolderUtils
{
public static string Desktop()
{
return Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
}
public static string Temp()
{
return Path.GetTempPath();
}
// Note: the same path should be used in SnapshotTool and Launcher
public static string DataFolder()
{
return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\Microsoft\\PowerToys\\Workspaces";
}
}

View File

@@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using System.IO.Abstractions;
using System.Threading.Tasks;
namespace WorkspacesCsharpLibrary.Utils;
public class IOUtils
{
private readonly IFileSystem _fileSystem = new FileSystem();
public void WriteFile(string fileName, string data)
{
_fileSystem.File.WriteAllText(fileName, data);
}
public string ReadFile(string fileName)
{
if (_fileSystem.File.Exists(fileName))
{
int attempts = 0;
while (attempts < 10)
{
try
{
using FileSystemStream inputStream = _fileSystem.File.Open(fileName, FileMode.Open);
using StreamReader reader = new(inputStream);
string data = reader.ReadToEnd();
inputStream.Close();
return data;
}
catch (Exception)
{
Task.Delay(10).Wait();
}
attempts++;
}
}
return string.Empty;
}
}

View File

@@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Linq;
namespace WorkspacesCsharpLibrary.Utils;
public static class StringUtils
{
public static string UpperCamelCaseToDashCase(this string str)
{
// If it's a single letter variable, leave it as it is
return str.Length == 1
? str
: string.Concat(str.Select((x, i) => i > 0 && char.IsUpper(x) ? "-" + x : x.ToString())).ToLowerInvariant();
}
}

View File

@@ -1,11 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" /> <Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup> <PropertyGroup>
<AssemblyTitle>PowerToys.WorkspacesCsharpLibrary</AssemblyTitle> <AssemblyTitle>PowerToys.WorkspacesCsharpLibrary</AssemblyTitle>
<AssemblyDescription>PowerToys Workspaces Csharp Library</AssemblyDescription> <AssemblyDescription>PowerToys Workspaces Csharp Library</AssemblyDescription>
<Description>PowerToys Workspaces Csharp Library</Description> <Description>PowerToys Workspaces Csharp Library</Description>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
@@ -15,4 +17,8 @@
<AssemblyName>PowerToys.WorkspacesCsharpLibrary</AssemblyName> <AssemblyName>PowerToys.WorkspacesCsharpLibrary</AssemblyName>
</PropertyGroup> </PropertyGroup>
</Project> <ItemGroup>
<PackageReference Include="System.IO.Abstractions" />
</ItemGroup>
</Project>

View File

@@ -1,101 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using static WorkspacesEditor.Data.ProjectData;
namespace WorkspacesEditor.Data
{
public class ProjectData : WorkspacesEditorData<ProjectWrapper>
{
public struct ApplicationWrapper
{
public struct WindowPositionWrapper
{
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
}
public string Id { get; set; }
public string Application { get; set; }
public string ApplicationPath { get; set; }
public string Title { get; set; }
public string PackageFullName { get; set; }
public string AppUserModelId { get; set; }
public string PwaAppId { get; set; }
public string CommandLineArguments { get; set; }
public bool IsElevated { get; set; }
public bool CanLaunchElevated { get; set; }
public bool Minimized { get; set; }
public bool Maximized { get; set; }
public WindowPositionWrapper Position { get; set; }
public int Monitor { get; set; }
public string Version { get; set; }
}
public struct MonitorConfigurationWrapper
{
public struct MonitorRectWrapper
{
public int Top { get; set; }
public int Left { get; set; }
public int Width { get; set; }
public int Height { get; set; }
}
public string Id { get; set; }
public string InstanceId { get; set; }
public int MonitorNumber { get; set; }
public int Dpi { get; set; }
public MonitorRectWrapper MonitorRectDpiAware { get; set; }
public MonitorRectWrapper MonitorRectDpiUnaware { get; set; }
}
public struct ProjectWrapper
{
public string Id { get; set; }
public string Name { get; set; }
public long CreationTime { get; set; }
public long LastLaunchedTime { get; set; }
public bool IsShortcutNeeded { get; set; }
public bool MoveExistingWindows { get; set; }
public List<MonitorConfigurationWrapper> MonitorConfiguration { get; set; }
public List<ApplicationWrapper> Applications { get; set; }
}
}
}

View File

@@ -1,30 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using WorkspacesEditor.Utils;
using static WorkspacesEditor.Data.ProjectData;
using static WorkspacesEditor.Data.WorkspacesData;
namespace WorkspacesEditor.Data
{
public class WorkspacesData : WorkspacesEditorData<WorkspacesListWrapper>
{
public string File => FolderUtils.DataFolder() + "\\workspaces.json";
public struct WorkspacesListWrapper
{
public List<ProjectWrapper> Workspaces { get; set; }
}
public enum OrderBy
{
LastViewed = 0,
Created = 1,
Name = 2,
Unknown = 3,
}
}
}

View File

@@ -1,33 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json;
using WorkspacesEditor.Utils;
namespace WorkspacesEditor.Data
{
public class WorkspacesEditorData<T>
{
protected JsonSerializerOptions JsonOptions
{
get => new()
{
PropertyNamingPolicy = new DashCaseNamingPolicy(),
WriteIndented = true,
};
}
public T Read(string file)
{
IOUtils ioUtils = new();
string data = ioUtils.ReadFile(file);
return JsonSerializer.Deserialize<T>(data, JsonOptions);
}
public string Serialize(T data)
{
return JsonSerializer.Serialize(data, JsonOptions);
}
}
}

View File

@@ -13,7 +13,7 @@ using System.Threading.Tasks;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using ManagedCommon; using ManagedCommon;
using WorkspacesEditor.Data; using WorkspacesCsharpLibrary.Data;
using WorkspacesEditor.Utils; using WorkspacesEditor.Utils;
namespace WorkspacesEditor.Models namespace WorkspacesEditor.Models
@@ -226,7 +226,7 @@ namespace WorkspacesEditor.Models
} }
} }
public Project(ProjectData.ProjectWrapper project) public Project(ProjectWrapper project)
{ {
Id = project.Id; Id = project.Id;
Name = project.Name; Name = project.Name;
@@ -237,7 +237,7 @@ namespace WorkspacesEditor.Models
Monitors = []; Monitors = [];
Applications = []; Applications = [];
foreach (ProjectData.ApplicationWrapper app in project.Applications) foreach (ApplicationWrapper app in project.Applications)
{ {
Models.Application newApp = new() Models.Application newApp = new()
{ {
@@ -269,7 +269,7 @@ namespace WorkspacesEditor.Models
Applications.Add(newApp); Applications.Add(newApp);
} }
foreach (ProjectData.MonitorConfigurationWrapper monitor in project.MonitorConfiguration) foreach (MonitorConfigurationWrapper monitor in project.MonitorConfiguration)
{ {
System.Windows.Rect dpiAware = new(monitor.MonitorRectDpiAware.Left, monitor.MonitorRectDpiAware.Top, monitor.MonitorRectDpiAware.Width, monitor.MonitorRectDpiAware.Height); System.Windows.Rect dpiAware = new(monitor.MonitorRectDpiAware.Left, monitor.MonitorRectDpiAware.Top, monitor.MonitorRectDpiAware.Width, monitor.MonitorRectDpiAware.Height);
System.Windows.Rect dpiUnaware = new(monitor.MonitorRectDpiUnaware.Left, monitor.MonitorRectDpiUnaware.Top, monitor.MonitorRectDpiUnaware.Width, monitor.MonitorRectDpiUnaware.Height); System.Windows.Rect dpiUnaware = new(monitor.MonitorRectDpiUnaware.Left, monitor.MonitorRectDpiUnaware.Top, monitor.MonitorRectDpiUnaware.Width, monitor.MonitorRectDpiUnaware.Height);

View File

@@ -1,18 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json;
namespace WorkspacesEditor.Utils
{
public class DashCaseNamingPolicy : JsonNamingPolicy
{
public static DashCaseNamingPolicy Instance { get; } = new DashCaseNamingPolicy();
public override string ConvertName(string name)
{
return name.UpperCamelCaseToDashCase();
}
}
}

View File

@@ -1,28 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
namespace WorkspacesEditor.Utils
{
public class FolderUtils
{
public static string Desktop()
{
return Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
}
public static string Temp()
{
return Path.GetTempPath();
}
// Note: the same path should be used in SnapshotTool and Launcher
public static string DataFolder()
{
return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\Microsoft\\PowerToys\\Workspaces";
}
}
}

View File

@@ -1,52 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using System.IO.Abstractions;
using System.Threading.Tasks;
namespace WorkspacesEditor.Utils
{
public class IOUtils
{
private readonly IFileSystem _fileSystem = new FileSystem();
public IOUtils()
{
}
public void WriteFile(string fileName, string data)
{
_fileSystem.File.WriteAllText(fileName, data);
}
public string ReadFile(string fileName)
{
if (_fileSystem.File.Exists(fileName))
{
int attempts = 0;
while (attempts < 10)
{
try
{
using FileSystemStream inputStream = _fileSystem.File.Open(fileName, FileMode.Open);
using StreamReader reader = new(inputStream);
string data = reader.ReadToEnd();
inputStream.Close();
return data;
}
catch (Exception)
{
Task.Delay(10).Wait();
}
attempts++;
}
}
return string.Empty;
}
}
}

View File

@@ -6,9 +6,9 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using ManagedCommon; using ManagedCommon;
using WorkspacesEditor.Data; using WorkspacesCsharpLibrary.Data;
using WorkspacesCsharpLibrary.Utils;
using WorkspacesEditor.Models; using WorkspacesEditor.Models;
using WorkspacesEditor.ViewModels; using WorkspacesEditor.ViewModels;
@@ -81,7 +81,7 @@ namespace WorkspacesEditor.Utils
foreach (Project project in workspaces) foreach (Project project in workspaces)
{ {
ProjectData.ProjectWrapper wrapper = new() ProjectWrapper wrapper = new()
{ {
Id = project.Id, Id = project.Id,
Name = project.Name, Name = project.Name,
@@ -95,7 +95,7 @@ namespace WorkspacesEditor.Utils
foreach (Application app in project.Applications.Where(x => x.IsIncluded)) foreach (Application app in project.Applications.Where(x => x.IsIncluded))
{ {
wrapper.Applications.Add(new ProjectData.ApplicationWrapper wrapper.Applications.Add(new ApplicationWrapper
{ {
Id = app.Id, Id = app.Id,
Application = app.AppName, Application = app.AppName,
@@ -110,7 +110,7 @@ namespace WorkspacesEditor.Utils
Version = app.Version, Version = app.Version,
Maximized = app.Maximized, Maximized = app.Maximized,
Minimized = app.Minimized, Minimized = app.Minimized,
Position = new ProjectData.ApplicationWrapper.WindowPositionWrapper Position = new ApplicationWrapper.WindowPositionWrapper
{ {
X = app.Position.X, X = app.Position.X,
Y = app.Position.Y, Y = app.Position.Y,
@@ -123,20 +123,20 @@ namespace WorkspacesEditor.Utils
foreach (MonitorSetup monitor in project.Monitors) foreach (MonitorSetup monitor in project.Monitors)
{ {
wrapper.MonitorConfiguration.Add(new ProjectData.MonitorConfigurationWrapper wrapper.MonitorConfiguration.Add(new MonitorConfigurationWrapper
{ {
Id = monitor.MonitorName, Id = monitor.MonitorName,
InstanceId = monitor.MonitorInstanceId, InstanceId = monitor.MonitorInstanceId,
MonitorNumber = monitor.MonitorNumber, MonitorNumber = monitor.MonitorNumber,
Dpi = monitor.Dpi, Dpi = monitor.Dpi,
MonitorRectDpiAware = new ProjectData.MonitorConfigurationWrapper.MonitorRectWrapper MonitorRectDpiAware = new MonitorConfigurationWrapper.MonitorRectWrapper
{ {
Left = (int)monitor.MonitorDpiAwareBounds.Left, Left = (int)monitor.MonitorDpiAwareBounds.Left,
Top = (int)monitor.MonitorDpiAwareBounds.Top, Top = (int)monitor.MonitorDpiAwareBounds.Top,
Width = (int)monitor.MonitorDpiAwareBounds.Width, Width = (int)monitor.MonitorDpiAwareBounds.Width,
Height = (int)monitor.MonitorDpiAwareBounds.Height, Height = (int)monitor.MonitorDpiAwareBounds.Height,
}, },
MonitorRectDpiUnaware = new ProjectData.MonitorConfigurationWrapper.MonitorRectWrapper MonitorRectDpiUnaware = new MonitorConfigurationWrapper.MonitorRectWrapper
{ {
Left = (int)monitor.MonitorDpiUnawareBounds.Left, Left = (int)monitor.MonitorDpiUnawareBounds.Left,
Top = (int)monitor.MonitorDpiUnawareBounds.Top, Top = (int)monitor.MonitorDpiUnawareBounds.Top,
@@ -163,7 +163,7 @@ namespace WorkspacesEditor.Utils
private bool AddWorkspaces(MainViewModel mainViewModel, WorkspacesData.WorkspacesListWrapper workspaces) private bool AddWorkspaces(MainViewModel mainViewModel, WorkspacesData.WorkspacesListWrapper workspaces)
{ {
foreach (ProjectData.ProjectWrapper project in workspaces.Workspaces) foreach (ProjectWrapper project in workspaces.Workspaces)
{ {
mainViewModel.Workspaces.Add(new Project(project)); mainViewModel.Workspaces.Add(new Project(project));
} }

View File

@@ -18,12 +18,12 @@ using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Telemetry; using Microsoft.PowerToys.Telemetry;
using WorkspacesCsharpLibrary; using WorkspacesCsharpLibrary;
using WorkspacesEditor.Data; using WorkspacesCsharpLibrary.Data;
using WorkspacesCsharpLibrary.Utils;
using WorkspacesEditor.Models; using WorkspacesEditor.Models;
using WorkspacesEditor.Telemetry; using WorkspacesEditor.Telemetry;
using WorkspacesEditor.Utils; using WorkspacesEditor.Utils;
using static WorkspacesCsharpLibrary.Data.WorkspacesData;
using static WorkspacesEditor.Data.WorkspacesData;
namespace WorkspacesEditor.ViewModels namespace WorkspacesEditor.ViewModels
{ {

View File

@@ -78,6 +78,15 @@
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" /> <ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
<ProjectReference Include="..\WorkspacesCsharpLibrary\WorkspacesCsharpLibrary.csproj" /> <ProjectReference Include="..\WorkspacesCsharpLibrary\WorkspacesCsharpLibrary.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Remove="Data\WorkspacesData.cs" />
<Compile Remove="Data\ProjectData.cs" />
<Compile Remove="Data\WorkspacesEditorData`1.cs" />
<Compile Remove="Utils\IOUtils.cs" />
<Compile Remove="Utils\FolderUtils.cs" />
<Compile Remove="Utils\DashCaseNamingPolicy.cs" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="Properties\Resources.Designer.cs"> <Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
@@ -96,4 +105,4 @@
<LastGenOutput>Settings.Designer.cs</LastGenOutput> <LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None> </None>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -9,7 +9,7 @@ using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using WorkspacesEditor.Data; using WorkspacesCsharpLibrary.Data;
using WorkspacesEditor.Models; using WorkspacesEditor.Models;
using WorkspacesEditor.ViewModels; using WorkspacesEditor.ViewModels;

View File

@@ -3,15 +3,12 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Workspaces.Data;
using static WorkspacesLauncherUI.Data.AppLaunchData; using static WorkspacesLauncherUI.Data.AppLaunchData;
using static WorkspacesLauncherUI.Data.AppLaunchInfosData; using static WorkspacesLauncherUI.Data.AppLaunchInfosData;
namespace WorkspacesLauncherUI.Data namespace WorkspacesLauncherUI.Data
{ {
public class AppLaunchData : WorkspacesUIData<AppLaunchDataWrapper> public class AppLaunchData : WorkspacesCsharpLibrary.Data.WorkspacesEditorData<AppLaunchDataWrapper>
{ {
public struct AppLaunchDataWrapper public struct AppLaunchDataWrapper
{ {

View File

@@ -3,14 +3,11 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Workspaces.Data;
using static WorkspacesLauncherUI.Data.AppLaunchInfoData; using static WorkspacesLauncherUI.Data.AppLaunchInfoData;
namespace WorkspacesLauncherUI.Data namespace WorkspacesLauncherUI.Data
{ {
public class AppLaunchInfoData : WorkspacesUIData<AppLaunchInfoWrapper> public class AppLaunchInfoData : WorkspacesCsharpLibrary.Data.WorkspacesEditorData<AppLaunchInfoWrapper>
{ {
public struct AppLaunchInfoWrapper public struct AppLaunchInfoWrapper
{ {

View File

@@ -4,15 +4,12 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Workspaces.Data;
using static WorkspacesLauncherUI.Data.AppLaunchInfoData; using static WorkspacesLauncherUI.Data.AppLaunchInfoData;
using static WorkspacesLauncherUI.Data.AppLaunchInfosData; using static WorkspacesLauncherUI.Data.AppLaunchInfosData;
namespace WorkspacesLauncherUI.Data namespace WorkspacesLauncherUI.Data
{ {
public class AppLaunchInfosData : WorkspacesUIData<AppLaunchInfoListWrapper> public class AppLaunchInfosData : WorkspacesCsharpLibrary.Data.WorkspacesEditorData<AppLaunchInfoListWrapper>
{ {
public struct AppLaunchInfoListWrapper public struct AppLaunchInfoListWrapper
{ {

View File

@@ -1,35 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json;
using WorkspacesLauncherUI.Utils;
namespace Workspaces.Data
{
public class WorkspacesUIData<T>
{
protected JsonSerializerOptions JsonOptions
{
get
{
return new JsonSerializerOptions
{
PropertyNamingPolicy = new DashCaseNamingPolicy(),
WriteIndented = true,
};
}
}
public T Deserialize(string data)
{
return JsonSerializer.Deserialize<T>(data, JsonOptions);
}
public string Serialize(T data)
{
return JsonSerializer.Serialize(data, JsonOptions);
}
}
}

View File

@@ -1,102 +1,102 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well --> <!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" /> <Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" /> <Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<AssemblyTitle>PowerToys.WorkspacesLauncherUI</AssemblyTitle>
<AssemblyDescription>PowerToys Workspaces Editor</AssemblyDescription>
<Description>PowerToys Workspaces Editor</Description>
<OutputType>WinExe</OutputType>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)</OutputPath>
</PropertyGroup>
<PropertyGroup>
<ProjectGuid>{9C53CC25-0623-4569-95BC-B05410675EE3}</ProjectGuid>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup> <PropertyGroup>
<ApplicationIcon>..\Assets\Workspaces\Workspaces.ico</ApplicationIcon> <AssemblyTitle>PowerToys.WorkspacesLauncherUI</AssemblyTitle>
</PropertyGroup> <AssemblyDescription>PowerToys Workspaces Launcher UI</AssemblyDescription>
<PropertyGroup> <Description>PowerToys Workspaces Launcher UI</Description>
<ApplicationManifest>app.manifest</ApplicationManifest> <OutputType>WinExe</OutputType>
<AssemblyName>PowerToys.WorkspacesLauncherUI</AssemblyName> <UseWPF>true</UseWPF>
</PropertyGroup> <UseWindowsForms>true</UseWindowsForms>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<ItemGroup> <AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<Content Include="..\Assets\**\*.*"> <GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
<Link>Assets\Workspaces\%(Filename)%(Extension)</Link> <OutputPath>..\..\..\..\$(Platform)\$(Configuration)</OutputPath>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </PropertyGroup>
</Content>
</ItemGroup>
<ItemGroup> <PropertyGroup>
<COMReference Include="IWshRuntimeLibrary"> <ProjectGuid>{9C53CC25-0623-4569-95BC-B05410675EE3}</ProjectGuid>
<WrapperTool>tlbimp</WrapperTool> <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VersionMinor>0</VersionMinor> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<VersionMajor>1</VersionMajor> </PropertyGroup>
<Guid>f935dc20-1cf0-11d0-adb9-00c04fd58a0b</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
<COMReference Include="Shell32">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>0</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>50a7e9b0-70ef-11d1-b75a-00a0c90564fe</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="app.manifest" />
</ItemGroup>
<ItemGroup> <PropertyGroup>
<PackageReference Include="ControlzEx" /> <ApplicationIcon>..\Assets\Workspaces\Workspaces.ico</ApplicationIcon>
<PackageReference Include="ModernWpfUI" /> </PropertyGroup>
<PackageReference Include="System.IO.Abstractions" /> <PropertyGroup>
</ItemGroup> <ApplicationManifest>app.manifest</ApplicationManifest>
<AssemblyName>PowerToys.WorkspacesLauncherUI</AssemblyName>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" /> <Content Include="..\Assets\**\*.*">
<ProjectReference Include="..\..\..\common\GPOWrapperProjection\GPOWrapperProjection.csproj" /> <Link>Assets\Workspaces\%(Filename)%(Extension)</Link>
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" /> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" /> </Content>
<ProjectReference Include="..\..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" /> </ItemGroup>
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
<ProjectReference Include="..\WorkspacesCsharpLibrary\WorkspacesCsharpLibrary.csproj" /> <ItemGroup>
</ItemGroup> <COMReference Include="IWshRuntimeLibrary">
<ItemGroup> <WrapperTool>tlbimp</WrapperTool>
<Compile Update="Properties\Resources.Designer.cs"> <VersionMinor>0</VersionMinor>
<DesignTime>True</DesignTime> <VersionMajor>1</VersionMajor>
<AutoGen>True</AutoGen> <Guid>f935dc20-1cf0-11d0-adb9-00c04fd58a0b</Guid>
<DependentUpon>Resources.resx</DependentUpon> <Lcid>0</Lcid>
</Compile> <Isolated>false</Isolated>
<Compile Update="Properties\Settings.Designer.cs"> <EmbedInteropTypes>true</EmbedInteropTypes>
<DesignTimeSharedInput>True</DesignTimeSharedInput> </COMReference>
<AutoGen>True</AutoGen> <COMReference Include="Shell32">
<DependentUpon>Settings.settings</DependentUpon> <WrapperTool>tlbimp</WrapperTool>
</Compile> <VersionMinor>0</VersionMinor>
</ItemGroup> <VersionMajor>1</VersionMajor>
<ItemGroup> <Guid>50a7e9b0-70ef-11d1-b75a-00a0c90564fe</Guid>
<None Update="Properties\Settings.settings"> <Lcid>0</Lcid>
<Generator>SettingsSingleFileGenerator</Generator> <Isolated>false</Isolated>
<LastGenOutput>Settings.Designer.cs</LastGenOutput> <EmbedInteropTypes>true</EmbedInteropTypes>
</None> </COMReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="app.manifest" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ControlzEx" />
<PackageReference Include="ModernWpfUI" />
<PackageReference Include="System.IO.Abstractions" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
<ProjectReference Include="..\..\..\common\GPOWrapperProjection\GPOWrapperProjection.csproj" />
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" />
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
<ProjectReference Include="..\WorkspacesCsharpLibrary\WorkspacesCsharpLibrary.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Update="Properties\Settings.Designer.cs">
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<None Update="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
</Project> </Project>

View File

@@ -6,9 +6,9 @@ using System.Threading;
using Microsoft.CmdPal.Ext.PowerToys.Classes; using Microsoft.CmdPal.Ext.PowerToys.Classes;
using Microsoft.CmdPal.Ext.PowerToys.Properties; using Microsoft.CmdPal.Ext.PowerToys.Properties;
using Microsoft.CommandPalette.Extensions.Toolkit; using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.CmdPal.Ext.PowerToys.Services;
using PowerToys.Interop; using PowerToys.Interop;
using static Common.UI.SettingsDeepLink; using static Common.UI.SettingsDeepLink;
using Workspaces.ModuleServices;
namespace Microsoft.CmdPal.Ext.PowerToys.Commands; namespace Microsoft.CmdPal.Ext.PowerToys.Commands;
@@ -133,7 +133,7 @@ internal sealed partial class LaunchCommand : InvokableCommand
case SettingsWindow.Workspaces: case SettingsWindow.Workspaces:
{ {
var result = Services.ModuleServices.Workspaces().LaunchEditorAsync().GetAwaiter().GetResult(); var result = WorkspaceService.Instance.LaunchEditorAsync().GetAwaiter().GetResult();
return result.Success return result.Success
? CommandResult.KeepOpen() ? CommandResult.KeepOpen()
: CommandResult.ShowToast(result.Error ?? "Failed to launch Workspaces editor."); : CommandResult.ShowToast(result.Error ?? "Failed to launch Workspaces editor.");

View File

@@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using Microsoft.CommandPalette.Extensions.Toolkit; using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.CmdPal.Ext.PowerToys.Services; using Workspaces.ModuleServices;
namespace Microsoft.CmdPal.Ext.PowerToys.Commands; namespace Microsoft.CmdPal.Ext.PowerToys.Commands;
@@ -19,7 +19,7 @@ internal sealed partial class LaunchWorkspaceCommand : InvokableCommand
public override CommandResult Invoke() public override CommandResult Invoke()
{ {
var result = ModuleServices.Workspaces().LaunchWorkspaceAsync(_workspaceId).GetAwaiter().GetResult(); var result = WorkspaceService.Instance.LaunchWorkspaceAsync(_workspaceId).GetAwaiter().GetResult();
if (!result.Success) if (!result.Success)
{ {
return CommandResult.ShowToast(result.Error ?? "Failed to launch workspace."); return CommandResult.ShowToast(result.Error ?? "Failed to launch workspace.");

View File

@@ -18,6 +18,7 @@
<ProjectReference Include="..\..\..\..\common\Common.UI\Common.UI.csproj" /> <ProjectReference Include="..\..\..\..\common\Common.UI\Common.UI.csproj" />
<ProjectReference Include="..\..\..\..\common\ManagedCommon\ManagedCommon.csproj" /> <ProjectReference Include="..\..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" /> <ProjectReference Include="..\..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
<ProjectReference Include="..\..\..\..\modules\workspaces\Workspaces.ModuleServices\Workspaces.ModuleServices.csproj" />
<ProjectReference Include="..\..\..\..\common\PowerToys.ModuleContracts\PowerToys.ModuleContracts.csproj" /> <ProjectReference Include="..\..\..\..\common\PowerToys.ModuleContracts\PowerToys.ModuleContracts.csproj" />
<ProjectReference Include="..\..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" /> <ProjectReference Include="..\..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -1,17 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using PowerToys.ModuleContracts;
namespace Microsoft.CmdPal.Ext.PowerToys.Services;
/// <summary>
/// Centralized access to module services for the Command Palette host.
/// </summary>
internal static class ModuleServices
{
private static readonly IWorkspaceService _workspaceService = new WorkspaceService();
public static IWorkspaceService Workspaces() => _workspaceService;
}