fixes and optimizations

This commit is contained in:
Denys Konovalov 2024-09-14 17:49:20 +02:00
parent 5f1c8d8a55
commit 4bd93fa87e
6 changed files with 164 additions and 277 deletions

6
.editorconfig Normal file

@ -0,0 +1,6 @@
# CSharp formatting rules:
[*.cs]
csharp_new_line_before_open_brace = none
csharp_new_line_before_else = false
csharp_new_line_before_catch = false
csharp_new_line_before_finally = false

@ -1,9 +1,10 @@
public class AppInfo namespace Photomator;
{
public static readonly string ApplicationName = "Photomator"; public static class AppInfo {
public static readonly string IconName = "de.cantorgymnasium.Photomator"; public static readonly string ApplicationName = "Photomator";
public static readonly string Version = ThisAssembly.Git.Tag; public static readonly string IconName = "de.cantorgymnasium.Photomator";
public static readonly string ReleaseNotes = @" public static readonly string Version = ThisAssembly.Git.Tag;
public static readonly string ReleaseNotes = @"
<p><em>0.0.1</em></p> <p><em>0.0.1</em></p>
<p>Initial release</p> <p>Initial release</p>
<ul> <ul>
@ -12,8 +13,8 @@ public class AppInfo
<li>Windows support</li> <li>Windows support</li>
</ul> </ul>
"; ";
public static readonly string Copyright = "© 2024 Denys Konovalov"; public static readonly string Copyright = "© 2024 Denys Konovalov";
public static readonly string DeveloperName = "Denys Konovalov"; public static readonly string DeveloperName = "Denys Konovalov";
public static readonly string Website = "https://git.cantorgymnasium.de/gcg/Photomator"; public static readonly string Website = "https://git.cantorgymnasium.de/gcg/Photomator";
public static readonly string IssueUrl = "https://git.cantorgymnasium.de/gcg/Photomator/issues"; public static readonly string IssueUrl = "https://git.cantorgymnasium.de/gcg/Photomator/issues";
} }

