This commit is contained in:
Tobias Wohlleben 2025-01-21 17:30:13 +01:00
parent 0f931aa2d4
commit 9184c8d8ea
9 changed files with 304 additions and 21 deletions

View File

@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:liveView="clr-namespace:CamBooth.App.Features.LiveView"
mc:Ignorable="d" mc:Ignorable="d"
Title="LiveViewPage" Width="1350" Height="900" Title="LiveViewPage" Width="1350" Height="900"
Background="PaleVioletRed"> Background="PaleVioletRed">

View File

@ -58,7 +58,6 @@ public partial class LiveViewPage : Page
} }
} }
public void Dispose() public void Dispose()
{ {
this._cameraService.Dispose(); this._cameraService.Dispose();

View File

@ -0,0 +1,29 @@
<UserControl x:Class="CamBooth.App.Features.LiveView.ModernTimerControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="400">
<Grid>
<!-- Hintergrund für den Timer -->
<Border CornerRadius="20" Background="#1E1E1E" Padding="10" Opacity="60" x:Name="TimerContainer">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<!-- Countdown-Anzeige -->
<TextBlock x:Name="TimerText"
FontSize="288"
Foreground="White"
HorizontalAlignment="Center"
Text="5"
Margin="0,10"/>
<!-- Status-Text -->
<TextBlock x:Name="StatusText"
FontSize="32"
Foreground="Gray"
HorizontalAlignment="Center"
Text="Skunkface machen" />
</StackPanel>
</Border>
</Grid>
</UserControl>

View File

@ -0,0 +1,75 @@
using System.Windows.Controls;
using System.Windows.Media.Animation;
using System.Windows.Threading;
namespace CamBooth.App.Features.LiveView;
public partial class ModernTimerControl : UserControl
{
private DispatcherTimer _timer;
private int _remainingTime; // Zeit in Sekunden
public ModernTimerControl()
{
InitializeComponent();
InitializeTimer();
}
private void InitializeTimer()
{
_timer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(1)
};
_timer.Tick += Timer_Tick;
}
private void Timer_Tick(object sender, EventArgs e)
{
if (_remainingTime > 0)
{
_remainingTime--;
TimerText.Text = TimeSpan.FromSeconds(_remainingTime).ToString(@"mm\:ss");
}
else
{
_timer.Stop();
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);
}
}

View File

@ -0,0 +1,38 @@
<UserControl x:Class="CamBooth.App.Features.LiveView.TimerControlRectangleAnimation"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CamBooth.App.Features.LiveView"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="1350">
<Grid>
<!-- Hintergrund für den Timer -->
<Border CornerRadius="10" Background="Black" Padding="0" Opacity="0" x:Name="TimerContainer">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<!-- Fortschrittsanzeige -->
<Grid Height="100" Width="1350" Background="Gray" Margin="0,0,0,0">
<Rectangle x:Name="ProgressBar"
Fill="#4CAF50"
Height="100"
HorizontalAlignment="Left"/>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="72">HIER EINE ANWEISUNG ANZEIGEN</TextBlock>
</Grid>
<!-- ~1~ Countdown-Anzeige @1@ -->
<!-- <TextBlock x:Name="TimerText" -->
<!-- FontSize="32" -->
<!-- Foreground="White" -->
<!-- HorizontalAlignment="Center" -->
<!-- Text="00:00" -->
<!-- Margin="0,10"/> -->
<!-- ~1~ Status-Text @1@ -->
<!-- <TextBlock x:Name="StatusText" -->
<!-- FontSize="14" -->
<!-- Foreground="Gray" -->
<!-- HorizontalAlignment="Center" -->
<!-- Text="Timer läuft..."/> -->
</StackPanel>
</Border>
</Grid>
</UserControl>

View File

@ -0,0 +1,123 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using Microsoft.Win32;
namespace CamBooth.App.Features.LiveView;
public partial class TimerControlRectangleAnimation : UserControl
{
public delegate void TimerElapsedEventHandler();
public static event TimerElapsedEventHandler OnTimerEllapsed;
private DispatcherTimer _timer;
private int _remainingTime; // Zeit in Sekunden
private double _totalDuration; // Gesamtzeit in Sekunden
private Storyboard _progressBarAnimation;
public TimerControlRectangleAnimation()
{
InitializeComponent();
InitializeTimer();
}
private void InitializeTimer()
{
_timer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(1)
};
_timer.Tick += OnTimerTick;
}
private void OnTimerTick(object sender, EventArgs e)
{
if (_remainingTime > 0)
{
_remainingTime--;
// TimerText.Text = TimeSpan.FromSeconds(_remainingTime).ToString(@"mm\:ss");
}
else
{
_timer.Stop();
// StatusText.Text = "Zeit abgelaufen!";
StopProgressBarAnimation();
OnTimerEllapsed?.Invoke();
}
}
public void StartTimer(int durationInSeconds)
{
_totalDuration = durationInSeconds;
_remainingTime = durationInSeconds;
// TimerText.Text = TimeSpan.FromSeconds(_remainingTime).ToString(@"mm\:ss");
// StatusText.Text = "Timer läuft...";
_timer.Start();
StartProgressBarAnimation();
ShowTimer();
}
public void StopTimer()
{
_timer.Stop();
StopProgressBarAnimation();
// 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);
}
private void StartProgressBarAnimation()
{
// Fortschrittsbalken-Animation
_progressBarAnimation = new Storyboard();
var widthAnimation = new DoubleAnimation
{
From = 1350, // Volle Breite des Containers
To = 0, // Endet bei 0 Breite
Duration = TimeSpan.FromSeconds(_totalDuration),
FillBehavior = FillBehavior.Stop
};
Storyboard.SetTarget(widthAnimation, ProgressBar);
Storyboard.SetTargetProperty(widthAnimation, new PropertyPath(Rectangle.WidthProperty));
_progressBarAnimation.Children.Add(widthAnimation);
_progressBarAnimation.Begin();
}
private void StopProgressBarAnimation()
{
_progressBarAnimation?.Stop();
}
}

