Skip to content

Commit

Permalink
プロジェクト ファイルを追加します。
Browse files Browse the repository at this point in the history
  • Loading branch information
Freeesia committed Mar 15, 2024
1 parent e8a0f60 commit b3d550a
Show file tree
Hide file tree
Showing 16 changed files with 1,053 additions and 0 deletions.
25 changes: 25 additions & 0 deletions VdLabel.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.9.34701.34
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VdLabel", "VdLabel\VdLabel.csproj", "{550F365E-5537-4DEC-B4F4-9B3E4D904C05}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{550F365E-5537-4DEC-B4F4-9B3E4D904C05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{550F365E-5537-4DEC-B4F4-9B3E4D904C05}.Debug|Any CPU.Build.0 = Debug|Any CPU
{550F365E-5537-4DEC-B4F4-9B3E4D904C05}.Release|Any CPU.ActiveCfg = Release|Any CPU
{550F365E-5537-4DEC-B4F4-9B3E4D904C05}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4FF2BCDC-3065-48AF-82B4-4682B342CCBF}
EndGlobalSection
EndGlobal
17 changes: 17 additions & 0 deletions VdLabel/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Application
x:Class="VdLabel.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
ShutdownMode="OnMainWindowClose">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:ThemesDictionary Theme="Dark" />
<ui:ControlsDictionary />
<ResourceDictionary Source="pack://application:,,,/ColorPicker;component/Styles/DefaultColorPickerStyle.xaml" />
<ResourceDictionary Source="Themes/DefaultStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
14 changes: 14 additions & 0 deletions VdLabel/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Windows;

namespace VdLabel;

/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
public App()
{
InitializeComponent();
}
}
10 changes: 10 additions & 0 deletions VdLabel/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Windows;

[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
27 changes: 27 additions & 0 deletions VdLabel/Config.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Drawing;

namespace VdLabel;

class Config
{
public OverlayPosition Position { get; set; } = OverlayPosition.TopLeft;
public double FontSize { get; set; } = 48;
public Color Foreground { get; set; } = Color.WhiteSmoke;
public Color Background { get; set; } = Color.FromArgb(0x0d1117);
public double Duration { get; set; } = 2.5;
public List<DesktopConfig> DesktopConfigs { get; init; } = [];
}

enum OverlayPosition
{
Center,
TopLeft,
}

record DesktopConfig
{
public Guid Id { get; set; }
public bool IsVisibleName { get; set; } = true;
public string? Name { get; set; }
public string? ImagePath { get; set; }
}
64 changes: 64 additions & 0 deletions VdLabel/IConfigStore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System.Drawing;
using System.IO;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace VdLabel;

interface IConfigStore
{
event EventHandler? Saved;

ValueTask<Config> Load();
ValueTask Save(Config? config = null);
}

class ConfigStore : IConfigStore
{
private readonly string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "VdLabel", "config.json");
private static readonly JsonSerializerOptions options = new()
{
Converters = { new ColorJsonConverter() },
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
};
private Config? config;

public event EventHandler? Saved;

public ValueTask<Config> Load()
{
if (File.Exists(this.path))
{
using var fs = File.OpenRead(this.path);
this.config = JsonSerializer.Deserialize<Config>(fs, options);
}
return new(this.config ??= new Config()
{
DesktopConfigs = { new() { Id = Guid.Empty } }
});
}

public ValueTask Save(Config? config = null)
{
if (config is not null)
{
this.config = config;
}
Directory.CreateDirectory(Path.GetDirectoryName(this.path)!);
using (var fs = File.Create(this.path))
{
JsonSerializer.Serialize(fs, this.config, options);
}
this.Saved?.Invoke(this, EventArgs.Empty);
return default;
}

private class ColorJsonConverter : JsonConverter<Color>
{
public override Color Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> ColorTranslator.FromHtml(reader.GetString()!);
public override void Write(Utf8JsonWriter writer, Color value, JsonSerializerOptions options)
=> writer.WriteStringValue(ColorTranslator.ToHtml(value));
}
}
165 changes: 165 additions & 0 deletions VdLabel/MainViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Win32;
using System.Collections.ObjectModel;
using System.Reflection;
using Wpf.Ui;
using Wpf.Ui.Extensions;

namespace VdLabel;