@ -4,49 +4,35 @@ using SixLabors.ImageSharp.Processing;
namespace Photomator; namespace Photomator;
public class Lib public static class Lib {
{ public static async Task Convert(string src, string dest, ConvertOptions options) {
public static async Task Convert(string src, string dest, ConvertOptions options)
{
Image img = await Image.LoadAsync(src); Image img = await Image.LoadAsync(src);
img.Mutate(i => img.Mutate(i => {
{
i.AutoOrient(); i.AutoOrient();
Size currentSize = i.GetCurrentSize(); Size currentSize = i.GetCurrentSize();
if (currentSize.Height > currentSize.Width) if (currentSize.Height > currentSize.Width) {
{
i.Resize(options.Resolution, 0); i.Resize(options.Resolution, 0);
} } else {
else
{
i.Resize(0, options.Resolution); i.Resize(0, options.Resolution);
} }
}); });
await img.SaveAsWebpAsync(dest, new WebpEncoder await img.SaveAsWebpAsync(dest, new WebpEncoder {
{
FileFormat = options.Format FileFormat = options.Format
}); });
} }
public static async Task<ConvertError[]> ConvertList(string[] src, string dest, ConvertOptions options, Action<double> setProgress) public static async Task<ConvertError[]> ConvertList(string[] src, string dest, ConvertOptions options, Action<double> setProgress) {
{
double progress = 0; double progress = 0;
List<ConvertError> unconverted = []; List<ConvertError> unconverted = [];
await Parallel.ForEachAsync(src, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, async (path, _) => await Parallel.ForEachAsync(src, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, async (path, _) => {
{ string filename = path.Split(Path.DirectorySeparatorChar)[^1];
string filename = path.Split(Path.DirectorySeparatorChar).Last();
string[] splitted = filename.Split('.'); string[] splitted = filename.Split('.');
splitted[^1] = "webp"; splitted[^1] = "webp";
try try {
{
await Convert(path, dest + Path.DirectorySeparatorChar + string.Join(".", splitted), options); await Convert(path, dest + Path.DirectorySeparatorChar + string.Join(".", splitted), options);
} } catch (UnknownImageFormatException) {
catch (UnknownImageFormatException)
{
unconverted.Add(new ConvertError(filename, "Das Dateiformat wird nicht unterstützt.")); unconverted.Add(new ConvertError(filename, "Das Dateiformat wird nicht unterstützt."));
} } catch (Exception e) {
catch (Exception e)
{
unconverted.Add(new ConvertError(filename, e.Message)); unconverted.Add(new ConvertError(filename, e.Message));
} }
progress += 1.0 / src.Length; progress += 1.0 / src.Length;
@ -56,14 +42,12 @@ public class Lib
} }
} }
public readonly struct ConvertOptions(string? resolution, uint format) public readonly struct ConvertOptions(string? resolution, uint format) {
{
public int Resolution { get; init; } = resolution != null ? Convert.ToInt32(resolution) : 1440; public int Resolution { get; init; } = resolution != null ? Convert.ToInt32(resolution) : 1440;
public WebpFileFormatType Format { get; init; } = format == 1 ? WebpFileFormatType.Lossless : WebpFileFormatType.Lossy; public WebpFileFormatType Format { get; init; } = format == 1 ? WebpFileFormatType.Lossless : WebpFileFormatType.Lossy;
} }
public readonly struct ConvertError(string file, string message) public readonly struct ConvertError(string file, string message) {
{
public string File { get; init; } = file; public string File { get; init; } = file;
public string Message { get; init; } = message; public string Message { get; init; } = message;
} }

@ -3,37 +3,26 @@ using Photomator.Views;
namespace Photomator; namespace Photomator;
public partial class Program public partial class Program {
{
public delegate void OpenCallback(nint application, nint[] files, int n_files, nint hint, nint data); public delegate void OpenCallback(nint application, nint[] files, int n_files, nint hint, nint data);
private readonly Adw.Application _application; private readonly Adw.Application _application;
public static int Main() => new Program().Run(); public static int Main() => new Program().Run();
public Program() public Program() {
{
_application = Adw.Application.New("de.cantorgymnasium.Photomator", Gio.ApplicationFlags.FlagsNone); _application = Adw.Application.New("de.cantorgymnasium.Photomator", Gio.ApplicationFlags.FlagsNone);
Gtk.Window.SetDefaultIconName("de.cantorgymnasium.Photomator"); Gtk.Window.SetDefaultIconName("de.cantorgymnasium.Photomator");
if (File.Exists(Path.GetFullPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!) + "/de.cantorgymnasium.Photomator.gresource")) if (File.Exists(Path.GetFullPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!) + "/de.cantorgymnasium.Photomator.gresource"))
{
Gio.Functions.ResourcesRegister(Gio.Functions.ResourceLoad(Path.GetFullPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!) + "/de.cantorgymnasium.Photomator.gresource")); Gio.Functions.ResourcesRegister(Gio.Functions.ResourceLoad(Path.GetFullPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!) + "/de.cantorgymnasium.Photomator.gresource"));
} else {
else
{
var prefixes = new List<string> { var prefixes = new List<string> {
Directory.GetParent(Directory.GetParent(Path.GetFullPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!))!.FullName)!.FullName, Directory.GetParent(Directory.GetParent(Path.GetFullPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!))!.FullName)!.FullName,
Directory.GetParent(Path.GetFullPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!))!.FullName, Directory.GetParent(Path.GetFullPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!))!.FullName,
"/usr" "/usr"
}; };
foreach (var prefix in prefixes) string? prefix = prefixes.Find(prefix => File.Exists(prefix + "/share/de.cantorgymnasium.Photomator/de.cantorgymnasium.Photomator.gresource"));
{ Gio.Functions.ResourcesRegister(Gio.Functions.ResourceLoad(Path.GetFullPath(prefix + "/share/de.cantorgymnasium.Photomator/de.cantorgymnasium.Photomator.gresource")));
if (File.Exists(prefix + "/share/de.cantorgymnasium.Photomator/de.cantorgymnasium.Photomator.gresource"))
{
Gio.Functions.ResourcesRegister(Gio.Functions.ResourceLoad(Path.GetFullPath(prefix + "/share/de.cantorgymnasium.Photomator/de.cantorgymnasium.Photomator.gresource")));
break;
}
}
} }
_application.OnActivate += (_, _) => new MainWindow(_application).Start(); _application.OnActivate += (_, _) => new MainWindow(_application).Start();
} }

