Skip to content

Commit 911be8f

Browse files
committed
feat: release v0.4.0
This commit breaks conventional commits. Sorry.
1 parent 89aa73b commit 911be8f

37 files changed

Lines changed: 1339 additions & 90 deletions

SnapX.Avalonia/App.axaml.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
using Microsoft.Extensions.DependencyInjection;
2222
using Serilog;
2323
using SnapX.Avalonia.ViewModels;
24+
using SnapX.Avalonia.ViewModels.Settings;
2425
// using SnapX.Avalonia.ViewModels.Settings;
2526
using SnapX.Avalonia.Views;
2627
using SnapX.Avalonia.Views.Settings;
@@ -315,8 +316,27 @@ public void ListenForEvents()
315316
{
316317
Core.SnapXL.EventAggregator.Subscribe<NeedClipboardCopyEvent>(HandleClipboardCopyEvent);
317318
Core.SnapXL.EventAggregator.Subscribe<ErrorMessageEvent>(HandleErrorMessageEvent);
319+
Core.SnapXL.EventAggregator.Subscribe<NeedOCRWindowEvent>(HandleOCRWindowRequestEvent);
320+
Core.SnapXL.EventAggregator.Subscribe<NeedScanQRCodeEvent>(HandleScanQRCodeEvent);
321+
}
322+
void HandleOCRWindowRequestEvent(NeedOCRWindowEvent @event)
323+
{
324+
Dispatcher.UIThread.Invoke(() =>
325+
{
326+
var OCR = new OCR(@event.Image, @event.TaskSettings);
327+
OCR.Show();
328+
});
329+
}
330+
void HandleScanQRCodeEvent(NeedScanQRCodeEvent @event)
331+
{
332+
Dispatcher.UIThread.Invoke(() =>
333+
{
334+
var qrView = new QRCodeView();
335+
qrView.Show();
336+
if (@event.HasImage) qrView.ScanImage(@event.Image);
337+
else qrView.QRText.Text = @event.Text;
338+
});
318339
}
319-
320340
private async void HandleClipboardCopyEvent(NeedClipboardCopyEvent @event)
321341
{
322342
try
@@ -1014,6 +1034,13 @@ public static void ConfigureServices(IServiceCollection services)
10141034
services.AddTransient<NotImplemented>();
10151035
services.AddSingleton<NotImplementedVM>();
10161036

1037+
services.AddTransient<ApplicationUploadSettingsView>();
1038+
services.AddSingleton<ApplicationUploadSettingsVM>();
1039+
services.AddSingleton<ApplicationPathSettingsVM>();
1040+
services.AddTransient<ApplicationPathSettingsView>();
1041+
1042+
services.AddSingleton<GeneralSettingsVM>();
1043+
services.AddTransient<GeneralSettingsView>();
10171044

10181045
services.AddSingleton<IMessenger>(WeakReferenceMessenger.Default);
10191046
}

SnapX.Avalonia/Program.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#if BROWSER
77
using Avalonia.Browser;
88
#else
9-
using Avalonia.Dialogs;
109
using Avalonia.Media;
1110
#endif
1211