View File

@ -5,6 +5,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:local="clr-namespace:CamBooth.App" xmlns:local="clr-namespace:CamBooth.App"
xmlns:liveView="clr-namespace:CamBooth.App.Features.LiveView"
mc:Ignorable="d" mc:Ignorable="d"
Title="MainWindow" Title="MainWindow"
Background="Black" Background="Black"
@ -49,19 +50,18 @@
VerticalAlignment="Bottom" VerticalAlignment="Bottom"
Panel.ZIndex="1" /> Panel.ZIndex="1" />
<StackPanel x:Name="GenericPanelCtl"
Panel.ZIndex="10"
Grid.Row="0">
</StackPanel>
<!-- Inhalt der dritten Zeile --> <!-- Inhalt der dritten Zeile -->
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden" Name="TimerPanel"
Margin="0 0 5 5">
<liveView:TimerControlRectangleAnimation x:Name="TimerControlRectangleAnimation" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Name="ButtonPanel"
Margin="0 0 5 5"> Margin="0 0 5 5">
<ui:Button Content="Start" Click="NavToLiveView" Width="200" Height="50" VerticalAlignment="Bottom" <ui:Button Content="Start" Click="NavToLiveView" Width="200" Height="50" VerticalAlignment="Bottom"
Margin="0 0 5 5" /> Margin="0 0 5 5" />
<ui:Button Content="Hide Debug" Click="SetVisibilityDebugConsole" Width="200" Height="50" <ui:Button Content="Hide Debug" Click="SetVisibilityDebugConsole" Width="200" Height="50"
VerticalAlignment="Bottom" Margin="0 0 5 5" /> VerticalAlignment="Bottom" Margin="0 0 5 5" />
<ui:Button Content="Take Photo" Click="TakePhoto" Width="200" Height="50" VerticalAlignment="Bottom" <ui:Button Content="Take Photo" Click="StartTakePhotoProcess" Width="200" Height="50" VerticalAlignment="Bottom"
Margin="0 0 5 5" /> Margin="0 0 5 5" />
<ui:Button Content="Pictures" Click="SetVisibilityPicturePanel" Width="200" Height="50" <ui:Button Content="Pictures" Click="SetVisibilityPicturePanel" Width="200" Height="50"
VerticalAlignment="Bottom" Margin="0 0 5 5" /> VerticalAlignment="Bottom" Margin="0 0 5 5" />

View File