@ -1,32 +1,25 @@
using Gtk; using Gtk;
using Adw; using Adw;
using System.Text; using System.Text;
using GLib;
namespace Photomator.Views; namespace Photomator.Views;
public partial class MainWindow : Adw.ApplicationWindow public partial class MainWindow : Adw.ApplicationWindow {
{
private readonly Adw.Application _application; private readonly Adw.Application _application;
public MainWindow(Adw.Application application) : base() public MainWindow(Adw.Application application) : base() {
{
_application = application; _application = application;
SetTitle(AppInfo.ApplicationName); SetTitle(AppInfo.ApplicationName);
SetIconName(AppInfo.IconName); SetIconName(AppInfo.IconName);
PreferencesPage layoutSingle = InitPageSingle(); PreferencesPage pageSingle = InitPageSingle();
PreferencesPage layoutFolder = InitPageFolder(); PreferencesPage pageFolder = InitPageFolder();
ViewStack viewStack = ViewStack.New(); ViewStack viewStack = ViewStack.New();
viewStack.Add(layoutSingle); viewStack.AddTitledWithIcon(pageSingle, "page-single", "Einzelne Datei", "image-x-generic-symbolic");
ViewStackPage pageSingle = viewStack.GetPage(layoutSingle); viewStack.AddTitledWithIcon(pageFolder, "page-folder", "Ordner", "folder-symbolic");
pageSingle.SetTitle("Einzelne Datei");
pageSingle.SetIconName("image-x-generic-symbolic");
viewStack.Add(layoutFolder);
ViewStackPage pageFolder = viewStack.GetPage(layoutFolder);
pageFolder.SetTitle("Ordner");
pageFolder.SetIconName("folder-symbolic");
ViewSwitcher viewSwitcher = ViewSwitcher.New(); ViewSwitcher viewSwitcher = ViewSwitcher.New();
viewSwitcher.SetStack(viewStack); viewSwitcher.SetStack(viewStack);
@ -50,22 +43,20 @@ public partial class MainWindow : Adw.ApplicationWindow
SetContent(view); SetContent(view);
} }
public void Start() public void Start() {
{
_application.AddWindow(this); _application.AddWindow(this);
Present(); Present();
} }
public PreferencesPage InitPageSingle() public PreferencesPage InitPageSingle() {
{
PreferencesPage page = PreferencesPage.New(); PreferencesPage page = PreferencesPage.New();
PreferencesGroup pgSelect = PreferencesGroup.New(); PreferencesGroup pgSource = PreferencesGroup.New();
pgSelect.SetTitle("Bild"); pgSource.SetTitle("Bild");
pgSelect.SetDescription("Als Eingabeformate werden BMP, GIF, JPEG, PBM, PNG, TIFF, TGA und WebP unterstützt."); pgSource.SetDescription("Als Eingabeformate werden BMP, GIF, JPEG, PBM, PNG, TIFF, TGA und WebP unterstützt.");
EntryRow erSelect = EntryRow.New(); EntryRow erSource = EntryRow.New();
erSelect.SetTitle("Zu konvertierendes Bild"); erSource.SetTitle("Zu konvertierendes Bild");
erSelect.SetEditable(false); erSource.SetEditable(false);
PreferencesGroup pgOptions = PreferencesGroup.New(); PreferencesGroup pgOptions = PreferencesGroup.New();
pgOptions.SetTitle("Optionen"); pgOptions.SetTitle("Optionen");
@ -89,8 +80,7 @@ public partial class MainWindow : Adw.ApplicationWindow
pgBtn.SetValign(Align.Center); pgBtn.SetValign(Align.Center);
pgBtn.SetHalign(Align.Center); pgBtn.SetHalign(Align.Center);
Button btnConvert = Button.NewWithLabel("Konvertieren"); Button btnConvert = Button.NewWithLabel("Konvertieren");
btnConvert.OnClicked += async (_, _) => btnConvert.OnClicked += async (_, _) => {
{
FileDialog fileDialog = FileDialog.New(); FileDialog fileDialog = FileDialog.New();
Gio.ListStore listStore = Gio.ListStore.New(FileFilter.GetGType()); Gio.ListStore listStore = Gio.ListStore.New(FileFilter.GetGType());
FileFilter filter = FileFilter.New(); FileFilter filter = FileFilter.New();
@ -100,21 +90,16 @@ public partial class MainWindow : Adw.ApplicationWindow
listStore.Append(filter); listStore.Append(filter);
fileDialog.SetFilters(listStore); fileDialog.SetFilters(listStore);
Gio.File? file; Gio.File? file;
try try {
{
file = await fileDialog.SaveAsync(this); file = await fileDialog.SaveAsync(this);
} } catch {
catch
{
file = null; file = null;
} }
if (file != null && file.GetPath() != null) if (file != null && file.GetPath() != null) {
{
ConvertOptions options = new(resOptions.GetString(crRes.GetSelected()), crFormat.GetSelected()); ConvertOptions options = new(resOptions.GetString(crRes.GetSelected()), crFormat.GetSelected());
await Lib.Convert(erSelect.GetText(), file.GetPath()!, options); await Lib.Convert(erSource.GetText(), file.GetPath()!, options);
} } else
else
InitInfoAlert("Kein Ziel ausgewählt", "Es wurde keine Zieldatei ausgewählt. Konvertierung wird abgebrochen."); InitInfoAlert("Kein Ziel ausgewählt", "Es wurde keine Zieldatei ausgewählt. Konvertierung wird abgebrochen.");
}; };
btnConvert.SetCssClasses(["pill", "suggested-action", "long"]); btnConvert.SetCssClasses(["pill", "suggested-action", "long"]);
@ -125,63 +110,33 @@ public partial class MainWindow : Adw.ApplicationWindow
btnSelect.SetValign(Align.Center); btnSelect.SetValign(Align.Center);
btnSelect.AddCssClass("flat"); btnSelect.AddCssClass("flat");
btnSelect.SetIconName("document-open-symbolic"); btnSelect.SetIconName("document-open-symbolic");
btnSelect.OnClicked += async (_, _) => btnSelect.OnClicked += async (_, _) => {
{
FileDialog fileDialog = FileDialog.New(); FileDialog fileDialog = FileDialog.New();
Gio.ListStore listStore = Gio.ListStore.New(FileFilter.GetGType()); fileDialog.SetFilters(GetSourceFileFilter());
FileFilter filterAll = FileFilter.New();
filterAll.SetName("Alle unterstützten Bildformate");
string[][] formats = [["bmp", "dib"], ["gif"], ["jpeg", "jpg", "jpe", "jfif"], ["pbm"], ["png"], ["tiff", "tif"], ["tga", "bpx", "icb", "pix"], ["webp"]];
foreach (string[] format in formats)
{
FileFilter filter = FileFilter.New();
StringBuilder name = new($"{format[0].ToUpper()} (");
for (int i = 0; i < format.Length; i++)
{
name.Append($"*.{format[i]}");
if (i != format.Length - 1)
name.Append(", ");
filter.AddPattern($"*.{format[i]}");
filterAll.AddPattern($"*.{format[i]}");
filter.AddPattern($"*.{format[i].ToUpper()}");
filterAll.AddPattern($"*.{format[i].ToUpper()}");
}
name.Append(')');
filter.SetName(name.ToString());
listStore.Append(filter);
}
listStore.Insert(0, filterAll);
fileDialog.SetFilters(listStore);
Gio.File? file; Gio.File? file;
try try {
{
file = await fileDialog.OpenAsync(this); file = await fileDialog.OpenAsync(this);
} } catch {
catch
{
file = null; file = null;
} }
if (file != null && file.GetPath() != null) if (file != null && file.GetPath() != null) {
{ erSource.SetText(file.GetPath()!);
erSelect.SetText(file.GetPath()!);
btnConvert.SetSensitive(true); btnConvert.SetSensitive(true);
} } else if (erSource.GetText() == "")
else if (erSelect.GetText() == "")
btnConvert.SetSensitive(false); btnConvert.SetSensitive(false);
}; };
erSelect.AddSuffix(btnSelect); erSource.AddSuffix(btnSelect);
pgSelect.Add(erSelect); pgSource.Add(erSource);
page.Add(pgSelect); page.Add(pgSource);
page.Add(pgOptions); page.Add(pgOptions);
page.Add(pgBtn); page.Add(pgBtn);
return page; return page;
} }
public PreferencesPage InitPageFolder() public PreferencesPage InitPageFolder() {
{
EntryRow erSource = EntryRow.New(); EntryRow erSource = EntryRow.New();
erSource.SetTitle("Quellordner"); erSource.SetTitle("Quellordner");
erSource.SetEditable(false); erSource.SetEditable(false);
@ -212,96 +167,44 @@ public partial class MainWindow : Adw.ApplicationWindow
pgBtn.SetValign(Align.Center); pgBtn.SetValign(Align.Center);
pgBtn.SetHalign(Align.Center); pgBtn.SetHalign(Align.Center);
Button btnConvert = Button.NewWithLabel("Konvertieren"); Button btnConvert = Button.NewWithLabel("Konvertieren");
btnConvert.OnClicked += async (_, _) => btnConvert.OnClicked += async (_, _) => {
{ string[] filesSource;
if (erSource.GetText() != "" && erDest.GetText() != "") if (Directory.Exists(erSource.GetText()))
{ filesSource = Directory.GetFiles(erSource.GetText());
string[] filesSource; else {
if (Directory.Exists(erSource.GetText())) InitInfoAlert("Quellordner existiert nicht", "Der ausgewählte Quellordner ist nicht im Dateisystem vorhanden. Die Konvertierung wurde abgebrochen.");
filesSource = Directory.GetFiles(erSource.GetText()); return;
}
if (filesSource.Length == 0) {
InitInfoAlert("Quellordner ist leer", "Im ausgewählten Quellordner befinden sich keine Dateien. Die Konvertierung wurde abgebrochen.");
return;
}
string dest = erDest.GetText();
Directory.CreateDirectory(dest);
StatusDialog statusDialog = new(_application, this);
statusDialog.Start();
try {
ConvertOptions options = new(resOptions.GetString(crRes.GetSelected()), crFormat.GetSelected());
ConvertError[] convertErrors = await Lib.ConvertList(filesSource, dest, options, statusDialog.SetProgress);
if (convertErrors.Length > 0)
statusDialog.Partial(filesSource.Length, dest, convertErrors);
else else
{ statusDialog.Success(filesSource.Length, dest);
InitInfoAlert("Quellordner existiert nicht", "Der ausgewählte Quellordner ist nicht im Dateisystem vorhanden. Die Konvertierung wurde abgebrochen."); } catch (Exception e) {
return; statusDialog.Error(e.Message);
}
if (filesSource.Length == 0)
{
InitInfoAlert("Quellordner ist leer", "Im ausgewählten Quellordner befinden sich keine Dateien. Die Konvertierung wurde abgebrochen.");
return;
}
string dest = erDest.GetText();
if (!Directory.Exists(dest))
Directory.CreateDirectory(dest);
StatusDialog statusDialog = new(_application, this);
statusDialog.Start();
try
{
ConvertOptions options = new ConvertOptions(resOptions.GetString(crRes.GetSelected()), crFormat.GetSelected());
ConvertError[] convertErrors = await Lib.ConvertList(filesSource, dest, options, statusDialog.SetProgress);
if (convertErrors.Length > 0)
statusDialog.Partial(filesSource.Length, dest, convertErrors);
else
statusDialog.Success(filesSource.Length, dest);
}
catch (Exception e)
{
statusDialog.Error(e.Message);
}
} }
}; };
btnConvert.SetCssClasses(["pill", "suggested-action", "long"]); btnConvert.SetCssClasses(["pill", "suggested-action", "long"]);
btnConvert.SetSensitive(false); btnConvert.SetSensitive(false);
pgBtn.Add(btnConvert); pgBtn.Add(btnConvert);
void checkButtonState() void checkButtonState() {
{
if (erSource.GetText() != "" && erDest.GetText() != "") btnConvert.SetSensitive(true); if (erSource.GetText() != "" && erDest.GetText() != "") btnConvert.SetSensitive(true);
else btnConvert.SetSensitive(false); else btnConvert.SetSensitive(false);
} }
Button btnSource = Button.New(); erSource.AddSuffix(InitButtonSelectFolder(erSource, checkButtonState));
btnSource.SetValign(Align.Center); erDest.AddSuffix(InitButtonSelectFolder(erDest, checkButtonState));
btnSource.AddCssClass("flat");
btnSource.SetIconName("document-open-symbolic");
btnSource.OnClicked += async (_, _) =>
{
FileDialog fileDialog = FileDialog.New();
Gio.File? file;
try
{
file = await fileDialog.SelectFolderAsync(this);
}
catch
{
file = null;
}
if (file != null && file.GetPath() != null)
erSource.SetText(file.GetPath()!);
checkButtonState();
};
erSource.AddSuffix(btnSource);
Button btnDest = Button.New();
btnDest.SetValign(Align.Center);
btnDest.AddCssClass("flat");
btnDest.SetIconName("document-open-symbolic");
btnDest.OnClicked += async (_, _) =>
{
FileDialog fileDialog = FileDialog.New();
Gio.File? file;
try
{
file = await fileDialog.SelectFolderAsync(this);
}
catch
{
file = null;
}
if (file != null && file.GetPath() != null)
erDest.SetText(file.GetPath()!);
checkButtonState();
};
erDest.AddSuffix(btnDest);
PreferencesPage page = PreferencesPage.New(); PreferencesPage page = PreferencesPage.New();
@ -317,8 +220,7 @@ public partial class MainWindow : Adw.ApplicationWindow
return page; return page;
} }
public void InitInfoAlert(string title, string body) public void InitInfoAlert(string title, string body) {
{
Adw.AlertDialog alert = Adw.AlertDialog.New(title, body); Adw.AlertDialog alert = Adw.AlertDialog.New(title, body);
alert.AddResponse("ok", "OK"); alert.AddResponse("ok", "OK");
alert.SetResponseAppearance("ok", ResponseAppearance.Suggested); alert.SetResponseAppearance("ok", ResponseAppearance.Suggested);
@ -327,37 +229,7 @@ public partial class MainWindow : Adw.ApplicationWindow
alert.Present(this); alert.Present(this);
} }
public bool InitDestructiveAlert(string title, string body, string resp) public static Adw.AboutDialog InitAboutDialog() {
{
Adw.AlertDialog alert = Adw.AlertDialog.New(title, body);
alert.AddResponse("cancel", "Abbrechen");
alert.AddResponse(resp.ToLower(), resp);
alert.SetResponseAppearance(resp.ToLower(), ResponseAppearance.Destructive);
alert.SetDefaultResponse("cancel");
alert.SetCloseResponse("cancel");
bool running = true;
bool response = false;
alert.OnResponse += (Adw.AlertDialog _, Adw.AlertDialog.ResponseSignalArgs args) =>
{
if (args.Response.Equals(resp, StringComparison.CurrentCultureIgnoreCase))
{
response = true;
}
running = false;
};
alert.Present(this);
while (running == true)
{
}
return response;
}
public Adw.AboutDialog InitAboutDialog()
{
Adw.AboutDialog aboutDialog = Adw.AboutDialog.New(); Adw.AboutDialog aboutDialog = Adw.AboutDialog.New();
aboutDialog.SetApplicationName(AppInfo.ApplicationName); aboutDialog.SetApplicationName(AppInfo.ApplicationName);
aboutDialog.SetDeveloperName(AppInfo.DeveloperName); aboutDialog.SetDeveloperName(AppInfo.DeveloperName);
@ -371,4 +243,51 @@ public partial class MainWindow : Adw.ApplicationWindow
return aboutDialog; return aboutDialog;
} }
public Button InitButtonSelectFolder(EntryRow entryRow, VoidFunc checkButtonState) {
Button btnSelect = Button.New();
btnSelect.SetValign(Align.Center);
btnSelect.AddCssClass("flat");
btnSelect.SetIconName("document-open-symbolic");
btnSelect.OnClicked += async (_, _) => {
FileDialog fileDialog = FileDialog.New();
Gio.File? file;
try {
file = await fileDialog.SelectFolderAsync(this);
} catch {
file = null;
}
if (file != null && file.GetPath() != null)
entryRow.SetText(file.GetPath()!);
checkButtonState();
};
return btnSelect;
}
public static Gio.ListStore GetSourceFileFilter() {
Gio.ListStore listStore = Gio.ListStore.New(FileFilter.GetGType());
FileFilter filterAll = FileFilter.New();
filterAll.SetName("Alle unterstützten Bildformate");
string[][] formats = [["bmp", "dib"], ["gif"], ["jpeg", "jpg", "jpe", "jfif"], ["pbm"], ["png"], ["tiff", "tif"], ["tga", "bpx", "icb", "pix"], ["webp"]];
foreach (string[] format in formats) {
FileFilter filter = FileFilter.New();
StringBuilder name = new($"{format[0].ToUpper()} (");
for (int i = 0; i < format.Length; i++) {
name.Append($"*.{format[i]}");
if (i != format.Length - 1)
name.Append(", ");
filter.AddPattern($"*.{format[i]}");
filterAll.AddPattern($"*.{format[i]}");
filter.AddPattern($"*.{format[i].ToUpper()}");
filterAll.AddPattern($"*.{format[i].ToUpper()}");
}
name.Append(')');
filter.SetName(name.ToString());
listStore.Append(filter);
}
listStore.Insert(0, filterAll);
return listStore;
}
} }