partial class MainViewModel : ObservableObject
{
private readonly IConfigStore configStore;
private readonly IContentDialogService dialogService;
[ObservableProperty]
private bool isBusy;

[ObservableProperty]
private Config? config;

[ObservableProperty]
private DesktopConfigViewModel? selectedDesktopConfig;

[ObservableProperty]
private bool isStartup;

public ObservableCollection<DesktopConfigViewModel> DesktopConfigs { get; } = [];

public IReadOnlyList<OverlayPosition> Positions { get; } = Enum.GetValues<OverlayPosition>();

public MainViewModel(IConfigStore configStore, IContentDialogService dialogService)
{
this.configStore = configStore;
this.dialogService = dialogService;
this.isStartup = GetIsStartup();
Load();
}

private async void Load()
{
this.IsBusy = true;
try
{
this.Config = await this.configStore.Load();
this.DesktopConfigs.Clear();
foreach (var desktopConfig in this.Config.DesktopConfigs)
{
this.DesktopConfigs.Add(new DesktopConfigViewModel(desktopConfig));
}
this.SelectedDesktopConfig = this.DesktopConfigs.FirstOrDefault();
}
finally
{
this.IsBusy = false;
}
}

[RelayCommand]
public async Task Save()
{
this.IsBusy = true;
try
{
this.Config!.DesktopConfigs.Clear();
foreach (var desktopConfig in this.DesktopConfigs)
{
this.Config.DesktopConfigs.Add(desktopConfig.DesktopConfig);
}
await this.configStore.Save(this.Config);
}
finally
{
this.IsBusy = false;
}
}

partial void OnIsStartupChanged(bool value)
{
var exe = Assembly.GetExecutingAssembly();
using var key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true) ?? throw new InvalidOperationException();
var name = exe.GetName().Name ?? throw new InvalidOperationException();
var path = Environment.ProcessPath ?? throw new InvalidOperationException();
if (value)
{
key.SetValue(name, exe.Location);
this.dialogService.ShowAlertAsync("自動起動", $"{name}を自動起動に登録しました。", "OK");
}
else
{
key.DeleteValue(name, false);
this.dialogService.ShowAlertAsync("自動起動", $"{name}の自動起動を解除しました。", "OK");
}
}

private static bool GetIsStartup()
{
var exe = Assembly.GetExecutingAssembly();
using var key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", false);
string? name = exe.GetName().Name;
return key?.GetValue(name) is { };
}
}

partial class DesktopConfigViewModel(DesktopConfig desktopConfig) : ObservableObject
{
public DesktopConfig DesktopConfig { get; } = desktopConfig;

public Guid Id => this.DesktopConfig.Id;

public bool IsDefault => this.DesktopConfig.Id == Guid.Empty;

public string Title => this.IsDefault ? "デフォルト設定" : this.DesktopConfig.Name ?? this.DesktopConfig.Id.ToString();

public bool IsVisibleName
{
get => this.DesktopConfig.IsVisibleName;
set => SetProperty(this.DesktopConfig.IsVisibleName, value, this.DesktopConfig, (c, v) => c.IsVisibleName = v);
}

public string? Name
{
get => this.DesktopConfig.Name;
set
{
if (SetProperty(this.DesktopConfig.Name, value, this.DesktopConfig, (c, v) => c.Name = v))
{
OnPropertyChanged(nameof(Title));
}
}
}

public string? ImagePath
{
get => this.DesktopConfig.ImagePath;
set
{
if (SetProperty(this.DesktopConfig.ImagePath, value, this.DesktopConfig, (c, v) => c.ImagePath = v))
{
OnPropertyChanged(nameof(IsVisibleImage));
}
}
}

public bool IsVisibleImage => this.ImagePath is not null;

[RelayCommand]
public void PickImage()
{
var openFileDialog = new OpenFileDialog()
{
DefaultDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures),
AddToRecent = true,
CheckFileExists = true,
ForcePreviewPane = true,
Filter = "Image files (*.bmp;*.jpg;*.jpeg;*.png)|*.bmp;*.jpg;*.jpeg;*.png|All files (*.*)|*.*"
};

if (openFileDialog.ShowDialog() != true)
{
return;
}

this.ImagePath = openFileDialog.FileName;
}
}
Loading

0 comments on commit b3d550a

Please sign in to comment.