"Refactor UI and logging: Update UI text and wrapping for better readability, switch logging to Debug for consistency, and clean up unused imports and code alignment across multiple services"
This commit is contained in:
parent
d0db293bb8
commit
9ad55bd90a
@ -1,15 +1,11 @@
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
using CamBooth.App.Core.AppSettings;
|
using CamBooth.App.Core.AppSettings;
|
||||||
using CamBooth.App.Core.Logging;
|
using CamBooth.App.Core.Logging;
|
||||||
using CamBooth.App.Features.Camera;
|
using CamBooth.App.Features.Camera;
|
||||||
using CamBooth.App.Features.PhotoPrismUpload;
|
using CamBooth.App.Features.PhotoPrismUpload;
|
||||||
using CamBooth.App.Features.PictureGallery;
|
using CamBooth.App.Features.PictureGallery;
|
||||||
|
|
||||||
using EDSDKLib.API.Base;
|
using EDSDKLib.API.Base;
|
||||||
|
|
||||||
using EOSDigital.API;
|
using EOSDigital.API;
|
||||||
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
@ -20,134 +16,134 @@ namespace CamBooth.App;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class App : Application
|
public partial class App : Application
|
||||||
{
|
{
|
||||||
private IServiceProvider? _serviceProvider;
|
private IServiceProvider? _serviceProvider;
|
||||||
|
|
||||||
protected override void OnStartup(StartupEventArgs e)
|
protected override void OnStartup(StartupEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnStartup(e);
|
base.OnStartup(e);
|
||||||
|
|
||||||
var configuration = BuildConfiguration();
|
var configuration = BuildConfiguration();
|
||||||
var services = new ServiceCollection();
|
var services = new ServiceCollection();
|
||||||
|
|
||||||
RegisterServices(services, configuration);
|
RegisterServices(services, configuration);
|
||||||
|
|
||||||
_serviceProvider = services.BuildServiceProvider();
|
_serviceProvider = services.BuildServiceProvider();
|
||||||
|
|
||||||
StartBackgroundServices();
|
StartBackgroundServices();
|
||||||
|
|
||||||
_serviceProvider.GetRequiredService<MainWindow>().Show();
|
_serviceProvider.GetRequiredService<MainWindow>().Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSessionEnding(SessionEndingCancelEventArgs e)
|
protected override void OnSessionEnding(SessionEndingCancelEventArgs e)
|
||||||
{
|
{
|
||||||
TryShutdownCamera("OnSessionEnding");
|
TryShutdownCamera("OnSessionEnding");
|
||||||
base.OnSessionEnding(e);
|
base.OnSessionEnding(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnExit(ExitEventArgs e)
|
protected override void OnExit(ExitEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_serviceProvider?.GetService<PhotoPrismUploadQueueService>()
|
_serviceProvider?.GetService<PhotoPrismUploadQueueService>()
|
||||||
?.StopAsync().Wait(TimeSpan.FromSeconds(10));
|
?.StopAsync().Wait(TimeSpan.FromSeconds(10));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Debug.WriteLine($"Error stopping upload service: {ex.Message}");
|
System.Diagnostics.Debug.WriteLine($"Error stopping upload service: {ex.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
TryShutdownCamera("OnExit");
|
TryShutdownCamera("OnExit");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
(_serviceProvider as IDisposable)?.Dispose();
|
(_serviceProvider as IDisposable)?.Dispose();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Debug.WriteLine($"Error disposing service provider: {ex.Message}");
|
System.Diagnostics.Debug.WriteLine($"Error disposing service provider: {ex.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnExit(e);
|
base.OnExit(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static IConfiguration BuildConfiguration()
|
private static IConfiguration BuildConfiguration()
|
||||||
{
|
{
|
||||||
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production";
|
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production";
|
||||||
|
|
||||||
var builder = new ConfigurationBuilder()
|
var builder = new ConfigurationBuilder()
|
||||||
.SetBasePath(AppContext.BaseDirectory)
|
.SetBasePath(AppContext.BaseDirectory)
|
||||||
.AddJsonFile("Core/AppSettings/app.settings.json", optional: false, reloadOnChange: true);
|
.AddJsonFile("Core/AppSettings/app.settings.json", optional: false, reloadOnChange: true);
|
||||||
|
|
||||||
if (environment == "Development")
|
if (environment == "Development")
|
||||||
builder.AddJsonFile("Core/AppSettings/app.settings.dev.json", optional: true, reloadOnChange: true);
|
builder.AddJsonFile("Core/AppSettings/app.settings.dev.json", optional: true, reloadOnChange: true);
|
||||||
|
|
||||||
return builder.Build();
|
return builder.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void RegisterServices(ServiceCollection services, IConfiguration configuration)
|
private static void RegisterServices(ServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
services.AddSingleton(configuration);
|
services.AddSingleton(configuration);
|
||||||
services.AddSingleton<Logger>();
|
services.AddSingleton<Logger>();
|
||||||
services.AddSingleton<AppSettingsService>();
|
services.AddSingleton<AppSettingsService>();
|
||||||
services.AddSingleton<PictureGalleryService>();
|
services.AddSingleton<PictureGalleryService>();
|
||||||
services.AddSingleton<CameraService>();
|
services.AddSingleton<CameraService>();
|
||||||
services.AddSingleton<PhotoPrismAuthService>();
|
services.AddSingleton<PhotoPrismAuthService>();
|
||||||
services.AddSingleton<PhotoPrismUploadService>();
|
services.AddSingleton<PhotoPrismUploadService>();
|
||||||
services.AddSingleton<PhotoPrismUploadQueueService>();
|
services.AddSingleton<PhotoPrismUploadQueueService>();
|
||||||
services.AddSingleton<MainWindowViewModel>();
|
services.AddSingleton<MainWindowViewModel>();
|
||||||
services.AddTransient<MainWindow>();
|
services.AddTransient<MainWindow>();
|
||||||
|
|
||||||
RegisterCameraApi(services, configuration);
|
RegisterCameraApi(services, configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void RegisterCameraApi(ServiceCollection services, IConfiguration configuration)
|
private static void RegisterCameraApi(ServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
var useMockCamera = bool.Parse(configuration["AppSettings:UseMockCamera"] ?? "false");
|
var useMockCamera = bool.Parse(configuration["AppSettings:UseMockCamera"] ?? "false");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ICanonAPI canonApi = useMockCamera ? new CanonAPIMock() : new CanonAPI();
|
ICanonAPI canonApi = useMockCamera ? new CanonAPIMock() : new CanonAPI();
|
||||||
services.AddSingleton(canonApi);
|
services.AddSingleton(canonApi);
|
||||||
}
|
}
|
||||||
catch (DllNotFoundException ex)
|
catch (DllNotFoundException ex)
|
||||||
{
|
{
|
||||||
MessageBox.Show(
|
MessageBox.Show(
|
||||||
$"EDSDK konnte nicht geladen werden. Verwende Mock-Kamera.\n\nFehler: {ex.Message}",
|
$"EDSDK konnte nicht geladen werden. Verwende Mock-Kamera.\n\nFehler: {ex.Message}",
|
||||||
"DLL nicht gefunden", MessageBoxButton.OK, MessageBoxImage.Warning);
|
"DLL nicht gefunden", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
|
||||||
services.AddSingleton<ICanonAPI>(new CanonAPIMock());
|
services.AddSingleton<ICanonAPI>(new CanonAPIMock());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void StartBackgroundServices()
|
private void StartBackgroundServices()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var logger = _serviceProvider!.GetRequiredService<Logger>();
|
var logger = _serviceProvider!.GetRequiredService<Logger>();
|
||||||
var uploadQueueService = _serviceProvider.GetRequiredService<PhotoPrismUploadQueueService>();
|
var uploadQueueService = _serviceProvider.GetRequiredService<PhotoPrismUploadQueueService>();
|
||||||
uploadQueueService.Start();
|
uploadQueueService.Start();
|
||||||
uploadQueueService.ScanAndQueueFailedUploads();
|
uploadQueueService.ScanAndQueueFailedUploads();
|
||||||
logger.Info("PhotoPrism UploadQueueService gestartet");
|
logger.Info("PhotoPrism UploadQueueService gestartet");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Debug.WriteLine($"Error starting background services: {ex.Message}");
|
System.Diagnostics.Debug.WriteLine($"Error starting background services: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TryShutdownCamera(string source)
|
private void TryShutdownCamera(string source)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var cameraService = _serviceProvider?.GetService<CameraService>();
|
var cameraService = _serviceProvider?.GetService<CameraService>();
|
||||||
cameraService?.CloseSession();
|
cameraService?.CloseSession();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Debug.WriteLine($"Error closing camera session ({source}): {ex.Message}");
|
System.Diagnostics.Debug.WriteLine($"Error closing camera session ({source}): {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,7 +71,7 @@ public class CameraService : IDisposable
|
|||||||
|
|
||||||
if (attempt < maxRetries - 1)
|
if (attempt < maxRetries - 1)
|
||||||
{
|
{
|
||||||
System.Threading.Thread.Sleep(retryDelayMs);
|
Thread.Sleep(retryDelayMs);
|
||||||
RefreshCameraList();
|
RefreshCameraList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,9 +143,7 @@ public class CameraService : IDisposable
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Task.Run(() => sdkCamera.SendCommand(CameraCommand.PressShutterButton, (int)ShutterButton.Halfway));
|
await Task.Run(() => sdkCamera.SendCommand(CameraCommand.PressShutterButton, (int)ShutterButton.Halfway));
|
||||||
var completed = await Task.WhenAny(focusCompleted.Task, Task.Delay(focusTimeoutMs));
|
await Task.WhenAny(focusCompleted.Task, Task.Delay(focusTimeoutMs));
|
||||||
if (completed != focusCompleted.Task)
|
|
||||||
_logger.Info("Autofocus timeout reached, continuing.");
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -286,13 +284,13 @@ public class CameraService : IDisposable
|
|||||||
|
|
||||||
private void MainCamera_DownloadReady(ICamera sender, IDownloadInfo info)
|
private void MainCamera_DownloadReady(ICamera sender, IDownloadInfo info)
|
||||||
{
|
{
|
||||||
_logger.Info("Download ready");
|
_logger.Debug("Download ready");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
info.FileName = $"img_{Guid.NewGuid()}.jpg";
|
info.FileName = $"img_{Guid.NewGuid()}.jpg";
|
||||||
sender.DownloadFile(info, _appSettings.PictureLocation);
|
sender.DownloadFile(info, _appSettings.PictureLocation);
|
||||||
var savedPath = Path.Combine(_appSettings.PictureLocation!, info.FileName);
|
var savedPath = Path.Combine(_appSettings.PictureLocation!, info.FileName);
|
||||||
_logger.Info($"Download complete: {savedPath}");
|
_logger.Debug($"Download complete: {savedPath}");
|
||||||
|
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,20 +1,15 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using CamBooth.App.Core.Logging;
|
using CamBooth.App.Core.Logging;
|
||||||
using CamBooth.App.Features.Camera;
|
using CamBooth.App.Features.Camera;
|
||||||
using EOSDigital.API;
|
|
||||||
|
|
||||||
namespace CamBooth.App.Features.LiveView;
|
namespace CamBooth.App.Features.LiveView;
|
||||||
|
|
||||||
public partial class LiveViewPage : Page, IDisposable
|
public partial class LiveViewPage : IDisposable
|
||||||
{
|
{
|
||||||
private readonly CameraService _cameraService;
|
private readonly CameraService _cameraService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|||||||
@ -41,35 +41,4 @@ public partial class ModernTimerControl : UserControl
|
|||||||
StatusText.Text = "Zeit abgelaufen!";
|
StatusText.Text = "Zeit abgelaufen!";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void StartTimer(int durationInSeconds)
|
|
||||||
{
|
|
||||||
_remainingTime = durationInSeconds;
|
|
||||||
TimerText.Text = TimeSpan.FromSeconds(_remainingTime).ToString(@"mm\:ss");
|
|
||||||
StatusText.Text = "Timer läuft...";
|
|
||||||
_timer.Start();
|
|
||||||
ShowTimer();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void StopTimer()
|
|
||||||
{
|
|
||||||
_timer.Stop();
|
|
||||||
StatusText.Text = "Timer angehalten";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void ShowTimer()
|
|
||||||
{
|
|
||||||
var fadeInAnimation = new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(300));
|
|
||||||
TimerContainer.BeginAnimation(OpacityProperty, fadeInAnimation);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void HideTimer()
|
|
||||||
{
|
|
||||||
var fadeOutAnimation = new DoubleAnimation(1, 0, TimeSpan.FromMilliseconds(300));
|
|
||||||
TimerContainer.BeginAnimation(OpacityProperty, fadeOutAnimation);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -54,16 +54,21 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<!-- Instruction text below the ring -->
|
<!-- Instruction text below the ring -->
|
||||||
<TextBlock x:Name="InstructionText"
|
<Border Background="#CC101010"
|
||||||
FontSize="46"
|
CornerRadius="16"
|
||||||
FontWeight="Bold"
|
Padding="28,14"
|
||||||
Foreground="#D4AF37"
|
HorizontalAlignment="Center"
|
||||||
HorizontalAlignment="Center"
|
Margin="0,24,0,0">
|
||||||
TextAlignment="Center"
|
<TextBlock x:Name="InstructionText"
|
||||||
TextWrapping="Wrap"
|
FontSize="46"
|
||||||
MaxWidth="900"
|
FontWeight="Bold"
|
||||||
Margin="0,24,0,0"
|
Foreground="#D4AF37"
|
||||||
Text="Lächeln! 😊"/>
|
HorizontalAlignment="Center"
|
||||||
|
TextAlignment="Center"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
MaxWidth="900"
|
||||||
|
Text="Lächeln! 😊"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
@ -10,104 +10,104 @@ namespace CamBooth.App.Features.LiveView;
|
|||||||
public partial class TimerControlRectangleAnimation : UserControl
|
public partial class TimerControlRectangleAnimation : UserControl
|
||||||
{
|
{
|
||||||
// Ellipse diameter=320, StrokeThickness=12 → circumference = π*320/12 ≈ 83.78 dash-units
|
// Ellipse diameter=320, StrokeThickness=12 → circumference = π*320/12 ≈ 83.78 dash-units
|
||||||
private static readonly double RingFullDashUnits = Math.PI * 320.0 / 12.0;
|
private static readonly double RingFullDashUnits = Math.PI * 320.0 / 12.0;
|
||||||
|
|
||||||
public static event Action? OnTimerEllapsed;
|
public static event Action? OnTimerEllapsed;
|
||||||
|
|
||||||
private readonly DispatcherTimer _ticker = new() { Interval = TimeSpan.FromSeconds(1) };
|
private readonly DispatcherTimer _ticker = new() { Interval = TimeSpan.FromSeconds(1) };
|
||||||
private readonly Random _random = new();
|
private readonly Random _random = new();
|
||||||
|
|
||||||
private int _remainingTime;
|
private int _remainingTime;
|
||||||
private double _totalDuration;
|
private double _totalDuration;
|
||||||
|
|
||||||
private static readonly string[] Instructions =
|
private static readonly string[] Instructions =
|
||||||
[
|
[
|
||||||
"Lächeln! 😊", "Hasenohren machen! 🐰", "Zunge rausstrecken! 👅",
|
"Lächeln! 😊", "Hasenohren machen! 🐰", "Zunge rausstrecken! 👅",
|
||||||
"Grimasse ziehen! 😝", "Daumen hoch! 👍", "Peace-Zeichen! ✌️",
|
"Grimasse ziehen! 😝", "Daumen hoch! 👍", "Peace-Zeichen! ✌️",
|
||||||
"Lustig gucken! 🤪", "Crazy Face! 🤯", "Küsschen! 😘",
|
"Lustig gucken! 🤪", "Crazy Face! 🤯", "Küsschen! 😘",
|
||||||
"Winken! 👋", "Herz mit den Händen! ❤️", "Überrascht schauen! 😲",
|
"Winken! 👋", "Herz mit den Händen! ❤️", "Überrascht schauen! 😲",
|
||||||
"Cool bleiben! 😎", "Lachen! 😄", "Zähne zeigen! 😁",
|
"Cool bleiben! 😎", "Lachen! 😄", "Zähne zeigen! 😁",
|
||||||
"Schnute ziehen! 😗", "Arm hochstrecken! 🙌", "Gruppe umarmen! 🤗"
|
"Schnute ziehen! 😗", "Arm hochstrecken! 🙌", "Gruppe umarmen! 🤗"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
public TimerControlRectangleAnimation()
|
public TimerControlRectangleAnimation()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
_ticker.Tick += OnTick;
|
_ticker.Tick += OnTick;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void StartTimer(int durationInSeconds)
|
public void StartTimer(int durationInSeconds)
|
||||||
{
|
{
|
||||||
_totalDuration = durationInSeconds;
|
_totalDuration = durationInSeconds;
|
||||||
_remainingTime = durationInSeconds;
|
_remainingTime = durationInSeconds;
|
||||||
|
|
||||||
CountdownNumber.Text = _remainingTime.ToString();
|
CountdownNumber.Text = _remainingTime.ToString();
|
||||||
InstructionText.Text = Instructions[_random.Next(Instructions.Length)];
|
InstructionText.Text = Instructions[_random.Next(Instructions.Length)];
|
||||||
|
|
||||||
// Reset ring offset so ring appears full
|
// Reset ring offset so ring appears full
|
||||||
CountdownRing.StrokeDashOffset = 0;
|
CountdownRing.StrokeDashOffset = 0;
|
||||||
CountdownRing.StrokeDashArray = new DoubleCollection { RingFullDashUnits, RingFullDashUnits };
|
CountdownRing.StrokeDashArray = new DoubleCollection { RingFullDashUnits, RingFullDashUnits };
|
||||||
|
|
||||||
FadeIn();
|
FadeIn();
|
||||||
StartRingAnimation();
|
StartRingAnimation();
|
||||||
_ticker.Start();
|
_ticker.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void OnTick(object? sender, EventArgs e)
|
private void OnTick(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
_remainingTime--;
|
_remainingTime--;
|
||||||
|
|
||||||
if (_remainingTime > 0)
|
if (_remainingTime > 0)
|
||||||
{
|
|
||||||
CountdownNumber.Text = _remainingTime.ToString();
|
|
||||||
AnimateNumberPop();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_ticker.Stop();
|
|
||||||
CountdownNumber.Text = "0";
|
|
||||||
AnimateNumberPop();
|
|
||||||
StopRingAnimation();
|
|
||||||
OnTimerEllapsed?.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void FadeIn()
|
|
||||||
{
|
|
||||||
TimerContainer.BeginAnimation(OpacityProperty,
|
|
||||||
new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(300)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void StartRingAnimation()
|
|
||||||
{
|
|
||||||
// StrokeDashOffset IS a DependencyProperty — animate directly, no Storyboard needed.
|
|
||||||
// Pattern: dash=C, gap=C. Offset 0 → full ring; offset C → empty ring.
|
|
||||||
CountdownRing.BeginAnimation(Shape.StrokeDashOffsetProperty,
|
|
||||||
new DoubleAnimation(0, RingFullDashUnits,
|
|
||||||
new Duration(TimeSpan.FromSeconds(_totalDuration)))
|
|
||||||
{
|
{
|
||||||
FillBehavior = FillBehavior.HoldEnd
|
CountdownNumber.Text = _remainingTime.ToString();
|
||||||
});
|
AnimateNumberPop();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_ticker.Stop();
|
||||||
|
CountdownNumber.Text = "0";
|
||||||
|
AnimateNumberPop();
|
||||||
|
StopRingAnimation();
|
||||||
|
OnTimerEllapsed?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void StopRingAnimation() =>
|
private void FadeIn()
|
||||||
CountdownRing.BeginAnimation(Shape.StrokeDashOffsetProperty, null);
|
{
|
||||||
|
TimerContainer.BeginAnimation(OpacityProperty,
|
||||||
|
new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(300)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void AnimateNumberPop()
|
private void StartRingAnimation()
|
||||||
{
|
{
|
||||||
var easing = new BackEase { Amplitude = 0.4, EasingMode = EasingMode.EaseOut };
|
// StrokeDashOffset IS a DependencyProperty — animate directly, no Storyboard needed.
|
||||||
CountdownNumberScale.ScaleX = 1.4;
|
// Pattern: dash=C, gap=C. Offset 0 → full ring; offset C → empty ring.
|
||||||
CountdownNumberScale.ScaleY = 1.4;
|
CountdownRing.BeginAnimation(Shape.StrokeDashOffsetProperty,
|
||||||
CountdownNumberScale.BeginAnimation(ScaleTransform.ScaleXProperty,
|
new DoubleAnimation(0, RingFullDashUnits,
|
||||||
new DoubleAnimation(1.4, 1.0, TimeSpan.FromMilliseconds(450)) { EasingFunction = easing });
|
new Duration(TimeSpan.FromSeconds(_totalDuration)))
|
||||||
CountdownNumberScale.BeginAnimation(ScaleTransform.ScaleYProperty,
|
{
|
||||||
new DoubleAnimation(1.4, 1.0, TimeSpan.FromMilliseconds(450)) { EasingFunction = easing });
|
FillBehavior = FillBehavior.HoldEnd
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void StopRingAnimation() =>
|
||||||
|
CountdownRing.BeginAnimation(Shape.StrokeDashOffsetProperty, null);
|
||||||
|
|
||||||
|
|
||||||
|
private void AnimateNumberPop()
|
||||||
|
{
|
||||||
|
var easing = new BackEase { Amplitude = 0.4, EasingMode = EasingMode.EaseOut };
|
||||||
|
CountdownNumberScale.ScaleX = 1.4;
|
||||||
|
CountdownNumberScale.ScaleY = 1.4;
|
||||||
|
CountdownNumberScale.BeginAnimation(ScaleTransform.ScaleXProperty,
|
||||||
|
new DoubleAnimation(1.4, 1.0, TimeSpan.FromMilliseconds(450)) { EasingFunction = easing });
|
||||||
|
CountdownNumberScale.BeginAnimation(ScaleTransform.ScaleYProperty,
|
||||||
|
new DoubleAnimation(1.4, 1.0, TimeSpan.FromMilliseconds(450)) { EasingFunction = easing });
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -37,7 +37,7 @@ public class PhotoPrismAuthService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.Info("Starte PhotoPrism-Authentifizierung...");
|
_logger.Debug("Starte PhotoPrism-Authentifizierung...");
|
||||||
|
|
||||||
if (!ValidateConfiguration())
|
if (!ValidateConfiguration())
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -134,7 +134,7 @@ public class PhotoPrismUploadQueueService : IDisposable
|
|||||||
{
|
{
|
||||||
if (_uploadQueue.Contains(photoPath)) return;
|
if (_uploadQueue.Contains(photoPath)) return;
|
||||||
_uploadQueue.Enqueue(photoPath);
|
_uploadQueue.Enqueue(photoPath);
|
||||||
_logger.Info($"Neues Foto in PhotoPrism-Queue: {Path.GetFileName(photoPath)}");
|
_logger.Debug($"Neues Foto in PhotoPrism-Queue: {Path.GetFileName(photoPath)}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +151,7 @@ public class PhotoPrismUploadQueueService : IDisposable
|
|||||||
|
|
||||||
private async Task ProcessQueueAsync(CancellationToken cancellationToken)
|
private async Task ProcessQueueAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_logger.Info("PhotoPrism Upload-Queue-Verarbeitung gestartet");
|
_logger.Debug("PhotoPrism Upload-Queue-Verarbeitung gestartet");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -203,7 +203,7 @@ public class PhotoPrismUploadQueueService : IDisposable
|
|||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
_uploadTracker.MarkAsUploaded(filePath);
|
_uploadTracker.MarkAsUploaded(filePath);
|
||||||
_logger.Info($"✅ PhotoPrism Upload erfolgreich: {fileName}");
|
_logger.Debug($"✅ PhotoPrism Upload erfolgreich: {fileName}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -140,7 +140,7 @@ public class PhotoPrismUploadService : IDisposable
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Info($"Starte Upload: {Path.GetFileName(imagePath)}");
|
_logger.Debug($"Starte Upload: {Path.GetFileName(imagePath)}");
|
||||||
_logger.Debug($" Authentifiziert: {_isAuthenticated}");
|
_logger.Debug($" Authentifiziert: {_isAuthenticated}");
|
||||||
_logger.Debug($" Token vorhanden: {!string.IsNullOrEmpty(_authService.AccessToken)}");
|
_logger.Debug($" Token vorhanden: {!string.IsNullOrEmpty(_authService.AccessToken)}");
|
||||||
|
|
||||||
|
|||||||
@ -53,7 +53,7 @@ public class PhotoPrismUploadTracker
|
|||||||
};
|
};
|
||||||
|
|
||||||
SaveToDisk();
|
SaveToDisk();
|
||||||
_logger.Info($"Bild als hochgeladen markiert: {key}");
|
_logger.Debug($"Bild als hochgeladen markiert: {key}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -76,12 +76,13 @@ public partial class PictureGalleryPage : Page
|
|||||||
|
|
||||||
var qrSubLabel = new TextBlock
|
var qrSubLabel = new TextBlock
|
||||||
{
|
{
|
||||||
Text = "zum Fotoalbum",
|
Text = "📱 Handy-Kamera draufhalten",
|
||||||
Foreground = new SolidColorBrush(Colors.White),
|
Foreground = new SolidColorBrush(Colors.White),
|
||||||
FontSize = 11,
|
FontSize = 12,
|
||||||
FontWeight = FontWeights.Bold,
|
FontWeight = FontWeights.Bold,
|
||||||
TextAlignment = TextAlignment.Center,
|
TextAlignment = TextAlignment.Center,
|
||||||
Margin = new Thickness(4, 0, 4, 2)
|
TextWrapping = TextWrapping.Wrap,
|
||||||
|
Margin = new Thickness(4, 0, 4, 4)
|
||||||
};
|
};
|
||||||
|
|
||||||
qrContainer.Children.Add(qrSubLabel);
|
qrContainer.Children.Add(qrSubLabel);
|
||||||
|
|||||||
@ -103,7 +103,7 @@ public class PictureGalleryService
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.thumbnails.Add(creationTime, PictureGalleryService.CreateThumbnail(picturePath, 244, 0));
|
this.thumbnails.Add(creationTime, PictureGalleryService.CreateThumbnail(picturePath, 244, 0));
|
||||||
this._logger.Info($"Thumbnail '{picturePath}' successfully created");
|
this._logger.Debug($"Thumbnail '{picturePath}' successfully created");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -115,7 +115,7 @@ public class PictureGalleryService
|
|||||||
}
|
}
|
||||||
while ((loop < cacheSize || cacheSize == 0) && loop < picturePaths.Count);
|
while ((loop < cacheSize || cacheSize == 0) && loop < picturePaths.Count);
|
||||||
});
|
});
|
||||||
this._logger.Info("Loading thumbnails into cache completed");
|
this._logger.Debug("Loading thumbnails into cache completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -253,13 +253,13 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<!-- Text -->
|
<!-- Text -->
|
||||||
<TextBlock Text="Herunterladen"
|
<TextBlock Text="Fotos"
|
||||||
Foreground="White"
|
Foreground="White"
|
||||||
FontSize="10"
|
FontSize="10"
|
||||||
FontWeight="Bold"
|
FontWeight="Bold"
|
||||||
TextAlignment="Center"
|
TextAlignment="Center"
|
||||||
Margin="0,0,0,2"/>
|
Margin="0,0,0,2"/>
|
||||||
<TextBlock Text="Fotos"
|
<TextBlock Text="aufs Handy"
|
||||||
Foreground="#D4AF37"
|
Foreground="#D4AF37"
|
||||||
FontSize="8"
|
FontSize="8"
|
||||||
FontWeight="SemiBold"
|
FontWeight="SemiBold"
|
||||||
@ -525,7 +525,7 @@
|
|||||||
|
|
||||||
<!-- QR-Code Dialog -->
|
<!-- QR-Code Dialog -->
|
||||||
<core:BaseDialogOverlay x:Name="QRCodeOverlay"
|
<core:BaseDialogOverlay x:Name="QRCodeOverlay"
|
||||||
DialogTitle="Online-Fotoalbum"
|
DialogTitle="Alle Fotos aufs Handy"
|
||||||
Grid.RowSpan="2"
|
Grid.RowSpan="2"
|
||||||
Panel.ZIndex="200"/>
|
Panel.ZIndex="200"/>
|
||||||
|
|
||||||
|
|||||||
@ -233,10 +233,14 @@ public partial class MainWindow : Window
|
|||||||
});
|
});
|
||||||
content.Children.Add(new System.Windows.Controls.TextBlock
|
content.Children.Add(new System.Windows.Controls.TextBlock
|
||||||
{
|
{
|
||||||
Text = "Mit einem QR-Code-Scanner scannen",
|
Text = "Nimm dein Handy und halte die Kamera auf den Code.\n" +
|
||||||
|
"Tippe dann auf den Link, der erscheint - schon siehst du alle Fotos.",
|
||||||
Foreground = Brushes.White,
|
Foreground = Brushes.White,
|
||||||
FontSize = 16,
|
FontSize = 18,
|
||||||
TextAlignment = TextAlignment.Center
|
LineHeight = 26,
|
||||||
|
TextAlignment = TextAlignment.Center,
|
||||||
|
TextWrapping = TextWrapping.Wrap,
|
||||||
|
MaxWidth = 420
|
||||||
});
|
});
|
||||||
|
|
||||||
QRCodeOverlay.DialogContent = content;
|
QRCodeOverlay.DialogContent = content;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user