@ -4,15 +4,13 @@ using System.Text;
namespace Photomator.Views; namespace Photomator.Views;
public partial class StatusDialog : Adw.Window public partial class StatusDialog : Adw.Window {
{
private readonly Adw.Application _application; private readonly Adw.Application _application;
private readonly Adw.ApplicationWindow _mainWindow; private readonly Adw.ApplicationWindow _mainWindow;
private readonly ViewStack _stack; private readonly ViewStack _stack;
private readonly ProgressBar _progress; private readonly ProgressBar _progress;
public StatusDialog(Adw.Application application, Adw.ApplicationWindow parent) : base() public StatusDialog(Adw.Application application, Adw.ApplicationWindow parent) : base() {
{
_application = application; _application = application;
_mainWindow = parent; _mainWindow = parent;
_progress = InitProgressBar(); _progress = InitProgressBar();
@ -27,18 +25,17 @@ public partial class StatusDialog : Adw.Window
StatusPage pageStatus = InitPageProgress(); StatusPage pageStatus = InitPageProgress();
_stack.AddNamed(pageStatus, "page-status"); _stack.AddNamed(pageStatus, "page-status");
_stack.SetChildVisible(true);
SetContent(_stack); SetContent(_stack);
} }
public void Start() public void Start() {
{
_application.AddWindow(this); _application.AddWindow(this);
Present(); Present();
} }
private StatusPage InitPageProgress() private StatusPage InitPageProgress() {
{
StatusPage pageStatus = StatusPage.New(); StatusPage pageStatus = StatusPage.New();
pageStatus.SetTitle("Konvertierung wird ausgeführt..."); pageStatus.SetTitle("Konvertierung wird ausgeführt...");
pageStatus.SetDescription("Das kann eine Weile dauern."); pageStatus.SetDescription("Das kann eine Weile dauern.");
@ -47,8 +44,7 @@ public partial class StatusDialog : Adw.Window
return pageStatus; return pageStatus;
} }
private ProgressBar InitProgressBar() private static ProgressBar InitProgressBar() {
{
ProgressBar progressBar = ProgressBar.New(); ProgressBar progressBar = ProgressBar.New();
progressBar.WidthRequest = 300; progressBar.WidthRequest = 300;
progressBar.SetHalign(Align.Center); progressBar.SetHalign(Align.Center);
@ -62,22 +58,19 @@ public partial class StatusDialog : Adw.Window
return progressBar; return progressBar;
} }
public void SetProgress(double progress) public void SetProgress(double progress) {
{
_progress.SetFraction(progress); _progress.SetFraction(progress);
_progress.SetText(string.Format("{0:p0}", progress)); _progress.SetText(string.Format("{0:p0}", progress));
} }
private StatusPage InitPageSuccess(int number, string dest) private StatusPage InitPageSuccess(int number, string dest) {
{
StatusPage pageStatus = StatusPage.New(); StatusPage pageStatus = StatusPage.New();
pageStatus.SetTitle("Die Konvertierung wurde erfolgreich abgeschlossen"); pageStatus.SetTitle("Die Konvertierung wurde erfolgreich abgeschlossen");
pageStatus.SetDescription($"{number} Dateien wurden erfolgreich konvertiert."); pageStatus.SetDescription($"{number} Dateien wurden erfolgreich konvertiert.");
pageStatus.SetIconName("selection-mode-symbolic"); pageStatus.SetIconName("selection-mode-symbolic");
Button btnOpen = Button.NewWithLabel("Ordner öffnen"); Button btnOpen = Button.NewWithLabel("Ordner öffnen");
btnOpen.OnClicked += async (_, _) => btnOpen.OnClicked += async (_, _) => {
{
FileLauncher fileLauncher = FileLauncher.New(Gio.FileHelper.NewForPath(dest)); FileLauncher fileLauncher = FileLauncher.New(Gio.FileHelper.NewForPath(dest));
await fileLauncher.LaunchAsync(_mainWindow); await fileLauncher.LaunchAsync(_mainWindow);
Close(); Close();
@ -90,15 +83,14 @@ public partial class StatusDialog : Adw.Window
return pageStatus; return pageStatus;
} }
public void Success(int number, string dest) public void Success(int number, string dest) {
{
StatusPage pageSuccess = InitPageSuccess(number, dest); StatusPage pageSuccess = InitPageSuccess(number, dest);
_stack.AddNamed(pageSuccess, "page-success"); _stack.AddNamed(pageSuccess, "page-success");
_stack.SetVisibleChildName("page-success"); _stack.SetVisibleChildName("page-success");
_stack.SetChildVisible(true);
} }
private StatusPage InitPagePartial(int number, string dest, ConvertError[] convertErrors) private StatusPage InitPagePartial(int number, string dest, ConvertError[] convertErrors) {
{
StatusPage pageStatus = StatusPage.New(); StatusPage pageStatus = StatusPage.New();
pageStatus.SetTitle("Bei der Konvertierung sind Fehler aufgetreten"); pageStatus.SetTitle("Bei der Konvertierung sind Fehler aufgetreten");
pageStatus.SetDescription($"{number - convertErrors.Length} von {number} Dateien wurden erfolgreich konvertiert."); pageStatus.SetDescription($"{number - convertErrors.Length} von {number} Dateien wurden erfolgreich konvertiert.");
@ -107,11 +99,9 @@ public partial class StatusDialog : Adw.Window
Box box = Box.New(Orientation.Vertical, 36); Box box = Box.New(Orientation.Vertical, 36);
box.SetHalign(Align.Center); box.SetHalign(Align.Center);
if (convertErrors.Length < number) if (convertErrors.Length < number) {
{
Button btnOpen = Button.NewWithLabel("Ordner öffnen"); Button btnOpen = Button.NewWithLabel("Ordner öffnen");
btnOpen.OnClicked += async (_, _) => btnOpen.OnClicked += async (_, _) => {
{
FileLauncher fileLauncher = FileLauncher.New(Gio.FileHelper.NewForPath(dest)); FileLauncher fileLauncher = FileLauncher.New(Gio.FileHelper.NewForPath(dest));
await fileLauncher.LaunchAsync(_mainWindow); await fileLauncher.LaunchAsync(_mainWindow);
Close(); Close();
@ -128,8 +118,7 @@ public partial class StatusDialog : Adw.Window
scrolled.SetOverflow(Overflow.Hidden); scrolled.SetOverflow(Overflow.Hidden);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
foreach (ConvertError err in convertErrors) foreach (ConvertError err in convertErrors) {
{
sb.AppendLine($"{err.File}: {err.Message}"); sb.AppendLine($"{err.File}: {err.Message}");
} }
Label label = Label.New(sb.ToString()); Label label = Label.New(sb.ToString());
@ -155,15 +144,14 @@ public partial class StatusDialog : Adw.Window
return pageStatus; return pageStatus;
} }
public void Partial(int number, string dest, ConvertError[] convertErrors) public void Partial(int number, string dest, ConvertError[] convertErrors) {
{
StatusPage pagePartial = InitPagePartial(number, dest, convertErrors); StatusPage pagePartial = InitPagePartial(number, dest, convertErrors);
_stack.AddNamed(pagePartial, "page-partial"); _stack.AddNamed(pagePartial, "page-partial");
_stack.SetVisibleChildName("page-partial"); _stack.SetVisibleChildName("page-partial");
_stack.SetChildVisible(true);
} }
private StatusPage InitPageError(string error) private StatusPage InitPageError(string error) {
{
StatusPage pageStatus = StatusPage.New(); StatusPage pageStatus = StatusPage.New();
pageStatus.SetTitle("Konvertierung fehlgeschlagen"); pageStatus.SetTitle("Konvertierung fehlgeschlagen");
pageStatus.SetDescription("Es ist ein Fehler aufgetreten."); pageStatus.SetDescription("Es ist ein Fehler aufgetreten.");
@ -206,10 +194,10 @@ public partial class StatusDialog : Adw.Window
return pageStatus; return pageStatus;
} }
public void Error(string error) public void Error(string error) {
{
StatusPage pageError = InitPageError(error); StatusPage pageError = InitPageError(error);
_stack.AddNamed(pageError, "page-error"); _stack.AddNamed(pageError, "page-error");
_stack.SetVisibleChildName("page-error"); _stack.SetVisibleChildName("page-error");
_stack.SetChildVisible(true);
} }
} }