@ -30,7 +30,8 @@ public partial class MainWindow : Window
private LiveViewPage? _liveViewPage; private LiveViewPage? _liveViewPage;
public MainWindow(Logger logger, public MainWindow(
Logger logger,
AppSettingsService appSettings, AppSettingsService appSettings,
PictureGalleryService pictureGalleryService, PictureGalleryService pictureGalleryService,
CameraService cameraService) CameraService cameraService)
@ -44,9 +45,27 @@ public partial class MainWindow : Window
this.SetVisibilityPicturePanel(this._isPicturePanelVisible); this.SetVisibilityPicturePanel(this._isPicturePanelVisible);
_ = this._pictureGalleryService.LoadThumbnailsToCache(); _ = this._pictureGalleryService.LoadThumbnailsToCache();
this.Closing += OnClosing; this.Closing += OnClosing;
TimerControlRectangleAnimation.OnTimerEllapsed += TimerControlRectangleAnimation_OnTimerEllapsed;
logger.Info("MainWindow initialized"); logger.Info("MainWindow initialized");
} }
private void TimerControlRectangleAnimation_OnTimerEllapsed()
{
try
{
this._cameraService.TakePhoto();
SwitchButtonAndTimerPanel();
}
catch (Exception exception)
{
//TODO: mit content dialog ersetzen
System.Windows.MessageBox.Show("Sorry, da ging was schief!");
this._logger.Info(exception.Message);
}
}
private void SetVisibilityPicturePanel(bool visibility) private void SetVisibilityPicturePanel(bool visibility)
{ {
if (visibility) if (visibility)
@ -96,19 +115,17 @@ public partial class MainWindow : Window
} }
private void TakePhoto(object sender, RoutedEventArgs e) private void StartTakePhotoProcess(object sender, RoutedEventArgs e)
{ {
try TimerControlRectangleAnimation.StartTimer(5);
{ SwitchButtonAndTimerPanel();
this._cameraService.TakePhoto();
}
catch (Exception exception)
{
System.Windows.MessageBox.Show("Sorry, da ging was schief!");
this._logger.Info(exception.Message);
}
} }
private void SwitchButtonAndTimerPanel()
{
this.ButtonPanel.Visibility = this.ButtonPanel.Visibility == Visibility.Hidden ? Visibility.Visible : Visibility.Hidden;
this.TimerPanel.Visibility = this.TimerPanel.Visibility == Visibility.Hidden ? Visibility.Visible : Visibility.Hidden;
}
private void SetVisibilityPicturePanel(object sender, RoutedEventArgs e) private void SetVisibilityPicturePanel(object sender, RoutedEventArgs e)
{ {

View File

@ -11,5 +11,6 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEventRoute_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003Ftobia_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F4bda76b5cc453e1edf5d5c754c4a8215edbd3d3e4f80706dcf4f52a4f68979_003FEventRoute_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEventRoute_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003Ftobia_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F4bda76b5cc453e1edf5d5c754c4a8215edbd3d3e4f80706dcf4f52a4f68979_003FEventRoute_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003Ftobia_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F793c644a163b4a9992123fa9cc1562efbf3908_003F4a_003Fd28af422_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003Ftobia_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F793c644a163b4a9992123fa9cc1562efbf3908_003F4a_003Fd28af422_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003Ftobia_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fbd1d5c50194fea68ff3559c160230b0ab50f5acf4ce3061bffd6d62958e2182_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003Ftobia_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fbd1d5c50194fea68ff3559c160230b0ab50f5acf4ce3061bffd6d62958e2182_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATimerElapsedEventArgs_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003Ftobia_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F84fc76ffb0d44a0784938f79e15bb37217928_003F20_003Fb02e4ce4_003FTimerElapsedEventArgs_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWindow_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003Ftobia_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F0713c794b56e4feca091d5981a6f5967f60930_003Fc8_003F61b7e802_003FWindow_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWindow_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003Ftobia_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F0713c794b56e4feca091d5981a6f5967f60930_003Fc8_003F61b7e802_003FWindow_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWindow_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003Ftobia_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fd0db11e55b76dc7f234163f6cee32b297b8ddb591fb0b5cbad1b46ed17343e18_003FWindow_002Ecs_002Fz_003A2_002D1/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWindow_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003Ftobia_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fd0db11e55b76dc7f234163f6cee32b297b8ddb591fb0b5cbad1b46ed17343e18_003FWindow_002Ecs_002Fz_003A2_002D1/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>