Compare commits
7 Commits
5f1c8d8a55
...
main
Author | SHA1 | Date | |
---|---|---|---|
66a92e6838 | |||
088637ff5d | |||
23dc2d75e0 | |||
2a7a7b01cf | |||
a299ec043b | |||
a115f37c95 | |||
4bd93fa87e |
6
.editorconfig
Normal file
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
.gitignore
vendored
1
.gitignore
vendored
@ -3,6 +3,7 @@
|
|||||||
project.lock.json
|
project.lock.json
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.pyc
|
*.pyc
|
||||||
|
*.exe
|
||||||
nupkg/
|
nupkg/
|
||||||
|
|
||||||
# Visual Studio Code
|
# Visual Studio Code
|
||||||
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Denys Konovalov
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -1,10 +1,11 @@
|
|||||||
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;
|
||||||
<p><em>0.0.1</em></p>
|
public static readonly string ReleaseNotes = @"
|
||||||
|
<p><em>v0.0.1</em></p>
|
||||||
<p>Initial release</p>
|
<p>Initial release</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>single-file and folder conversions</li>
|
<li>single-file and folder conversions</li>
|
||||||
@ -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;
|
||||||
}
|
}
|
@ -1,15 +1,17 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<SelfContained>true</SelfContained>
|
||||||
|
<ApplicationIcon>Resources\de.cantorgymnasium.Photomator.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="GirCore.Adw-1" Version="0.5.0" />
|
<PackageReference Include="GirCore.Adw-1" Version="0.5.0" />
|
||||||
<PackageReference Include="GitInfo" Version="3.3.5">
|
<PackageReference Include="GitInfo" Version="3.5.0">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
@ -17,8 +19,33 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
||||||
<Exec Command="echo Compiling extra resources..." />
|
<Message Text="=== Building Photomator $(GitTag)... ===" Importance="high" />
|
||||||
|
<RemoveDir Directories="$(PublishDir)" />
|
||||||
|
<Message Text="=== Compiling extra resources... ===" Importance="high" />
|
||||||
<Exec Command="glib-compile-resources --sourcedir ./Resources ./Resources/de.cantorgymnasium.Photomator.gresource.xml --target=$(OutDir)/de.cantorgymnasium.Photomator.gresource" />
|
<Exec Command="glib-compile-resources --sourcedir ./Resources ./Resources/de.cantorgymnasium.Photomator.gresource.xml --target=$(OutDir)/de.cantorgymnasium.Photomator.gresource" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="CopyFiles" AfterTargets="Publish">
|
||||||
|
<ItemGroup>
|
||||||
|
<SourceFiles Include="$(PublishDir)\**\*.*" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Move SourceFiles="@(SourceFiles)" DestinationFolder="$(PublishDir)\bin" />
|
||||||
|
<Copy SourceFiles="$(OutDir)/de.cantorgymnasium.Photomator.gresource" DestinationFolder="$(PublishDir)\share\de.cantorgymnasium.Photomator" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="CopyFilesWindows" AfterTargets="Publish" Condition="'$(RuntimeIdentifier)' == 'win-x64'">
|
||||||
|
<Message Text="=== Copying Gtk files for win-x64 runtime ... ===" Importance="high"/>
|
||||||
|
<ItemGroup>
|
||||||
|
|
||||||
|
<GtkDlls Include="libgtk-4-1.dll;libadwaita-1-0.dll;libappstream-5.dll;libbrotlicommon.dll;libbrotlidec.dll;libbz2-1.dll;libcairo-2.dll;libcairo-gobject-2.dll;libcairo-script-interpreter-2.dll;libcrypto-3-x64.dll;libcurl-4.dll;libdatrie-1.dll;libdeflate.dll;libepoxy-0.dll;libexpat-1.dll;libffi-8.dll;libfontconfig-1.dll;libfreetype-6.dll;libfribidi-0.dll;libgcc_s_seh-1.dll;libgdk_pixbuf-2.0-0.dll;libgio-2.0-0.dll;libglib-2.0-0.dll;libgmodule-2.0-0.dll;libgobject-2.0-0.dll;libgraphene-1.0-0.dll;libgraphite2.dll;libharfbuzz-0.dll;libharfbuzz-gobject-0.dll;libiconv-2.dll;libidn2-0.dll;libintl-8.dll;libjbig-0.dll;libjpeg-8.dll;libLerc.dll;liblzma-5.dll;liblzo2-2.dll;libnghttp2-14.dll;libnghttp3-9.dll;libpango-1.0-0.dll;libpangocairo-1.0-0.dll;libpangoft2-1.0-0.dll;libpangowin32-1.0-0.dll;libpcre2-8-0.dll;libpixman-1-0.dll;libpng16-16.dll;libpsl-5.dll;librsvg-2-2.dll;libsharpyuv-0.dll;libssh2-1.dll;libssl-3-x64.dll;libstdc++-6.dll;libthai-0.dll;libtiff-6.dll;libunistring-5.dll;libwebp-7.dll;libwinpthread-1.dll;libxml2-2.dll;libxmlb-2.dll;libyaml-0-2.dll;libzstd.dll;zlib1.dll;gdbus.exe"/>
|
||||||
|
<Icons Include="C:\msys64\mingw64\share\icons\**\*.*" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Copy SourceFiles="@(GtkDlls->'C:\msys64\mingw64\bin\%(Filename)%(Extension)')" DestinationFolder="$(PublishDir)\bin" />
|
||||||
|
<Copy SourceFiles="C:\msys64\mingw64\lib\gdk-pixbuf-2.0\2.10.0\loaders\libpixbufloader-svg.dll" DestinationFolder="$(PublishDir)\lib\gdk-pixbuf-2.0\2.10.0\loaders" />
|
||||||
|
<Copy SourceFiles=".\Resources\loaders.cache" DestinationFolder="$(PublishDir)\lib\gdk-pixbuf-2.0\2.10.0" />
|
||||||
|
<Copy SourceFiles="C:\msys64\mingw64\share\glib-2.0\schemas\gschemas.compiled" DestinationFolder="$(PublishDir)\share\glib-2.0\schemas" />
|
||||||
|
<Copy SourceFiles="@(Icons)" DestinationFolder="$(PublishDir)\share\icons\%(RecursiveDir)" />
|
||||||
|
<Message Text="=== Building Windows installer ... ===" Importance="high"/>
|
||||||
|
<Exec Command='"C:\Program Files (x86)\Inno Setup 6\ISCC.exe" Resources\Photomator.iss -DMyAppVersion=$(GitTag)' />
|
||||||
|
</Target>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -3,37 +3,28 @@ 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"))
|
string localPath = Path.GetFullPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!) + "/de.cantorgymnasium.Photomator.gresource";
|
||||||
{
|
if (File.Exists(localPath))
|
||||||
Gio.Functions.ResourcesRegister(Gio.Functions.ResourceLoad(Path.GetFullPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!) + "/de.cantorgymnasium.Photomator.gresource"));
|
Gio.Functions.ResourcesRegister(Gio.Functions.ResourceLoad(localPath));
|
||||||
}
|
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"));
|
||||||
{
|
if (prefix != null)
|
||||||
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")));
|
||||||
{
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
65
Photomator/Resources/Photomator.iss
Normal file
65
Photomator/Resources/Photomator.iss
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
; Script generated by the Inno Setup Script Wizard.
|
||||||
|
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
||||||
|
|
||||||
|
#define MyAppName "Photomator"
|
||||||
|
|
||||||
|
#ifndef MyAppVersion
|
||||||
|
#define MyAppVersion "v0.0.0-dev"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MyAppPublisher "Georg-Cantor-Gymnasium Halle (Saale)"
|
||||||
|
#define MyAppURL "https://git.cantorgymnasium.de/gcg/photomator/"
|
||||||
|
#define MyAppSupportURL "https://git.cantorgymnasium.de/gcg/photomator/issues/"
|
||||||
|
#define MyAppUpdatesURL "https://git.cantorgymnasium.de/gcg/photomator/releases/"
|
||||||
|
#define MyAppExeName "Photomator.exe"
|
||||||
|
|
||||||
|
[Setup]
|
||||||
|
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
|
||||||
|
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
|
||||||
|
AppId={{2F93EA62-DD17-4ACF-87B9-4B80B5217CC4}
|
||||||
|
AppName={#MyAppName}
|
||||||
|
;AppVersion={#MyAppVersion}
|
||||||
|
AppVerName={#MyAppName} {#MyAppVersion}
|
||||||
|
AppPublisher={#MyAppPublisher}
|
||||||
|
AppPublisherURL={#MyAppURL}
|
||||||
|
AppSupportURL={#MyAppSupportURL}
|
||||||
|
AppUpdatesURL={#MyAppUpdatesURL}
|
||||||
|
DefaultDirName={autopf}\{#MyAppName}
|
||||||
|
; "ArchitecturesAllowed=x64compatible" specifies that Setup cannot run
|
||||||
|
; on anything but x64 and Windows 11 on Arm.
|
||||||
|
ArchitecturesAllowed=x64compatible
|
||||||
|
; "ArchitecturesInstallIn64BitMode=x64compatible" requests that the
|
||||||
|
; install be done in "64-bit mode" on x64 or Windows 11 on Arm,
|
||||||
|
; meaning it should use the native 64-bit Program Files directory and
|
||||||
|
; the 64-bit view of the registry.
|
||||||
|
ArchitecturesInstallIn64BitMode=x64compatible
|
||||||
|
DisableProgramGroupPage=yes
|
||||||
|
LicenseFile=..\..\LICENSE
|
||||||
|
; Uncomment the following line to run in non administrative install mode (install for current user only.)
|
||||||
|
;PrivilegesRequired=lowest
|
||||||
|
OutputDir=..\bin\Release\net8.0\win-x64\publish
|
||||||
|
OutputBaseFilename={#MyAppName}-{#MyAppVersion}-win-x64-setup
|
||||||
|
SetupIconFile=de.cantorgymnasium.Photomator.ico
|
||||||
|
Compression=lzma
|
||||||
|
SolidCompression=yes
|
||||||
|
WizardStyle=modern
|
||||||
|
|
||||||
|
[Languages]
|
||||||
|
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
|
||||||
|
|
||||||
|
[Tasks]
|
||||||
|
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||||
|
|
||||||
|
[Files]
|
||||||
|
Source: "..\bin\Release\net8.0\win-x64\publish\bin\*"; DestDir: "{app}\bin"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||||
|
Source: "..\bin\Release\net8.0\win-x64\publish\lib\*"; DestDir: "{app}\lib"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||||
|
Source: "..\bin\Release\net8.0\win-x64\publish\share\*"; DestDir: "{app}\share"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||||
|
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
||||||
|
|
||||||
|
[Icons]
|
||||||
|
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\bin\{#MyAppExeName}"
|
||||||
|
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\bin\{#MyAppExeName}"; Tasks: desktopicon
|
||||||
|
|
||||||
|
[Run]
|
||||||
|
Filename: "{app}\bin\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
||||||
|
|
BIN
Photomator/Resources/de.cantorgymnasium.Photomator.ico
Normal file
BIN
Photomator/Resources/de.cantorgymnasium.Photomator.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
7
Photomator/Resources/loaders.cache
Normal file
7
Photomator/Resources/loaders.cache
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
"lib\\gdk-pixbuf-2.0\\2.10.0\\loaders\\libpixbufloader-svg.dll"
|
||||||
|
"svg" 6 "gdk-pixbuf" "Scalable Vector Graphics" "LGPL"
|
||||||
|
"image/svg+xml" "image/svg" "image/svg-xml" "image/vnd.adobe.svg+xml" "text/xml-svg" "image/svg+xml-compressed" ""
|
||||||
|
"svg" "svgz" "svg.gz" ""
|
||||||
|
" <svg" "* " 100
|
||||||
|
" <!DOCTYPE svg" "* " 100
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,18 +1,17 @@
|
|||||||
using Gtk;
|
using Gtk;
|
||||||
using Adw;
|
using Adw;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
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 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();
|
||||||
@ -22,23 +21,16 @@ public partial class StatusDialog : Adw.Window
|
|||||||
SetDeletable(true);
|
SetDeletable(true);
|
||||||
SetDefaultSize(400, 500);
|
SetDefaultSize(400, 500);
|
||||||
|
|
||||||
_stack = ViewStack.New();
|
|
||||||
_stack.SetVexpand(true);
|
|
||||||
|
|
||||||
StatusPage pageStatus = InitPageProgress();
|
StatusPage pageStatus = InitPageProgress();
|
||||||
_stack.AddNamed(pageStatus, "page-status");
|
SetContent(pageStatus);
|
||||||
|
|
||||||
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 +39,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,24 +53,26 @@ 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 (_, _) => {
|
||||||
{
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
|
||||||
FileLauncher fileLauncher = FileLauncher.New(Gio.FileHelper.NewForPath(dest));
|
FileLauncher fileLauncher = FileLauncher.New(Gio.FileHelper.NewForPath(dest));
|
||||||
await fileLauncher.LaunchAsync(_mainWindow);
|
await fileLauncher.LaunchAsync(_mainWindow);
|
||||||
|
} else {
|
||||||
|
Process.Start("explorer.exe", @$"{dest}");
|
||||||
|
}
|
||||||
|
|
||||||
Close();
|
Close();
|
||||||
};
|
};
|
||||||
btnOpen.SetCssClasses(["pill", "suggested-action"]);
|
btnOpen.SetCssClasses(["pill", "suggested-action"]);
|
||||||
@ -90,15 +83,12 @@ 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");
|
SetContent(pageSuccess);
|
||||||
_stack.SetVisibleChildName("page-success");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,13 +97,16 @@ 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 (_, _) => {
|
||||||
{
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
|
||||||
FileLauncher fileLauncher = FileLauncher.New(Gio.FileHelper.NewForPath(dest));
|
FileLauncher fileLauncher = FileLauncher.New(Gio.FileHelper.NewForPath(dest));
|
||||||
await fileLauncher.LaunchAsync(_mainWindow);
|
await fileLauncher.LaunchAsync(_mainWindow);
|
||||||
|
} else {
|
||||||
|
Process.Start("explorer.exe", @$"{dest}");
|
||||||
|
}
|
||||||
|
|
||||||
Close();
|
Close();
|
||||||
};
|
};
|
||||||
btnOpen.SetCssClasses(["pill", "suggested-action"]);
|
btnOpen.SetCssClasses(["pill", "suggested-action"]);
|
||||||
@ -128,8 +121,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 +147,12 @@ 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");
|
SetContent(pagePartial);
|
||||||
_stack.SetVisibleChildName("page-partial");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 +195,8 @@ 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");
|
SetContent(pageError);
|
||||||
_stack.SetVisibleChildName("page-error");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
20
README.md
20
README.md
@ -1,3 +1,23 @@
|
|||||||
# Photomator
|
# Photomator
|
||||||
|
|
||||||
Desktop-Anwendung zum Konvertieren und Schrumpfen von Bildern für die Verwendung im Web.
|
Desktop-Anwendung zum Konvertieren und Schrumpfen von Bildern für die Verwendung im Web.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
- install msys2 (mingw-w64) -> libadwaita, gtk4, libwebp
|
||||||
|
- install .NET 8.0
|
||||||
|
- install Git for Windows
|
||||||
|
- add .NET 8.0 and mingw-w64 to PATH
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git clone https://git.cantorgymnasium.de/gcg/photomator
|
||||||
|
|
||||||
|
cd photomator/Photomator
|
||||||
|
|
||||||
|
dotnet restore
|
||||||
|
dotnet publish -r win-x64
|
||||||
|
```
|
||||||
|
|
||||||
|
The installer will be located under `Photomator\bin\Release\net8.0\win-x64\publish`.
|
||||||
|
3
renovate.json
Normal file
3
renovate.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user