Compare commits
5 Commits
1d3064904a
...
bd2e388fd0
| Author | SHA1 | Date | |
|---|---|---|---|
| bd2e388fd0 | |||
| 857b06655f | |||
| 6740835be7 | |||
| 3a3c780c07 | |||
| 074f3ccb7f |
@ -2,6 +2,5 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using System.Windows;
|
using System.IO;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
using CamBooth.App.Core.AppSettings;
|
using CamBooth.App.Core.AppSettings;
|
||||||
using CamBooth.App.Core.Logging;
|
using CamBooth.App.Core.Logging;
|
||||||
@ -25,31 +26,65 @@ public partial class App : Application
|
|||||||
base.OnStartup(e);
|
base.OnStartup(e);
|
||||||
|
|
||||||
var services = new ServiceCollection();
|
var services = new ServiceCollection();
|
||||||
ConfigureServices(services);
|
|
||||||
|
// Register base services
|
||||||
|
services.AddSingleton<Logger>();
|
||||||
|
services.AddSingleton<AppSettingsService>();
|
||||||
|
services.AddSingleton<PictureGalleryService>();
|
||||||
|
services.AddSingleton<CameraService>();
|
||||||
|
|
||||||
|
// Zuerst den Provider bauen, um AppSettings zu laden
|
||||||
|
var tempProvider = services.BuildServiceProvider();
|
||||||
|
var appSettings = tempProvider.GetRequiredService<AppSettingsService>();
|
||||||
|
var logger = tempProvider.GetRequiredService<Logger>();
|
||||||
|
|
||||||
|
// Stelle sicher, dass das PictureLocation-Verzeichnis existiert
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(appSettings.PictureLocation))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(appSettings.PictureLocation);
|
||||||
|
logger.Info($"Picture directory created: {appSettings.PictureLocation}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error($"Failed to create picture directory: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jetzt die Camera Services basierend auf AppSettings registrieren
|
||||||
|
// Mit Try-Catch für fehlende DLL-Abhängigkeiten
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (appSettings.UseMockCamera)
|
||||||
|
{
|
||||||
|
services.AddSingleton<ICanonAPI, CanonAPIMock>();
|
||||||
|
services.AddSingleton<ICamera, CameraMock>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
services.AddSingleton<ICanonAPI, CanonAPI>();
|
||||||
|
services.AddSingleton<ICamera, Camera>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (DllNotFoundException ex)
|
||||||
|
{
|
||||||
|
// Falls EDSDK DLL nicht gefunden, fallback auf Mock
|
||||||
|
MessageBox.Show(
|
||||||
|
$"EDSDK konnte nicht geladen werden. Verwende Mock-Kamera.\n\nFehler: {ex.Message}",
|
||||||
|
"DLL nicht gefunden",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Warning);
|
||||||
|
|
||||||
|
services.AddSingleton<ICanonAPI, CanonAPIMock>();
|
||||||
|
services.AddSingleton<ICamera, CameraMock>();
|
||||||
|
}
|
||||||
|
|
||||||
|
services.AddTransient<MainWindow>();
|
||||||
|
|
||||||
_serviceProvider = services.BuildServiceProvider();
|
_serviceProvider = services.BuildServiceProvider();
|
||||||
|
|
||||||
var mainWindow = _serviceProvider.GetRequiredService<MainWindow>();
|
var mainWindow = _serviceProvider.GetRequiredService<MainWindow>();
|
||||||
mainWindow.Show();
|
mainWindow.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void ConfigureServices(IServiceCollection services)
|
|
||||||
{
|
|
||||||
// Register your services and view models here
|
|
||||||
services.AddTransient<MainWindow>();
|
|
||||||
services.AddSingleton<Logger>();
|
|
||||||
services.AddSingleton<AppSettingsService>();
|
|
||||||
services.AddSingleton<PictureGalleryService>();
|
|
||||||
services.AddSingleton<CameraService>();
|
|
||||||
#if DEBUG
|
|
||||||
services.AddSingleton<ICanonAPI, CanonAPIMock>();
|
|
||||||
services.AddSingleton<ICamera, CameraMock>();
|
|
||||||
#else
|
|
||||||
services.AddSingleton<ICanonAPI, CanonAPI>();
|
|
||||||
services.AddSingleton<ICamera, Camera>();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -29,10 +29,16 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Core\Models\" />
|
|
||||||
<Folder Include="Features\" />
|
<Folder Include="Features\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="artifacts\**\*.cs" />
|
||||||
|
<EmbeddedResource Remove="artifacts\**\*" />
|
||||||
|
<None Remove="artifacts\**\*" />
|
||||||
|
<Page Remove="artifacts\**\*.xaml" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="Core\AppSettings\app.settings.json">
|
<None Update="Core\AppSettings\app.settings.json">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
using CamBooth.App.Core.Logging;
|
using CamBooth.App.Core.Logging;
|
||||||
|
|
||||||
namespace CamBooth.App.Core.AppSettings;
|
namespace CamBooth.App.Core.AppSettings;
|
||||||
|
|
||||||
@ -21,18 +21,43 @@ public class AppSettingsService
|
|||||||
|
|
||||||
private void Initialize()
|
private void Initialize()
|
||||||
{
|
{
|
||||||
|
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production";
|
||||||
|
|
||||||
loadedConfigFile = "Core/AppSettings/app.settings.json";
|
loadedConfigFile = "Core/AppSettings/app.settings.json";
|
||||||
#if DEBUG
|
var configBuilder = new ConfigurationBuilder()
|
||||||
loadedConfigFile = "Core/AppSettings/app.settings.dev.json";
|
|
||||||
#endif
|
|
||||||
configuration = new ConfigurationBuilder()
|
|
||||||
.SetBasePath(AppContext.BaseDirectory)
|
.SetBasePath(AppContext.BaseDirectory)
|
||||||
.AddJsonFile(loadedConfigFile, optional: false, reloadOnChange: true)
|
.AddJsonFile(loadedConfigFile, optional: false, reloadOnChange: true);
|
||||||
.Build();
|
|
||||||
|
// Lade umgebungsspezifische Konfigurationsdatei
|
||||||
|
if (environment == "Development")
|
||||||
|
{
|
||||||
|
configBuilder.AddJsonFile("Core/AppSettings/app.settings.dev.json", optional: true, reloadOnChange: true);
|
||||||
|
loadedConfigFile = "Core/AppSettings/app.settings.dev.json";
|
||||||
|
}
|
||||||
|
|
||||||
|
configuration = configBuilder.Build();
|
||||||
|
|
||||||
|
_logger.Info($"Konfiguration geladen aus: {loadedConfigFile} (Environment: {environment})");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsDebugMode => bool.Parse(configuration["AppSettings:IsDebugMode"] ?? "false");
|
||||||
|
|
||||||
public string? AppName => configuration["AppSettings:AppName"];
|
public string? AppName => configuration["AppSettings:AppName"];
|
||||||
|
|
||||||
|
public bool IsDebugConsoleVisible => bool.Parse(configuration["AppSettings:DebugConsoleVisible"] ?? string.Empty);
|
||||||
|
|
||||||
public string? PictureLocation => configuration["AppSettings:PictureLocation"];
|
public string? PictureLocation => configuration["AppSettings:PictureLocation"];
|
||||||
|
|
||||||
|
public int PhotoCountdownSeconds => int.Parse(configuration["AppSettings:PhotoCountdownSeconds"] ?? "5");
|
||||||
|
|
||||||
|
public int FocusDelaySeconds => int.Parse(configuration["AppSettings:FocusDelaySeconds"] ?? "2");
|
||||||
|
|
||||||
|
public int FocusTimeoutMs => int.Parse(configuration["AppSettings:FocusTimeoutMs"] ?? "3000");
|
||||||
|
|
||||||
|
public bool IsShutdownEnabled => bool.Parse(configuration["AppSettings:IsShutdownEnabled"] ?? "false");
|
||||||
|
|
||||||
|
public bool UseMockCamera => bool.Parse(configuration["AppSettings:UseMockCamera"] ?? "false");
|
||||||
|
|
||||||
public string? ConnectionString => configuration.GetConnectionString("DefaultConnection");
|
public string? ConnectionString => configuration.GetConnectionString("DefaultConnection");
|
||||||
|
|
||||||
public string ConfigFileName => loadedConfigFile;
|
public string ConfigFileName => loadedConfigFile;
|
||||||
|
|||||||
@ -2,7 +2,14 @@
|
|||||||
"AppSettings": {
|
"AppSettings": {
|
||||||
"AppName": "Meine Anwendung",
|
"AppName": "Meine Anwendung",
|
||||||
"Version": "1.0.0",
|
"Version": "1.0.0",
|
||||||
"PictureLocation": "C:\\tmp\\cambooth"
|
"IsDebugMode": true,
|
||||||
|
"PictureLocation": "C:\\tmp\\cambooth",
|
||||||
|
"DebugConsoleVisible": "true",
|
||||||
|
"PhotoCountdownSeconds": 2,
|
||||||
|
"FocusDelaySeconds": 1,
|
||||||
|
"FocusTimeoutMs": 1000,
|
||||||
|
"IsShutdownEnabled": false,
|
||||||
|
"UseMockCamera": true
|
||||||
},
|
},
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Server=myServer;Database=myDB;User Id=myUser;Password=myPassword;"
|
"DefaultConnection": "Server=myServer;Database=myDB;User Id=myUser;Password=myPassword;"
|
||||||
|
|||||||
@ -2,7 +2,14 @@
|
|||||||
"AppSettings": {
|
"AppSettings": {
|
||||||
"AppName": "Meine Anwendung",
|
"AppName": "Meine Anwendung",
|
||||||
"Version": "1.0.0",
|
"Version": "1.0.0",
|
||||||
"PictureLocation": "C:\\cambooth\\pictures"
|
"IsDebugMode": false,
|
||||||
|
"PictureLocation": "C:\\cambooth\\pictures",
|
||||||
|
"DebugConsoleVisible": "false",
|
||||||
|
"PhotoCountdownSeconds": 5,
|
||||||
|
"FocusDelaySeconds": 2,
|
||||||
|
"FocusTimeoutMs": 3000,
|
||||||
|
"IsShutdownEnabled": true,
|
||||||
|
"UseMockCamera": true
|
||||||
},
|
},
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Server=myServer;Database=myDB;User Id=myUser;Password=myPassword;"
|
"DefaultConnection": "Server=myServer;Database=myDB;User Id=myUser;Password=myPassword;"
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
using CamBooth.App.Core.AppSettings;
|
using CamBooth.App.Core.AppSettings;
|
||||||
@ -192,6 +193,53 @@ public class CameraService : IDisposable
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public async Task PrepareFocusAsync(int focusTimeoutMs = 1500)
|
||||||
|
{
|
||||||
|
if (this._mainCamera is not EOSDigital.API.Camera sdkCamera)
|
||||||
|
{
|
||||||
|
await Task.Delay(200);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var focusCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
|
||||||
|
void FocusStateChanged(EOSDigital.API.Camera sender, StateEventID eventId, int parameter)
|
||||||
|
{
|
||||||
|
if (eventId == StateEventID.AfResult)
|
||||||
|
{
|
||||||
|
focusCompleted.TrySetResult(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sdkCamera.StateChanged += FocusStateChanged;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Task.Run(() => sdkCamera.SendCommand(CameraCommand.PressShutterButton, (int)ShutterButton.Halfway));
|
||||||
|
var completedTask = await Task.WhenAny(focusCompleted.Task, Task.Delay(focusTimeoutMs));
|
||||||
|
if (completedTask != focusCompleted.Task)
|
||||||
|
{
|
||||||
|
this._logger.Info("Autofocus timeout reached, continuing with countdown.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
this.ReportError(ex.Message);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Task.Run(() => sdkCamera.SendCommand(CameraCommand.PressShutterButton, (int)ShutterButton.OFF));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
this.ReportError(ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
sdkCamera.StateChanged -= FocusStateChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#region API Events
|
#region API Events
|
||||||
@ -269,7 +317,10 @@ public class CameraService : IDisposable
|
|||||||
Info.FileName = $"img_{Guid.NewGuid().ToString()}.jpg";
|
Info.FileName = $"img_{Guid.NewGuid().ToString()}.jpg";
|
||||||
sender.DownloadFile(Info, this._appSettings.PictureLocation);
|
sender.DownloadFile(Info, this._appSettings.PictureLocation);
|
||||||
this._logger.Info("Download complete: " + Path.Combine(this._appSettings.PictureLocation, Info.FileName));
|
this._logger.Info("Download complete: " + Path.Combine(this._appSettings.PictureLocation, Info.FileName));
|
||||||
Application.Current.Dispatcher.Invoke(() => { this._pictureGalleryService.LoadThumbnailsToCache(); });
|
Application.Current.Dispatcher.Invoke(() => {
|
||||||
|
this._pictureGalleryService.IncrementNewPhotoCount();
|
||||||
|
this._pictureGalleryService.LoadThumbnailsToCache();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -291,3 +342,4 @@ public class CameraService : IDisposable
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,6 @@ public partial class DebugConsolePage : Page
|
|||||||
this.InitializeComponent();
|
this.InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void Logger_OnErrorLog(string text)
|
private void Logger_OnErrorLog(string text)
|
||||||
{
|
{
|
||||||
this.tbDebugOutput.Text = this.tbDebugOutput.Text.Insert(0, text + "\n");
|
this.tbDebugOutput.Text = this.tbDebugOutput.Text.Insert(0, text + "\n");
|
||||||
|
|||||||
@ -32,6 +32,11 @@ public partial class LiveViewPage : Page
|
|||||||
this._cameraService = cameraService;
|
this._cameraService = cameraService;
|
||||||
this.InitializeComponent();
|
this.InitializeComponent();
|
||||||
this.SetImageAction = img => { this.bgbrush.ImageSource = img; };
|
this.SetImageAction = img => { this.bgbrush.ImageSource = img; };
|
||||||
|
|
||||||
|
// Mirror the LiveView image horizontally
|
||||||
|
ScaleTransform scaleTransform = new ScaleTransform(-1, 1, 0.5, 0.5);
|
||||||
|
this.bgbrush.Transform = scaleTransform;
|
||||||
|
|
||||||
this.LVCanvas.Background = this.bgbrush;
|
this.LVCanvas.Background = this.bgbrush;
|
||||||
cameraService.ConnectCamera();
|
cameraService.ConnectCamera();
|
||||||
cameraService._mainCamera.LiveViewUpdated += this.MainCamera_OnLiveViewUpdated;
|
cameraService._mainCamera.LiveViewUpdated += this.MainCamera_OnLiveViewUpdated;
|
||||||
|
|||||||
@ -9,7 +9,15 @@
|
|||||||
Background="Black">
|
Background="Black">
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<WrapPanel VerticalAlignment="Stretch" Background="Black" x:Name="PicturesPanel" Orientation="Horizontal" />
|
<ScrollViewer x:Name="GalleryScrollViewer" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Background="Black" CanContentScroll="False">
|
||||||
|
<ItemsControl x:Name="PicturesPanel" Background="Black">
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<WrapPanel Orientation="Horizontal" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
</ItemsControl>
|
||||||
|
</ScrollViewer>
|
||||||
<ContentPresenter x:Name="RootContentDialogPresenter" Grid.Row="0" />
|
<ContentPresenter x:Name="RootContentDialogPresenter" Grid.Row="0" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Page>
|
</Page>
|
||||||
@ -1,4 +1,4 @@
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Documents;
|
using System.Windows.Documents;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
@ -24,6 +24,8 @@ public partial class PictureGalleryPage : Page
|
|||||||
|
|
||||||
private readonly PictureGalleryService _pictureGalleryService;
|
private readonly PictureGalleryService _pictureGalleryService;
|
||||||
|
|
||||||
|
private ContentDialog? _openContentDialog;
|
||||||
|
|
||||||
|
|
||||||
public PictureGalleryPage(AppSettingsService appSettingsService, Logger logger, PictureGalleryService pictureGalleryService)
|
public PictureGalleryPage(AppSettingsService appSettingsService, Logger logger, PictureGalleryService pictureGalleryService)
|
||||||
{
|
{
|
||||||
@ -82,7 +84,7 @@ public partial class PictureGalleryPage : Page
|
|||||||
hyperlink.Inlines.Add(new InlineUIContainer(imageControl));
|
hyperlink.Inlines.Add(new InlineUIContainer(imageControl));
|
||||||
|
|
||||||
textBlock.Inlines.Add(hyperlink);
|
textBlock.Inlines.Add(hyperlink);
|
||||||
this.PicturesPanel.Children.Add(textBlock);
|
this.PicturesPanel.Items.Add(textBlock);
|
||||||
loop++;
|
loop++;
|
||||||
}
|
}
|
||||||
while ((loop < howManyPictures || howManyPictures == 0) && loop < this._pictureGalleryService.ThumbnailsOrderedByNewestDescending.Count);
|
while ((loop < howManyPictures || howManyPictures == 0) && loop < this._pictureGalleryService.ThumbnailsOrderedByNewestDescending.Count);
|
||||||
@ -90,19 +92,52 @@ public partial class PictureGalleryPage : Page
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void CloseOpenDialog()
|
||||||
|
{
|
||||||
|
void CloseDialog()
|
||||||
|
{
|
||||||
|
if (this._openContentDialog is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._openContentDialog.ButtonClicked -= this.ContentDialog_OnButtonClicked;
|
||||||
|
this._openContentDialog.GetType().GetMethod("Hide", Type.EmptyTypes)?.Invoke(this._openContentDialog, null);
|
||||||
|
this.RootContentDialogPresenter.Content = null;
|
||||||
|
this._openContentDialog = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.Dispatcher.CheckAccess())
|
||||||
|
{
|
||||||
|
CloseDialog();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Dispatcher.Invoke(CloseDialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void Hyperlink_OnClick(object sender, RoutedEventArgs e)
|
private void Hyperlink_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
Uri? picturePathUri = ((Hyperlink)sender).Tag as Uri;
|
Uri? picturePathUri = ((Hyperlink)sender).Tag as Uri;
|
||||||
|
if (picturePathUri is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string picturePath = Uri.UnescapeDataString(picturePathUri.AbsolutePath);
|
||||||
Application.Current.Dispatcher.BeginInvoke(
|
Application.Current.Dispatcher.BeginInvoke(
|
||||||
async () =>
|
async () =>
|
||||||
{
|
{
|
||||||
ContentDialog contentDialog = new (this.RootContentDialogPresenter);
|
this.CloseOpenDialog();
|
||||||
|
ContentDialog contentDialog = new(this.RootContentDialogPresenter);
|
||||||
|
this._openContentDialog = contentDialog;
|
||||||
Image imageToShow = new()
|
Image imageToShow = new()
|
||||||
{
|
{
|
||||||
MaxHeight = 570,
|
MaxHeight = 570,
|
||||||
Background = new SolidColorBrush(Colors.White),
|
Background = new SolidColorBrush(Colors.White),
|
||||||
VerticalAlignment = VerticalAlignment.Center,
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
Source = PictureGalleryService.CreateThumbnail(picturePathUri.AbsolutePath, 450, 300)
|
Source = PictureGalleryService.CreateThumbnail(picturePath, 450, 300)
|
||||||
};
|
};
|
||||||
|
|
||||||
contentDialog.VerticalAlignment = VerticalAlignment.Top;
|
contentDialog.VerticalAlignment = VerticalAlignment.Top;
|
||||||
@ -117,10 +152,23 @@ public partial class PictureGalleryPage : Page
|
|||||||
|
|
||||||
// contentDialog.SetCurrentValue(ContentDialog.PrimaryButtonIconProperty, PictureGalleryService.CreateRegularSymbolIcon(SymbolRegular.Print48, Colors.Tomato));
|
// contentDialog.SetCurrentValue(ContentDialog.PrimaryButtonIconProperty, PictureGalleryService.CreateRegularSymbolIcon(SymbolRegular.Print48, Colors.Tomato));
|
||||||
|
|
||||||
contentDialog.Tag = picturePathUri.AbsolutePath;
|
contentDialog.Tag = picturePath;
|
||||||
contentDialog.ButtonClicked += this.ContentDialog_OnButtonClicked;
|
contentDialog.ButtonClicked += this.ContentDialog_OnButtonClicked;
|
||||||
|
|
||||||
await contentDialog.ShowAsync();
|
try
|
||||||
|
{
|
||||||
|
await contentDialog.ShowAsync();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
contentDialog.ButtonClicked -= this.ContentDialog_OnButtonClicked;
|
||||||
|
if (ReferenceEquals(this._openContentDialog, contentDialog))
|
||||||
|
{
|
||||||
|
this._openContentDialog = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
@ -17,6 +17,10 @@ public class PictureGalleryService
|
|||||||
|
|
||||||
private readonly Dictionary<DateTime, BitmapImage> thumbnails = new();
|
private readonly Dictionary<DateTime, BitmapImage> thumbnails = new();
|
||||||
|
|
||||||
|
private int _newPhotoCount = 0;
|
||||||
|
|
||||||
|
public event EventHandler<int>? NewPhotoCountChanged;
|
||||||
|
|
||||||
|
|
||||||
public PictureGalleryService(AppSettingsService appSettings, Logger logger)
|
public PictureGalleryService(AppSettingsService appSettings, Logger logger)
|
||||||
{
|
{
|
||||||
@ -30,6 +34,25 @@ public class PictureGalleryService
|
|||||||
.Select(ordered => ordered.Value)
|
.Select(ordered => ordered.Value)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
public int NewPhotoCount => _newPhotoCount;
|
||||||
|
|
||||||
|
public void IncrementNewPhotoCount()
|
||||||
|
{
|
||||||
|
_newPhotoCount++;
|
||||||
|
OnNewPhotoCountChanged(_newPhotoCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetNewPhotoCount()
|
||||||
|
{
|
||||||
|
_newPhotoCount = 0;
|
||||||
|
OnNewPhotoCountChanged(_newPhotoCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnNewPhotoCountChanged(int count)
|
||||||
|
{
|
||||||
|
NewPhotoCountChanged?.Invoke(this, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task LoadThumbnailsToCache(int cacheSize = 0)
|
public async Task LoadThumbnailsToCache(int cacheSize = 0)
|
||||||
{
|
{
|
||||||
@ -37,7 +60,33 @@ public class PictureGalleryService
|
|||||||
string? pictureLocation = this._appSettings.PictureLocation;
|
string? pictureLocation = this._appSettings.PictureLocation;
|
||||||
int loop = 0;
|
int loop = 0;
|
||||||
|
|
||||||
List<string> picturePaths = Directory.EnumerateFiles(pictureLocation).ToList();
|
// Sicherstellen, dass das Verzeichnis existiert
|
||||||
|
if (!Directory.Exists(pictureLocation))
|
||||||
|
{
|
||||||
|
this._logger.Info($"Picture directory does not exist: '{pictureLocation}'. Creating it...");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(pictureLocation);
|
||||||
|
this._logger.Info($"Picture directory created: '{pictureLocation}'");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
this._logger.Error($"Failed to create picture directory: {ex.Message}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter nur Bilddateien
|
||||||
|
string[] imageExtensions = { ".jpg", ".jpeg", ".png", ".bmp", ".gif" };
|
||||||
|
List<string> picturePaths = Directory.EnumerateFiles(pictureLocation)
|
||||||
|
.Where(f => imageExtensions.Contains(Path.GetExtension(f).ToLower()))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (picturePaths.Count == 0)
|
||||||
|
{
|
||||||
|
this._logger.Info($"No pictures found in directory: '{pictureLocation}'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await Task.Run(
|
await Task.Run(
|
||||||
() =>
|
() =>
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
x:Name="MainFrame"
|
x:Name="MainFrame"
|
||||||
NavigationUIVisibility="Hidden"
|
NavigationUIVisibility="Hidden"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Background="LightBlue"
|
Background="Black"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Panel.ZIndex="0" />
|
Panel.ZIndex="0" />
|
||||||
|
|
||||||
@ -41,21 +41,27 @@
|
|||||||
Panel.ZIndex="1" />
|
Panel.ZIndex="1" />
|
||||||
|
|
||||||
<!-- Inhalt der dritten Zeile -->
|
<!-- Inhalt der dritten Zeile -->
|
||||||
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Bottom" Visibility="Hidden" Name="TimerPanel" Background="#AA000000" Panel.ZIndex="2"
|
<StackPanel Grid.Row="0" Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Bottom" Visibility="Hidden" Name="TimerPanel" Background="#AA000000" Panel.ZIndex="2"
|
||||||
Margin="0 0 0 0">
|
Margin="0 0 0 0">
|
||||||
|
<TextBlock x:Name="CaptureStatusText"
|
||||||
|
Text="Scharfstellen..."
|
||||||
|
Visibility="Collapsed"
|
||||||
|
Foreground="White"
|
||||||
|
FontSize="36"
|
||||||
|
FontWeight="Bold"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Margin="24 24 24 12"/>
|
||||||
<liveView:TimerControlRectangleAnimation x:Name="TimerControlRectangleAnimation" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
<liveView:TimerControlRectangleAnimation x:Name="TimerControlRectangleAnimation" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Bottom" Name="ButtonPanel" Background="Transparent" Panel.ZIndex="2"
|
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Bottom" Name="ButtonPanel" Background="Transparent" Panel.ZIndex="2"
|
||||||
|
Visibility="Hidden"
|
||||||
Margin="0 0 0 0">
|
Margin="0 0 0 0">
|
||||||
<ui:Button Content="Start" Click="NavToLiveView" Width="200" Height="75" VerticalAlignment="Bottom"
|
<ui:Button x:Name="HideDebugButton" Content="Hide Debug" Click="SetVisibilityDebugConsole" Width="200" Height="75"
|
||||||
Margin="0 0 5 0" />
|
|
||||||
<ui:Button Content="Hide Debug" Click="SetVisibilityDebugConsole" Width="200" Height="75"
|
|
||||||
VerticalAlignment="Bottom" Margin="0 0 5 0" />
|
VerticalAlignment="Bottom" Margin="0 0 5 0" />
|
||||||
<!-- <ui:Button Content="Take Photo" Click="StartTakePhotoProcess" Width="200" Height="75" VerticalAlignment="Bottom" -->
|
<!-- <ui:Button Content="Take Photo" Click="StartTakePhotoProcess" Width="200" Height="75" VerticalAlignment="Bottom" -->
|
||||||
<!-- Margin="0 0 5 0" /> -->
|
<!-- Margin="0 0 5 0" /> -->
|
||||||
<Button Width="160" Height="160"
|
<Button Width="160" Height="160"
|
||||||
Click="StartTakePhotoProcess"
|
Click="StartTakePhotoProcess"
|
||||||
Content="PUSH ME"
|
|
||||||
FontSize="64"
|
FontSize="64"
|
||||||
Foreground="White"
|
Foreground="White"
|
||||||
Margin="0 0 5 0"
|
Margin="0 0 5 0"
|
||||||
@ -64,12 +70,167 @@
|
|||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ModernRounded3DButtonStyle}"/>
|
Style="{StaticResource ModernRounded3DButtonStyle}"/>
|
||||||
|
<ui:Button x:Name="DebugCloseButton" Content="Close" Appearance="Danger" Click="CloseApp" Width="200" Height="75" VerticalAlignment="Bottom" Margin="0 0 5 0" />
|
||||||
<ui:Button Content="Pictures" Click="SetVisibilityPicturePanel" Width="200" Height="75"
|
|
||||||
VerticalAlignment="Bottom" Margin="0 0 5 0" />
|
|
||||||
<ui:Button Content="Close" Appearance="Danger" Click="CloseApp" Width="200" Height="75" VerticalAlignment="Bottom" Margin="0 0 5 0" />
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Picture Gallery Dock (bottom-right) -->
|
||||||
|
<Grid Grid.Row="0"
|
||||||
|
x:Name="PictureGalleryDock"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Margin="20"
|
||||||
|
Panel.ZIndex="3"
|
||||||
|
Visibility="Hidden">
|
||||||
|
<ui:Button Content=""
|
||||||
|
FontFamily="Segoe MDL2 Assets"
|
||||||
|
FontSize="30"
|
||||||
|
Width="72"
|
||||||
|
Height="72"
|
||||||
|
Click="SetVisibilityPicturePanel"
|
||||||
|
Background="#D4AF37"
|
||||||
|
Foreground="#1F1A00"
|
||||||
|
BorderBrush="#F6E7A1"
|
||||||
|
BorderThickness="2" />
|
||||||
|
<!-- Badge for new photos -->
|
||||||
|
<Border x:Name="NewPhotosBadge"
|
||||||
|
Background="#E61A1A1A"
|
||||||
|
BorderBrush="#FF0000"
|
||||||
|
BorderThickness="2"
|
||||||
|
CornerRadius="12"
|
||||||
|
Width="36"
|
||||||
|
Height="36"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Margin="0,-8,-8,0"
|
||||||
|
Visibility="Collapsed"
|
||||||
|
Panel.ZIndex="1">
|
||||||
|
<TextBlock x:Name="NewPhotoCountText"
|
||||||
|
Text="1"
|
||||||
|
Foreground="White"
|
||||||
|
FontSize="18"
|
||||||
|
FontWeight="Bold"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Gallery Prompt -->
|
||||||
|
<Border Grid.Row="0"
|
||||||
|
x:Name="GalleryPrompt"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Margin="20"
|
||||||
|
Padding="16"
|
||||||
|
Background="#E61A1A1A"
|
||||||
|
BorderBrush="#66FFFFFF"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="12"
|
||||||
|
Panel.ZIndex="4"
|
||||||
|
Visibility="Collapsed">
|
||||||
|
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||||
|
<TextBlock Text="Foto gespeichert"
|
||||||
|
Foreground="White"
|
||||||
|
FontSize="24"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="0 0 12 0" />
|
||||||
|
<ui:Button Content="Jetzt in Galerie ansehen"
|
||||||
|
Click="OpenGalleryFromPrompt"
|
||||||
|
Width="240"
|
||||||
|
Height="52" />
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Shutdown Slider (bottom-left) -->
|
||||||
|
<Grid Grid.Row="0"
|
||||||
|
x:Name="ShutdownDock"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Margin="20"
|
||||||
|
Panel.ZIndex="3"
|
||||||
|
Visibility="Hidden">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<ui:Button Grid.Column="0"
|
||||||
|
x:Name="ShutdownToggleButton"
|
||||||
|
Content=""
|
||||||
|
FontFamily="Segoe MDL2 Assets"
|
||||||
|
FontSize="28"
|
||||||
|
Width="64"
|
||||||
|
Height="64"
|
||||||
|
Appearance="Danger"
|
||||||
|
Click="ToggleShutdownSlider" />
|
||||||
|
|
||||||
|
<Border Grid.Column="1"
|
||||||
|
Width="160"
|
||||||
|
Height="64"
|
||||||
|
Margin="8 0 0 0"
|
||||||
|
CornerRadius="10"
|
||||||
|
Background="#44202020"
|
||||||
|
ClipToBounds="True">
|
||||||
|
<Grid RenderTransformOrigin="0.5,0.5">
|
||||||
|
<Grid.RenderTransform>
|
||||||
|
<TranslateTransform x:Name="ShutdownSliderTransform" X="160" />
|
||||||
|
</Grid.RenderTransform>
|
||||||
|
<ui:Button x:Name="ShutdownConfirmButton"
|
||||||
|
Content=""
|
||||||
|
FontFamily="Segoe MDL2 Assets"
|
||||||
|
FontSize="24"
|
||||||
|
Appearance="Danger"
|
||||||
|
Width="160"
|
||||||
|
Height="64"
|
||||||
|
Click="ShutdownWindows" />
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Welcome Overlay -->
|
||||||
|
<Grid Grid.RowSpan="2"
|
||||||
|
x:Name="WelcomeOverlay"
|
||||||
|
Background="#CC000000"
|
||||||
|
Panel.ZIndex="10">
|
||||||
|
<Border Background="#E61A1A1A"
|
||||||
|
BorderBrush="#66FFFFFF"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="20"
|
||||||
|
Padding="48"
|
||||||
|
MaxWidth="900"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center">
|
||||||
|
<StackPanel HorizontalAlignment="Center">
|
||||||
|
<TextBlock Text="Willkommen bei CamBooth!"
|
||||||
|
Foreground="White"
|
||||||
|
FontSize="56"
|
||||||
|
FontWeight="Bold"
|
||||||
|
TextAlignment="Center"
|
||||||
|
Margin="0 0 0 20"/>
|
||||||
|
<TextBlock Text="In wenigen Sekunden bist du bereit: Mit Start aktivierst du die Kamera und kannst direkt loslegen."
|
||||||
|
Foreground="#FFE8E8E8"
|
||||||
|
FontSize="28"
|
||||||
|
TextAlignment="Center"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Margin="0 0 0 16"/>
|
||||||
|
<ui:Button Click="StartExperience"
|
||||||
|
Width="480"
|
||||||
|
Height="100"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Foreground="#1F1A00"
|
||||||
|
Background="#FFFFD280"
|
||||||
|
Margin="0 12 0 0">
|
||||||
|
<TextBlock Text="Party starten"
|
||||||
|
FontSize="52"
|
||||||
|
FontWeight="Bold"
|
||||||
|
TextAlignment="Center"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"/>
|
||||||
|
</ui:Button>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<!-- DebugFrame -->
|
<!-- DebugFrame -->
|
||||||
<Frame Grid.Row="1"
|
<Frame Grid.Row="1"
|
||||||
x:Name="DebugFrame"
|
x:Name="DebugFrame"
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Media.Animation;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
using CamBooth.App.Core.AppSettings;
|
using CamBooth.App.Core.AppSettings;
|
||||||
using CamBooth.App.Core.Logging;
|
using CamBooth.App.Core.Logging;
|
||||||
@ -29,6 +33,24 @@ public partial class MainWindow : Window
|
|||||||
|
|
||||||
private LiveViewPage? _liveViewPage;
|
private LiveViewPage? _liveViewPage;
|
||||||
|
|
||||||
|
private bool _isPhotoProcessRunning;
|
||||||
|
|
||||||
|
private bool _isCameraStarted;
|
||||||
|
|
||||||
|
private bool _isShutdownSliderOpen;
|
||||||
|
|
||||||
|
private const string ShutdownGlyphClosed = "\uE7E8";
|
||||||
|
|
||||||
|
private const string ShutdownGlyphOpen = "\uE711";
|
||||||
|
|
||||||
|
private const double ShutdownSliderOffset = 160;
|
||||||
|
|
||||||
|
private readonly DispatcherTimer _focusStatusAnimationTimer = new() { Interval = TimeSpan.FromMilliseconds(250) };
|
||||||
|
|
||||||
|
private readonly DispatcherTimer _galleryPromptTimer = new() { Interval = TimeSpan.FromSeconds(5) };
|
||||||
|
|
||||||
|
private int _focusStatusDots;
|
||||||
|
|
||||||
|
|
||||||
public MainWindow(
|
public MainWindow(
|
||||||
Logger logger,
|
Logger logger,
|
||||||
@ -41,11 +63,24 @@ public partial class MainWindow : Window
|
|||||||
this._pictureGalleryService = pictureGalleryService;
|
this._pictureGalleryService = pictureGalleryService;
|
||||||
this._cameraService = cameraService;
|
this._cameraService = cameraService;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
this.SetVisibilityDebugConsole(this._isDebugConsoleVisible);
|
this.SetVisibilityDebugConsole(_appSettings.IsDebugConsoleVisible);
|
||||||
this.SetVisibilityPicturePanel(this._isPicturePanelVisible);
|
this.SetVisibilityPicturePanel(this._isPicturePanelVisible);
|
||||||
_ = this._pictureGalleryService.LoadThumbnailsToCache();
|
_ = this._pictureGalleryService.LoadThumbnailsToCache();
|
||||||
this.Closing += OnClosing;
|
this.Closing += OnClosing;
|
||||||
TimerControlRectangleAnimation.OnTimerEllapsed += TimerControlRectangleAnimation_OnTimerEllapsed;
|
TimerControlRectangleAnimation.OnTimerEllapsed += TimerControlRectangleAnimation_OnTimerEllapsed;
|
||||||
|
this._focusStatusAnimationTimer.Tick += (_, _) =>
|
||||||
|
{
|
||||||
|
this._focusStatusDots = (this._focusStatusDots + 1) % 4;
|
||||||
|
this.CaptureStatusText.Text = $"Scharfstellen{new string('.', this._focusStatusDots)}";
|
||||||
|
};
|
||||||
|
this._galleryPromptTimer.Tick += (_, _) => this.HideGalleryPrompt();
|
||||||
|
|
||||||
|
// Subscribe to new photo count changes
|
||||||
|
this._pictureGalleryService.NewPhotoCountChanged += PictureGalleryService_NewPhotoCountChanged;
|
||||||
|
|
||||||
|
this.DebugCloseButton.Visibility = Visibility.Collapsed;
|
||||||
|
this.HideDebugButton.Visibility = this._appSettings.IsDebugConsoleVisible ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
|
||||||
logger.Info($"config file loaded: '{appSettings.ConfigFileName}'");
|
logger.Info($"config file loaded: '{appSettings.ConfigFileName}'");
|
||||||
logger.Info("MainWindow initialized");
|
logger.Info("MainWindow initialized");
|
||||||
}
|
}
|
||||||
@ -53,9 +88,12 @@ public partial class MainWindow : Window
|
|||||||
|
|
||||||
private void TimerControlRectangleAnimation_OnTimerEllapsed()
|
private void TimerControlRectangleAnimation_OnTimerEllapsed()
|
||||||
{
|
{
|
||||||
|
var photoTakenSuccessfully = false;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this._cameraService.TakePhoto();
|
this._cameraService.TakePhoto();
|
||||||
|
photoTakenSuccessfully = true;
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
@ -65,7 +103,14 @@ public partial class MainWindow : Window
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
this.StopFocusStatusAnimation();
|
||||||
|
this.CaptureStatusText.Visibility = Visibility.Collapsed;
|
||||||
SwitchButtonAndTimerPanel();
|
SwitchButtonAndTimerPanel();
|
||||||
|
this._isPhotoProcessRunning = false;
|
||||||
|
if (photoTakenSuccessfully)
|
||||||
|
{
|
||||||
|
this.ShowGalleryPrompt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +119,10 @@ public partial class MainWindow : Window
|
|||||||
{
|
{
|
||||||
if (visibility)
|
if (visibility)
|
||||||
{
|
{
|
||||||
|
this.HideGalleryPrompt();
|
||||||
this.PicturePanel.Navigate(new PictureGalleryPage(this._appSettings, this._logger, this._pictureGalleryService));
|
this.PicturePanel.Navigate(new PictureGalleryPage(this._appSettings, this._logger, this._pictureGalleryService));
|
||||||
|
// Reset new photo count when opening gallery
|
||||||
|
this._pictureGalleryService.ResetNewPhotoCount();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -85,16 +133,47 @@ public partial class MainWindow : Window
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void ClosePicturePanel()
|
||||||
|
{
|
||||||
|
if (this.PicturePanel.Content is PictureGalleryPage pictureGalleryPage)
|
||||||
|
{
|
||||||
|
pictureGalleryPage.CloseOpenDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.PicturePanel.Content is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.SetVisibilityPicturePanel(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void OnClosing(object? sender, CancelEventArgs e)
|
private void OnClosing(object? sender, CancelEventArgs e)
|
||||||
{
|
{
|
||||||
this._liveViewPage?.Dispose();
|
this._liveViewPage?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void NavToLiveView(object sender, RoutedEventArgs e)
|
private void StartExperience(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_liveViewPage = new LiveViewPage(this._logger, this._appSettings, this._cameraService);
|
this.StartLiveViewIfNeeded();
|
||||||
MainFrame.Navigate(this._liveViewPage);
|
this.WelcomeOverlay.Visibility = Visibility.Collapsed;
|
||||||
|
this.ButtonPanel.Visibility = Visibility.Visible;
|
||||||
|
this.PictureGalleryDock.Visibility = Visibility.Visible;
|
||||||
|
this.ShutdownDock.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartLiveViewIfNeeded()
|
||||||
|
{
|
||||||
|
if (this._isCameraStarted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._liveViewPage = new LiveViewPage(this._logger, this._appSettings, this._cameraService);
|
||||||
|
this.MainFrame.Navigate(this._liveViewPage);
|
||||||
|
this._isCameraStarted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -106,6 +185,11 @@ public partial class MainWindow : Window
|
|||||||
|
|
||||||
private void SetVisibilityDebugConsole(bool visibility)
|
private void SetVisibilityDebugConsole(bool visibility)
|
||||||
{
|
{
|
||||||
|
if (!_appSettings.IsDebugConsoleVisible)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (visibility)
|
if (visibility)
|
||||||
{
|
{
|
||||||
this.DebugFrame.Navigate(new DebugConsolePage(this._logger));
|
this.DebugFrame.Navigate(new DebugConsolePage(this._logger));
|
||||||
@ -119,19 +203,44 @@ public partial class MainWindow : Window
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void StartTakePhotoProcess(object sender, RoutedEventArgs e)
|
private async void StartTakePhotoProcess(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
this.HideGalleryPrompt();
|
||||||
|
this.ClosePicturePanel();
|
||||||
|
|
||||||
|
if (this._isPhotoProcessRunning)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._isPhotoProcessRunning = true;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
TimerControlRectangleAnimation.StartTimer(1);
|
|
||||||
#else
|
|
||||||
TimerControlRectangleAnimation.StartTimer(5);
|
|
||||||
#endif
|
|
||||||
SwitchButtonAndTimerPanel();
|
SwitchButtonAndTimerPanel();
|
||||||
|
|
||||||
|
TimerControlRectangleAnimation.StartTimer(this._appSettings.PhotoCountdownSeconds);
|
||||||
|
this.StartFocusStatusAnimation();
|
||||||
|
this.CaptureStatusText.Visibility = Visibility.Visible;
|
||||||
|
await Task.Delay(TimeSpan.FromSeconds(this._appSettings.FocusDelaySeconds));
|
||||||
|
if (!this._isPhotoProcessRunning)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this._cameraService.PrepareFocusAsync(focusTimeoutMs: this._appSettings.FocusTimeoutMs);
|
||||||
|
this.StopFocusStatusAnimation();
|
||||||
|
this.CaptureStatusText.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
|
this._isPhotoProcessRunning = false;
|
||||||
|
this.StopFocusStatusAnimation();
|
||||||
|
this.CaptureStatusText.Visibility = Visibility.Collapsed;
|
||||||
|
if (this.TimerPanel.Visibility == Visibility.Visible)
|
||||||
|
{
|
||||||
|
SwitchButtonAndTimerPanel();
|
||||||
|
}
|
||||||
this._logger.Error(exception.Message);
|
this._logger.Error(exception.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,6 +248,7 @@ public partial class MainWindow : Window
|
|||||||
private void SwitchButtonAndTimerPanel()
|
private void SwitchButtonAndTimerPanel()
|
||||||
{
|
{
|
||||||
this.ButtonPanel.Visibility = this.ButtonPanel.Visibility == Visibility.Hidden ? Visibility.Visible : Visibility.Hidden;
|
this.ButtonPanel.Visibility = this.ButtonPanel.Visibility == Visibility.Hidden ? Visibility.Visible : Visibility.Hidden;
|
||||||
|
this.PictureGalleryDock.Visibility = this.PictureGalleryDock.Visibility == Visibility.Hidden ? Visibility.Visible : Visibility.Hidden;
|
||||||
this.TimerPanel.Visibility = this.TimerPanel.Visibility == Visibility.Hidden ? Visibility.Visible : Visibility.Hidden;
|
this.TimerPanel.Visibility = this.TimerPanel.Visibility == Visibility.Hidden ? Visibility.Visible : Visibility.Hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,4 +262,92 @@ public partial class MainWindow : Window
|
|||||||
{
|
{
|
||||||
this.Close();
|
this.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ShutdownWindows(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (this._appSettings.IsShutdownEnabled)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Process.Start(new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = "shutdown",
|
||||||
|
Arguments = "/s /t 0",
|
||||||
|
CreateNoWindow = true,
|
||||||
|
UseShellExecute = false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
this._logger.Error(exception.Message);
|
||||||
|
System.Windows.MessageBox.Show("Windows konnte nicht heruntergefahren werden. Bitte erneut versuchen.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ToggleShutdownSlider(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
this._isShutdownSliderOpen = !this._isShutdownSliderOpen;
|
||||||
|
this.ShutdownToggleButton.Content = this._isShutdownSliderOpen ? ShutdownGlyphOpen : ShutdownGlyphClosed;
|
||||||
|
this.AnimateShutdownSlider(this._isShutdownSliderOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AnimateShutdownSlider(bool open)
|
||||||
|
{
|
||||||
|
var animation = new DoubleAnimation
|
||||||
|
{
|
||||||
|
To = open ? 0 : ShutdownSliderOffset,
|
||||||
|
Duration = TimeSpan.FromMilliseconds(250),
|
||||||
|
EasingFunction = new QuadraticEase()
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ShutdownSliderTransform.BeginAnimation(System.Windows.Media.TranslateTransform.XProperty, animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartFocusStatusAnimation()
|
||||||
|
{
|
||||||
|
this._focusStatusDots = 0;
|
||||||
|
this.CaptureStatusText.Text = "Scharfstellen";
|
||||||
|
this._focusStatusAnimationTimer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopFocusStatusAnimation()
|
||||||
|
{
|
||||||
|
this._focusStatusAnimationTimer.Stop();
|
||||||
|
this._focusStatusDots = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowGalleryPrompt()
|
||||||
|
{
|
||||||
|
this.GalleryPrompt.Visibility = Visibility.Visible;
|
||||||
|
this._galleryPromptTimer.Stop();
|
||||||
|
this._galleryPromptTimer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HideGalleryPrompt()
|
||||||
|
{
|
||||||
|
this._galleryPromptTimer.Stop();
|
||||||
|
this.GalleryPrompt.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenGalleryFromPrompt(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
this.HideGalleryPrompt();
|
||||||
|
this.SetVisibilityPicturePanel(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PictureGalleryService_NewPhotoCountChanged(object? sender, int newPhotoCount)
|
||||||
|
{
|
||||||
|
if (newPhotoCount > 0)
|
||||||
|
{
|
||||||
|
this.NewPhotosBadge.Visibility = Visibility.Visible;
|
||||||
|
this.NewPhotoCountText.Text = newPhotoCount.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.NewPhotosBadge.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
8
src/CamBooth/CamBooth.App/ToDos.txt
Normal file
8
src/CamBooth/CamBooth.App/ToDos.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
- Rotate Flick Picture 180°
|
||||||
|
- Printer anschließen
|
||||||
|
- Galerie schließen
|
||||||
|
- Debug Window schließen
|
||||||
|
- Kiosk Modus einrichten
|
||||||
|
- Energiesparmodus abschalten
|
||||||
|
- Starbildschirm mit freundlicher Begrüßung, kurzer Erklärung, und viel Spaß wünschen mit der FotoCam
|
||||||
|
- Verschiedene Hinweise anzeigen beim Fotofrafieren (lächeln, Hasensohren, Zunge raus, Grimasse, usw.)
|
||||||
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -146,7 +146,14 @@ namespace EDSDKLib.API.Base
|
|||||||
/// <exception cref="ArgumentNullException">The DownloadInfo is null</exception>
|
/// <exception cref="ArgumentNullException">The DownloadInfo is null</exception>
|
||||||
public void DownloadFile(IDownloadInfo Info, string directory)
|
public void DownloadFile(IDownloadInfo Info, string directory)
|
||||||
{
|
{
|
||||||
File.WriteAllBytes(Path.Combine(directory, Info.FileName), File.ReadAllBytes(this.mockImageFiles[new Random().Next(1, this.mockImageFiles.Count)].FullName));
|
if (this.mockImageFiles.Count == 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("No mock images available");
|
||||||
|
}
|
||||||
|
|
||||||
|
Random random = new Random();
|
||||||
|
int randomIndex = random.Next(0, this.mockImageFiles.Count);
|
||||||
|
File.WriteAllBytes(Path.Combine(directory, Info.FileName), File.ReadAllBytes(this.mockImageFiles[randomIndex].FullName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -200,7 +207,7 @@ namespace EDSDKLib.API.Base
|
|||||||
|
|
||||||
this.DownloadReady?.Invoke(this, new DownloadInfoMock()
|
this.DownloadReady?.Invoke(this, new DownloadInfoMock()
|
||||||
{
|
{
|
||||||
FileName = $"{mockImageFiles[random.Next(1, 99)].FullName}"
|
FileName = $"MockPhoto_{Guid.NewGuid().ToString()}.jpg"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user