@@ -98,7 +97,7 @@ public static AppBuilder BuildAvaloniaApp()
9897
{
9998
builder = builder
10099
.UsePlatformDetect()
101-
.UseManagedSystemDialogs()
100+
// .UseManagedSystemDialogs()
102101
.With(x11Options)
103102
.With(new AvaloniaNativePlatformOptions { OverlayPopups = true })
104103
.With(new Win32PlatformOptions { OverlayPopups = true });

SnapX.Avalonia/SnapX.Avalonia.csproj

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@
6767
<PackageReference Include="SkiaSharp.NativeAssets.macOS" Version="$(SkiaSharpVersion)" />
6868
<PackageReference Include="SkiaSharp.NativeAssets.Win32" Version="$(SkiaSharpVersion)" />
6969
<PackageReference Include="SkiaSharp.NativeAssets.WebAssembly" Version="$(SkiaSharpVersion)" />
70+
<PackageReference Include="DesktopNotificationsFixed" Version="1.0.1" />
71+
<PackageReference Include="DesktopNotificationsFixed.FreeDesktop" Version="1.0.1" />
72+
<PackageReference Include="DesktopNotificationsFixed.Apple" Version="1.0.0" />
73+
<!-- Windows notification support? I hardly know her! It's broken.-->
7074
<ProjectReference Include="..\SnapX.CommonUI\SnapX.CommonUI.csproj" />
7175
</ItemGroup>
7276
<ItemGroup Condition="'$(TargetFreeBSD)' == 'true'">
@@ -86,4 +90,13 @@
8690
<PackageReference Remove="HarfBuzzSharp.NativeAssets.Win32" />
8791
<PackageReference Remove="HarfBuzzSharp.NativeAssets.WebAssembly" />
8892
</ItemGroup>
93+
<ItemGroup>
94+
<AdditionalFiles Include="Views\Settings\Views\ApplicationPathSettingsView.axaml" />
95+
</ItemGroup>
96+
<ItemGroup>
97+
<Compile Update="Views\Settings\Views\ApplicationPathSettingsView.axaml.cs">
98+
<DependentUpon>ApplicationPathSettingsView.axaml</DependentUpon>
99+
<SubType>Code</SubType>
100+
</Compile>
101+
</ItemGroup>
89102
</Project>

SnapX.Avalonia/ViewLocator.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using CommunityToolkit.Mvvm.ComponentModel;
55
using CommunityToolkit.Mvvm.DependencyInjection;
66
using SnapX.Avalonia.ViewModels;
7+
using SnapX.Avalonia.ViewModels.Settings;
78
using SnapX.Avalonia.Views;
89
using SnapX.Avalonia.Views.Settings;
910
using SnapX.Avalonia.Views.Settings.Views;
@@ -27,6 +28,9 @@ public ViewLocator()
2728
RegisterViewFactory<CoreUploaderVM, BuiltInUploaderSettingsView>();
2829
RegisterViewFactory<SettingsHomePageViewVM, SettingsHomePageView>();
2930
RegisterViewFactory<NotImplementedVM, NotImplemented>();
31+
RegisterViewFactory<GeneralSettingsVM, GeneralSettingsView>();
32+
RegisterViewFactory<ApplicationUploadSettingsVM, ApplicationUploadSettingsView>();
33+
RegisterViewFactory<ApplicationPathSettingsVM, ApplicationPathSettingsView>();
3034

3135

3236
}

SnapX.Avalonia/ViewModels/OCRViewModel.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,42 @@ public static readonly (string Display, string Code)[] _languages = new[]
4141
new(_languages.Select(l => l.Display));
4242

4343
public string GetLanguageCode(int index) => _languages[index].Code;
44+
public int GetIndexFromWindowsCode(string windowsCode)
45+
{
46+
var mapping = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
47+
{
48+
{ "af", "afr" }, { "am", "amh" }, { "ar", "ara" }, { "az", "aze" },
49+
{ "be", "bel" }, { "bg", "bul" }, { "bn", "ben" }, { "bs", "bos" },
50+
{ "ca", "cat" }, { "cs", "ces" }, { "cy", "cym" }, { "da", "dan" },
51+
{ "de", "deu" }, { "el", "ell" }, { "en", "eng" }, { "es", "spa" },
52+
{ "et", "est" }, { "eu", "eus" }, { "fa", "fas" }, { "fi", "fin" },
53+
{ "fr", "fra" }, { "ga", "gle" }, { "gl", "glg" }, { "gu", "guj" },
54+
{ "hi", "hin" }, { "hr", "hrv" }, { "hu", "hun" }, { "hy", "hye" },
55+
{ "id", "ind" }, { "is", "isl" }, { "it", "ita" }, { "iw", "heb" },
56+
{ "ja", "jpn" }, { "ka", "kat" }, { "kk", "kaz" }, { "km", "khm" },
57+
{ "kn", "kan" }, { "ko", "kor" }, { "lt", "lit" }, { "lv", "lav" },
58+
{ "mk", "mkd" }, { "ml", "mal" }, { "mn", "mon" }, { "mr", "mar" },
59+
{ "ms", "msl" }, { "mt", "mlt" }, { "my", "mya" }, { "ne", "nep" },
60+
{ "nl", "nld" }, { "no", "nor" }, { "pl", "pol" }, { "pt", "por" },
61+
{ "ro", "ron" }, { "ru", "rus" }, { "sk", "slk" }, { "sl", "slv" },
62+
{ "sq", "sqi" }, { "sr", "srp" }, { "sv", "swe" }, { "sw", "swa" },
63+
{ "ta", "tam" }, { "te", "tel" }, { "th", "tha" }, { "tr", "tur" },
64+
{ "uk", "ukr" }, { "ur", "urd" }, { "uz", "uzb" }, { "vi", "vie" },
65+
{ "zh-CN", "chi_sim" }, { "zh-TW", "chi_tra" }
66+
};
67+
68+
if (!mapping.TryGetValue(windowsCode, out var internalCode)) return 0;
69+
for (var i = 0; i < _languages.Length; i++)
70+
{
71+
if (_languages[i].Code.Equals(internalCode, StringComparison.OrdinalIgnoreCase))
72+
{
73+
return i;
74+
}
75+
}
76+
77+
// We've failed, fuck.
78+
return 0;
79+
}
4480

4581
public async Task<TaskHelpers.OcrResponse> RunOCRAsync(
4682
HistoryItem? Item = null,
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
using Avalonia;
2+
using Avalonia.Controls;
3+
using Avalonia.Platform.Storage;
4+
using CommunityToolkit.Mvvm.ComponentModel;
5+
using CommunityToolkit.Mvvm.Input;
6+
using SnapX.Core;
7+
using SnapX.Core.Utils;
8+
9+
namespace SnapX.Avalonia.ViewModels.Settings;
10+
11+
public partial class ApplicationPathSettingsVM : ViewModelBase
12+
{
13+
private readonly ApplicationConfig _config;
14+
private IStorageService? _storageService;
15+
16+
public void SetStorageService(IStorageService service)
17+
{
18+
_storageService = service;
19+
}
20+
[ObservableProperty]
21+
private string _personalFolderPath;
22+
23+
[ObservableProperty]
24+
private bool _useCustomScreenshotsFolder;
25+
26+
[ObservableProperty]
27+
private string _customScreenshotsPath;
28+
29+
[ObservableProperty]
30+
private string _subFolderPattern;
31+
32+
[ObservableProperty]
33+
private string _windowSubFolderPattern;
34+
35+
public string SubFolderPreviewPath => Path.Combine(
36+
UseCustomScreenshotsFolder ? CustomScreenshotsPath : PersonalFolderPath,
37+
"Screenshots",
38+
DateTime.Now.ToString(SubFolderPattern ?? "yyyy-MM"));
39+
40+
public ApplicationPathSettingsVM()
41+
{
42+
_config = SnapXL.Settings;
43+
44+
_personalFolderPath = SnapXL.PersonalFolder;
45+
_useCustomScreenshotsFolder = _config.UseCustomScreenshotsPath;
46+
_customScreenshotsPath = _config.CustomScreenshotsPath;
47+
_subFolderPattern = _config.SaveImageSubFolderPattern;
48+
_windowSubFolderPattern = _config.SaveImageSubFolderPatternWindow;
49+
}
50+
51+
partial void OnPersonalFolderPathChanged(string value) => SnapXL.CustomPersonalPath = value;
52+
partial void OnUseCustomScreenshotsFolderChanged(bool value)
53+
{
54+
_config.UseCustomScreenshotsPath = value;
55+
OnPropertyChanged(nameof(SubFolderPreviewPath));
56+
}
57+
partial void OnCustomScreenshotsPathChanged(string value)
58+
{
59+
_config.CustomScreenshotsPath = value;
60+
OnPropertyChanged(nameof(SubFolderPreviewPath));
61+
}
62+
partial void OnSubFolderPatternChanged(string value)
63+
{
64+
_config.SaveImageSubFolderPattern = value;
65+
OnPropertyChanged(nameof(SubFolderPreviewPath));
66+
}
67+
partial void OnWindowSubFolderPatternChanged(string value) => _config.SaveImageSubFolderPatternWindow = value;
68+
69+
[RelayCommand]
70+
private async Task BrowsePersonalFolder()
71+
{
72+
if (_storageService == null) return;
73+
74+
var path = await _storageService.SelectFolderAsync("Select Personal Folder", PersonalFolderPath);
75+
if (!string.IsNullOrEmpty(path))
76+
{
77+
PersonalFolderPath = path;
78+
}
79+
}
80+
81+
[RelayCommand]
82+
private void ApplyPersonalFolder()
83+
{
84+
// idk
85+
}
86+
87+
[RelayCommand]
88+
private void OpenPersonalFolder() => OpenFolder(PersonalFolderPath);
89+
90+
[RelayCommand]
91+
private async Task BrowseCustomScreenshots(Visual visual)
92+
{
93+
var path = await ShowFolderPicker(visual, "Select Screenshots Folder", CustomScreenshotsPath);
94+
if (!string.IsNullOrEmpty(path)) CustomScreenshotsPath = path;
95+
}
96+
97+
[RelayCommand]
98+
private void OpenSubFolder() => OpenFolder(SubFolderPreviewPath);
99+
100+
private async Task<string?> ShowFolderPicker(Visual visual, string title, string startPath)
101+
{
102+
var topLevel = TopLevel.GetTopLevel(visual);
103+
if (topLevel == null) return null;
104+
105+
var options = new FolderPickerOpenOptions
106+
{
107+
Title = title,
108+
AllowMultiple = false
109+
};
110+
111+
if (Directory.Exists(startPath))
112+
{
113+
options.SuggestedStartLocation = await topLevel.StorageProvider.TryGetFolderFromPathAsync(startPath);
114+
}
115+
116+
var result = await topLevel.StorageProvider.OpenFolderPickerAsync(options);
117+
return result.Count > 0 ? result[0].Path.LocalPath : null;
118+
}
119+
120+
private void OpenFolder(string path)
121+
{
122+
FileHelpers.OpenFolder(path);
123+
}
124+
}
125+
public interface IStorageService
126+
{
127+
Task<string?> SelectFolderAsync(string title, string startPath);
128+
}
129+
130+
public class StorageService(TopLevel topLevel) : IStorageService
131+
{
132+
public async Task<string?> SelectFolderAsync(string title, string startPath)
133+
{
134+
var options = new FolderPickerOpenOptions { Title = title, AllowMultiple = false };
135+
if (Directory.Exists(startPath))
136+
options.SuggestedStartLocation = await topLevel.StorageProvider.TryGetFolderFromPathAsync(startPath);
137+
138+
var result = await topLevel.StorageProvider.OpenFolderPickerAsync(options);
139+
return result.Count > 0 ? result[0].Path.LocalPath : null;
140+
}
141+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace SnapX.Avalonia.ViewModels.Settings;
2+
3+
public class ApplicationUploadSettingsVM : ViewModelBase
4+
{
5+
6+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using CommunityToolkit.Mvvm.ComponentModel;
2+
using SnapX.Core;
3+
4+
namespace SnapX.Avalonia.ViewModels.Settings;
5+
6+
public partial class GeneralSettingsVM : ViewModelBase
7+
{
8+
private readonly ApplicationConfig _config;
9+
10+
[ObservableProperty]
11+
private bool _rememberMainWindowPosition;
12+
13+
[ObservableProperty]
14+
private bool _disableTelemetry;
15+
16+
public GeneralSettingsVM()
17+
{
18+
_config = SnapXL.Settings;
19+
20+
_rememberMainWindowPosition = _config.RememberMainFormPosition;
21+
_disableTelemetry = _config.DisableTelemetry;
22+
}
23+
24+
partial void OnRememberMainWindowPositionChanged(bool value)
25+
{
26+
_config.RememberMainFormPosition = value;
27+
}
28+
29+
partial void OnDisableTelemetryChanged(bool value)
30+
{
31+
_config.DisableTelemetry = value;
32+
}
33+
}

SnapX.Avalonia/ViewModels/Settings/ImportExportVM.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ await Dispatcher.UIThread.InvokeAsync(() =>
9595

9696
try
9797
{
98-
await Dispatcher.UIThread.InvokeAsync(async() => { await dialog.ShowAsync(App.MySettingsWindow); });
98+
await Dispatcher.UIThread.InvokeAsync(async () => { await dialog.ShowAsync(App.MySettingsWindow); });
9999
}
100100
catch (Exception ex)
101101
{

SnapX.Avalonia/ViewModels/Settings/SettingsMainViewVM.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Avalonia.Controls;
22
using CommunityToolkit.Mvvm.ComponentModel;
33
using CommunityToolkit.Mvvm.DependencyInjection;
4+
using SnapX.Avalonia.ViewModels.Settings;
45
using SnapX.Core;
56
using SnapX.Core.Upload;
67

@@ -27,6 +28,10 @@ public SettingsMainViewVM()
2728
RegisterPage<DatabaseVM>("Database");
2829
RegisterPage<CoreUploaderVM>("BuiltInUploader");
2930
RegisterPage<NotImplementedVM>("NotImplemented");
31+
RegisterPage<GeneralSettingsVM>("General");
32+
// RegisterPage<ApplicationUploadSettingsVM>("Upload");
33+
RegisterPage<ApplicationPathSettingsVM>("Paths");
34+
3035
foreach (var category in Enum.GetValues<UploaderCategory>())
3136
{
3237
var pageKey = category.ToString();

0 commit comments

Comments
 (0)