mirror of
https://github.com/claunia/marechai.git
synced 2025-12-16 19:14:25 +00:00
Add photo detail page.
This commit is contained in:
@@ -17,6 +17,7 @@ using ComputersViewModel = Marechai.App.Presentation.ViewModels.ComputersViewMod
|
|||||||
using MachineViewViewModel = Marechai.App.Presentation.ViewModels.MachineViewViewModel;
|
using MachineViewViewModel = Marechai.App.Presentation.ViewModels.MachineViewViewModel;
|
||||||
using MainViewModel = Marechai.App.Presentation.ViewModels.MainViewModel;
|
using MainViewModel = Marechai.App.Presentation.ViewModels.MainViewModel;
|
||||||
using NewsViewModel = Marechai.App.Presentation.ViewModels.NewsViewModel;
|
using NewsViewModel = Marechai.App.Presentation.ViewModels.NewsViewModel;
|
||||||
|
using PhotoDetailViewModel = Marechai.App.Presentation.ViewModels.PhotoDetailViewModel;
|
||||||
|
|
||||||
namespace Marechai.App;
|
namespace Marechai.App;
|
||||||
|
|
||||||
@@ -121,6 +122,7 @@ public partial class App : Application
|
|||||||
services.AddSingleton<CompanyDetailService>();
|
services.AddSingleton<CompanyDetailService>();
|
||||||
services.AddSingleton<CompanyDetailViewModel>();
|
services.AddSingleton<CompanyDetailViewModel>();
|
||||||
services.AddSingleton<MachineViewViewModel>();
|
services.AddSingleton<MachineViewViewModel>();
|
||||||
|
services.AddTransient<PhotoDetailViewModel>();
|
||||||
|
|
||||||
services
|
services
|
||||||
.AddSingleton<IComputersListFilterContext,
|
.AddSingleton<IComputersListFilterContext,
|
||||||
@@ -157,6 +159,7 @@ public partial class App : Application
|
|||||||
new ViewMap<CompaniesPage, CompaniesViewModel>(),
|
new ViewMap<CompaniesPage, CompaniesViewModel>(),
|
||||||
new ViewMap<CompanyDetailPage, CompanyDetailViewModel>(),
|
new ViewMap<CompanyDetailPage, CompanyDetailViewModel>(),
|
||||||
new ViewMap<MachineViewPage, MachineViewViewModel>(),
|
new ViewMap<MachineViewPage, MachineViewViewModel>(),
|
||||||
|
new ViewMap<PhotoDetailPage, PhotoDetailViewModel>(),
|
||||||
new DataViewMap<SecondPage, SecondViewModel, Entity>());
|
new DataViewMap<SecondPage, SecondViewModel, Entity>());
|
||||||
|
|
||||||
routes.Register(new RouteMap("",
|
routes.Register(new RouteMap("",
|
||||||
|
|||||||
@@ -171,6 +171,18 @@ public partial class MachineViewViewModel : ObservableObject
|
|||||||
await _navigator.GoBack(this);
|
await _navigator.GoBack(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public async Task ViewPhotoDetails(Guid photoId)
|
||||||
|
{
|
||||||
|
var navParam = new PhotoDetailNavigationParameter
|
||||||
|
{
|
||||||
|
PhotoId = photoId
|
||||||
|
};
|
||||||
|
|
||||||
|
_logger.LogInformation("Navigating to photo details for {PhotoId}", photoId);
|
||||||
|
await _navigator.NavigateViewModelAsync<PhotoDetailViewModel>(this, data: navParam);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the navigation source (where we came from).
|
/// Sets the navigation source (where we came from).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
423
Marechai.App/Presentation/ViewModels/PhotoDetailViewModel.cs
Normal file
423
Marechai.App/Presentation/ViewModels/PhotoDetailViewModel.cs
Normal file
@@ -0,0 +1,423 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
// MARECHAI: Master repository of computing history artifacts information
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||||
|
//
|
||||||
|
// --[ License ] --------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Copyright © 2003-2026 Natalia Portillo
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Windows.Storage.Streams;
|
||||||
|
using Humanizer;
|
||||||
|
using Marechai.App.Services;
|
||||||
|
using Marechai.App.Services.Caching;
|
||||||
|
using Microsoft.UI.Xaml.Media.Imaging;
|
||||||
|
using Uno.Extensions.Navigation;
|
||||||
|
using ColorSpace = Marechai.Data.ColorSpace;
|
||||||
|
using Contrast = Marechai.Data.Contrast;
|
||||||
|
using ExposureMode = Marechai.Data.ExposureMode;
|
||||||
|
using ExposureProgram = Marechai.Data.ExposureProgram;
|
||||||
|
using Flash = Marechai.Data.Flash;
|
||||||
|
using LightSource = Marechai.Data.LightSource;
|
||||||
|
using MeteringMode = Marechai.Data.MeteringMode;
|
||||||
|
using Orientation = Marechai.Data.Orientation;
|
||||||
|
using ResolutionUnit = Marechai.Data.ResolutionUnit;
|
||||||
|
using Saturation = Marechai.Data.Saturation;
|
||||||
|
using SceneCaptureType = Marechai.Data.SceneCaptureType;
|
||||||
|
using SensingMethod = Marechai.Data.SensingMethod;
|
||||||
|
using Sharpness = Marechai.Data.Sharpness;
|
||||||
|
using SubjectDistanceRange = Marechai.Data.SubjectDistanceRange;
|
||||||
|
using WhiteBalance = Marechai.Data.WhiteBalance;
|
||||||
|
|
||||||
|
namespace Marechai.App.Presentation.ViewModels;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Navigation parameter for photo detail page
|
||||||
|
/// </summary>
|
||||||
|
public class PhotoDetailNavigationParameter
|
||||||
|
{
|
||||||
|
public Guid PhotoId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class PhotoDetailViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
private readonly ComputersService _computersService;
|
||||||
|
private readonly ILogger<PhotoDetailViewModel> _logger;
|
||||||
|
private readonly INavigator _navigator;
|
||||||
|
private readonly MachinePhotoCache _photoCache;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _errorMessage = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _errorOccurred;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isLoading;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isPortrait = true;
|
||||||
|
|
||||||
|
// EXIF Camera Settings
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoAperture = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoAuthor = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoCameraManufacturer = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoCameraModel = string.Empty;
|
||||||
|
|
||||||
|
// Photo Properties
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoColorSpace = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoComments = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoContrast = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoCreationDate = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoDigitalZoomRatio = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoExifVersion = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoExposureMode = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoExposureProgram = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoExposureTime = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoFlash = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoFocalLength = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoFocalLengthEquivalent = string.Empty;
|
||||||
|
|
||||||
|
// Resolution and Other
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoHorizontalResolution = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private BitmapImage? _photoImageSource;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoIsoRating = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoLensModel = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoLicenseName = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoLightSource = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoMachineCompany = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoMachineName = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoMeteringMode = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoOrientation = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoOriginalExtension = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoResolutionUnit = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoSaturation = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoSceneCaptureType = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoSensingMethod = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoSharpness = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoSoftwareUsed = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoSource = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoSubjectDistanceRange = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoUploadDate = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoVerticalResolution = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _photoWhiteBalance = string.Empty;
|
||||||
|
|
||||||
|
public PhotoDetailViewModel(ILogger<PhotoDetailViewModel> logger, INavigator navigator,
|
||||||
|
ComputersService computersService, MachinePhotoCache photoCache)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_navigator = navigator;
|
||||||
|
_computersService = computersService;
|
||||||
|
_photoCache = photoCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public async Task GoBack()
|
||||||
|
{
|
||||||
|
await _navigator.GoBack(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public async Task LoadPhoto(Guid photoId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IsLoading = true;
|
||||||
|
ErrorOccurred = false;
|
||||||
|
ErrorMessage = string.Empty;
|
||||||
|
PhotoImageSource = null;
|
||||||
|
|
||||||
|
_logger.LogInformation("Loading photo details for {PhotoId}", photoId);
|
||||||
|
|
||||||
|
// Fetch photo details from API
|
||||||
|
MachinePhotoDto? photo = await _computersService.GetMachinePhotoDetailsAsync(photoId);
|
||||||
|
|
||||||
|
if(photo is null)
|
||||||
|
{
|
||||||
|
ErrorOccurred = true;
|
||||||
|
ErrorMessage = "Photo not found";
|
||||||
|
IsLoading = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate photo information
|
||||||
|
PhotoAuthor = photo.Author ?? string.Empty;
|
||||||
|
PhotoCameraManufacturer = photo.CameraManufacturer ?? string.Empty;
|
||||||
|
PhotoCameraModel = photo.CameraModel ?? string.Empty;
|
||||||
|
PhotoComments = photo.Comments ?? string.Empty;
|
||||||
|
PhotoLensModel = photo.Lens ?? string.Empty;
|
||||||
|
PhotoLicenseName = photo.LicenseName ?? string.Empty;
|
||||||
|
PhotoMachineCompany = photo.MachineCompanyName ?? string.Empty;
|
||||||
|
PhotoMachineName = photo.MachineName ?? string.Empty;
|
||||||
|
PhotoOriginalExtension = photo.OriginalExtension ?? string.Empty;
|
||||||
|
|
||||||
|
if(photo.CreationDate.HasValue)
|
||||||
|
PhotoCreationDate = photo.CreationDate.Value.ToString("MMMM d, yyyy 'at' HH:mm");
|
||||||
|
|
||||||
|
// EXIF Camera Settings
|
||||||
|
PhotoAperture = photo.Aperture != null ? $"f/{photo.Aperture}" : string.Empty;
|
||||||
|
PhotoExposureTime = photo.Exposure != null ? $"{photo.Exposure}s" : string.Empty;
|
||||||
|
|
||||||
|
PhotoExposureMode =
|
||||||
|
ExtractAndHumanizeEnum(photo.ExposureMethod?.MachinePhotoDtoExposureMethodMember1?.AdditionalData,
|
||||||
|
typeof(ExposureMode));
|
||||||
|
|
||||||
|
PhotoExposureProgram = photo.ExposureProgram?.ExposureProgram != null
|
||||||
|
? ((ExposureProgram)ExtractInt(photo.ExposureProgram.ExposureProgram
|
||||||
|
.AdditionalData)).Humanize()
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
PhotoFocalLength = photo.FocalLength != null ? $"{photo.FocalLength}mm" : string.Empty;
|
||||||
|
PhotoFocalLengthEquivalent = photo.FocalEquivalent != null ? $"{photo.FocalEquivalent}mm" : string.Empty;
|
||||||
|
PhotoIsoRating = photo.Iso != null ? photo.Iso.ToString() : string.Empty;
|
||||||
|
|
||||||
|
PhotoFlash = photo.Flash?.Flash != null
|
||||||
|
? ((Flash)ExtractInt(photo.Flash.Flash.AdditionalData)).Humanize()
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
PhotoLightSource = photo.LightSource?.LightSource != null
|
||||||
|
? ((LightSource)ExtractInt(photo.LightSource.LightSource.AdditionalData)).Humanize()
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
PhotoMeteringMode = photo.MeteringMode?.MeteringMode != null
|
||||||
|
? ((MeteringMode)ExtractInt(photo.MeteringMode.MeteringMode.AdditionalData))
|
||||||
|
.Humanize()
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
PhotoWhiteBalance = photo.WhiteBalance?.WhiteBalance != null
|
||||||
|
? ((WhiteBalance)ExtractInt(photo.WhiteBalance.WhiteBalance.AdditionalData))
|
||||||
|
.Humanize()
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
// Photo Properties
|
||||||
|
PhotoColorSpace = ExtractAndHumanizeEnum(photo.Colorspace?.MachinePhotoDtoColorspaceMember1?.AdditionalData,
|
||||||
|
typeof(ColorSpace));
|
||||||
|
|
||||||
|
PhotoContrast = photo.Contrast?.Contrast != null
|
||||||
|
? ((Contrast)ExtractInt(photo.Contrast.Contrast.AdditionalData)).Humanize()
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
PhotoSaturation = photo.Saturation?.Saturation != null
|
||||||
|
? ((Saturation)ExtractInt(photo.Saturation.Saturation.AdditionalData)).Humanize()
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
PhotoSharpness = photo.Sharpness?.Sharpness != null
|
||||||
|
? ((Sharpness)ExtractInt(photo.Sharpness.Sharpness.AdditionalData)).Humanize()
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
PhotoOrientation = photo.Orientation?.Orientation != null
|
||||||
|
? ((Orientation)ExtractInt(photo.Orientation.Orientation.AdditionalData)).Humanize()
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
PhotoSceneCaptureType = photo.SceneCaptureType?.SceneCaptureType != null
|
||||||
|
? ((SceneCaptureType)ExtractInt(photo.SceneCaptureType.SceneCaptureType
|
||||||
|
.AdditionalData)).Humanize()
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
PhotoSensingMethod = photo.SensingMethod?.SensingMethod != null
|
||||||
|
? ((SensingMethod)ExtractInt(photo.SensingMethod.SensingMethod.AdditionalData))
|
||||||
|
.Humanize()
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
PhotoSubjectDistanceRange = photo.SubjectDistanceRange?.SubjectDistanceRange != null
|
||||||
|
? ((SubjectDistanceRange)ExtractInt(photo.SubjectDistanceRange
|
||||||
|
.SubjectDistanceRange
|
||||||
|
.AdditionalData)).Humanize()
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
// Resolution and Other
|
||||||
|
PhotoHorizontalResolution =
|
||||||
|
photo.HorizontalResolution != null ? $"{photo.HorizontalResolution} DPI" : string.Empty;
|
||||||
|
|
||||||
|
PhotoVerticalResolution =
|
||||||
|
photo.VerticalResolution != null ? $"{photo.VerticalResolution} DPI" : string.Empty;
|
||||||
|
|
||||||
|
PhotoResolutionUnit = photo.ResolutionUnit?.ResolutionUnit != null
|
||||||
|
? ((ResolutionUnit)ExtractInt(photo.ResolutionUnit.ResolutionUnit.AdditionalData))
|
||||||
|
.Humanize()
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
PhotoDigitalZoomRatio = photo.DigitalZoom != null ? $"{photo.DigitalZoom}x" : string.Empty;
|
||||||
|
PhotoExifVersion = photo.ExifVersion ?? string.Empty;
|
||||||
|
PhotoSoftwareUsed = photo.Software ?? string.Empty;
|
||||||
|
|
||||||
|
PhotoUploadDate = photo.UploadDate.HasValue
|
||||||
|
? photo.UploadDate.Value.ToString("MMMM d, yyyy 'at' HH:mm")
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
PhotoSource = photo.Source ?? string.Empty;
|
||||||
|
|
||||||
|
// Load the full photo image
|
||||||
|
await LoadPhotoImageAsync(photoId);
|
||||||
|
|
||||||
|
IsLoading = false;
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error loading photo details for {PhotoId}", photoId);
|
||||||
|
ErrorOccurred = true;
|
||||||
|
ErrorMessage = ex.Message;
|
||||||
|
IsLoading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the portrait/landscape orientation flag
|
||||||
|
/// </summary>
|
||||||
|
public void UpdateOrientation(bool isPortrait)
|
||||||
|
{
|
||||||
|
IsPortrait = isPortrait;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadPhotoImageAsync(Guid photoId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Stream stream = await _photoCache.GetPhotoAsync(photoId);
|
||||||
|
|
||||||
|
var bitmap = new BitmapImage();
|
||||||
|
|
||||||
|
using(IRandomAccessStream randomStream = stream.AsRandomAccessStream())
|
||||||
|
{
|
||||||
|
await bitmap.SetSourceAsync(randomStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
PhotoImageSource = bitmap;
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error loading photo image {PhotoId}", photoId);
|
||||||
|
ErrorOccurred = true;
|
||||||
|
ErrorMessage = "Failed to load photo image";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extracts an integer value from AdditionalData dictionary
|
||||||
|
/// </summary>
|
||||||
|
private int ExtractInt(IDictionary<string, object> additionalData)
|
||||||
|
{
|
||||||
|
if(additionalData == null || additionalData.Count == 0) return 0;
|
||||||
|
|
||||||
|
object? value = additionalData.Values.FirstOrDefault();
|
||||||
|
|
||||||
|
if(value is int intValue) return intValue;
|
||||||
|
if(value is double dblValue) return (int)dblValue;
|
||||||
|
if(int.TryParse(value?.ToString() ?? "", out int parsed)) return parsed;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Humanizes an enum value extracted from AdditionalData
|
||||||
|
/// </summary>
|
||||||
|
private string ExtractAndHumanizeEnum(IDictionary<string, object>? additionalData, Type enumType)
|
||||||
|
{
|
||||||
|
if(additionalData == null || additionalData.Count == 0) return string.Empty;
|
||||||
|
|
||||||
|
int intValue = ExtractInt(additionalData);
|
||||||
|
|
||||||
|
if(intValue == 0 && enumType != typeof(ExposureMode)) return string.Empty;
|
||||||
|
|
||||||
|
var enumValue = Enum.ToObject(enumType, intValue);
|
||||||
|
|
||||||
|
return ((Enum)enumValue).Humanize();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -389,6 +389,10 @@
|
|||||||
HorizontalAlignment="Stretch">
|
HorizontalAlignment="Stretch">
|
||||||
<wctui:Carousel.ItemTemplate>
|
<wctui:Carousel.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
|
<Button Command="{Binding DataContext.ViewPhotoDetailsCommand, ElementName=PageRoot}"
|
||||||
|
CommandParameter="{Binding PhotoId}"
|
||||||
|
Padding="0"
|
||||||
|
Background="Transparent">
|
||||||
<Grid Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
<Grid Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center">
|
VerticalAlignment="Center">
|
||||||
@@ -399,6 +403,7 @@
|
|||||||
MaxWidth="256"
|
MaxWidth="256"
|
||||||
MaxHeight="256" />
|
MaxHeight="256" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</Button>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</wctui:Carousel.ItemTemplate>
|
</wctui:Carousel.ItemTemplate>
|
||||||
</wctui:Carousel>
|
</wctui:Carousel>
|
||||||
|
|||||||
552
Marechai.App/Presentation/Views/PhotoDetailPage.xaml
Normal file
552
Marechai.App/Presentation/Views/PhotoDetailPage.xaml
Normal file
@@ -0,0 +1,552 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<Page x:Class="Marechai.App.Presentation.Views.PhotoDetailPage"
|
||||||
|
x:Name="PageRoot"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:utu="using:Uno.Toolkit.UI"
|
||||||
|
NavigationCacheMode="Disabled"
|
||||||
|
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
|
|
||||||
|
<Grid RowSpacing="0">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- Header with Back Button -->
|
||||||
|
<Grid Grid.Row="0"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||||
|
BorderThickness="0,0,0,1"
|
||||||
|
Padding="12,12,16,12">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Button Grid.Column="0"
|
||||||
|
Command="{Binding GoBackCommand}"
|
||||||
|
Style="{ThemeResource AlternateButtonStyle}"
|
||||||
|
ToolTipService.ToolTip="Go back"
|
||||||
|
Padding="8"
|
||||||
|
MinWidth="44"
|
||||||
|
MinHeight="44"
|
||||||
|
VerticalAlignment="Center">
|
||||||
|
<FontIcon Glyph="" FontSize="16" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<StackPanel Grid.Column="1"
|
||||||
|
Margin="12,0,0,0"
|
||||||
|
VerticalAlignment="Center">
|
||||||
|
<TextBlock Text="Photo Details"
|
||||||
|
FontSize="20"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
TextTrimming="CharacterEllipsis" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<Grid Grid.Row="1">
|
||||||
|
|
||||||
|
<!-- Loading State -->
|
||||||
|
<StackPanel Visibility="{Binding IsLoading}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Padding="32"
|
||||||
|
Spacing="16">
|
||||||
|
<ProgressRing IsActive="True"
|
||||||
|
IsIndeterminate="True"
|
||||||
|
Height="64"
|
||||||
|
Width="64" />
|
||||||
|
<TextBlock Text="Loading photo..."
|
||||||
|
FontSize="14"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Error State -->
|
||||||
|
<StackPanel Visibility="{Binding ErrorOccurred}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Padding="24"
|
||||||
|
Spacing="16"
|
||||||
|
MaxWidth="400">
|
||||||
|
<InfoBar IsOpen="True"
|
||||||
|
Severity="Error"
|
||||||
|
Title="Unable to Load Photo"
|
||||||
|
Message="{Binding ErrorMessage}"
|
||||||
|
IsClosable="False" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Responsive Layout -->
|
||||||
|
<utu:ResponsiveView Visibility="{Binding PhotoImageSource, Converter={StaticResource ObjectToVisibilityConverter}}">
|
||||||
|
|
||||||
|
<!-- Narrow Template -->
|
||||||
|
<utu:ResponsiveView.NarrowTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto"
|
||||||
|
HorizontalScrollBarVisibility="Disabled">
|
||||||
|
<StackPanel Padding="16" Spacing="24">
|
||||||
|
|
||||||
|
<!-- Photo -->
|
||||||
|
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="8"
|
||||||
|
MaxHeight="400"
|
||||||
|
MinHeight="250">
|
||||||
|
<ScrollViewer HorizontalScrollBarVisibility="Auto"
|
||||||
|
VerticalScrollBarVisibility="Auto"
|
||||||
|
ZoomMode="Enabled">
|
||||||
|
<Image Source="{Binding PhotoImageSource}"
|
||||||
|
Stretch="Uniform"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</ScrollViewer>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Metadata Sections -->
|
||||||
|
<StackPanel Spacing="16">
|
||||||
|
|
||||||
|
<!-- Machine -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Machine" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoMachineName, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Name" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoMachineName}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoMachineCompany, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Company" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoMachineCompany}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Camera -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Camera" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoCameraManufacturer, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Manufacturer" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoCameraManufacturer}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoCameraModel, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Model" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoCameraModel}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoLensModel, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Lens" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoLensModel}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoSoftwareUsed, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Software" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoSoftwareUsed}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Exposure Settings -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Exposure Settings" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoAperture, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Aperture" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoAperture}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoExposureTime, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Exposure Time" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoExposureTime}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoExposureMode, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Exposure Mode" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoExposureMode}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoExposureProgram, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Exposure Program" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoExposureProgram}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoIsoRating, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="ISO Rating" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoIsoRating}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Flash & Light -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Flash & Light" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoFlash, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Flash" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoFlash}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoLightSource, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Light Source" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoLightSource}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoMeteringMode, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Metering Mode" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoMeteringMode}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoWhiteBalance, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="White Balance" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoWhiteBalance}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Focal Length -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Focal Length" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoFocalLength, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Focal Length" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoFocalLength}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoFocalLengthEquivalent, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="35mm Equivalent" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoFocalLengthEquivalent}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoDigitalZoomRatio, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Digital Zoom" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoDigitalZoomRatio}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Image Properties -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Image Properties" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoColorSpace, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Color Space" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoColorSpace}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoContrast, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Contrast" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoContrast}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoSaturation, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Saturation" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoSaturation}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoSharpness, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Sharpness" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoSharpness}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoOrientation, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Orientation" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoOrientation}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoSceneCaptureType, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Scene Capture Type" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoSceneCaptureType}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Resolution -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Resolution" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoHorizontalResolution, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Horizontal Resolution" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoHorizontalResolution}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoVerticalResolution, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Vertical Resolution" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoVerticalResolution}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoResolutionUnit, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Resolution Unit" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoResolutionUnit}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- File & Metadata -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="File & Metadata" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoOriginalExtension, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Original Format" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoOriginalExtension}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoCreationDate, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Date Taken" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoCreationDate}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoUploadDate, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Upload Date" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoUploadDate}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoExifVersion, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="EXIF Version" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoExifVersion}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoAuthor, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Author" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoAuthor}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoLicenseName, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="License" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoLicenseName}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoComments, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Comments" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoComments}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoSource, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Source" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoSource}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Additional Sensors -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Advanced" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoSensingMethod, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Sensing Method" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoSensingMethod}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoSubjectDistanceRange, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Subject Distance Range" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoSubjectDistanceRange}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Border Height="24" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</DataTemplate>
|
||||||
|
</utu:ResponsiveView.NarrowTemplate>
|
||||||
|
|
||||||
|
<!-- Wide Template -->
|
||||||
|
<utu:ResponsiveView.WideTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Grid Padding="16" ColumnSpacing="24">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="1*" />
|
||||||
|
<ColumnDefinition Width="1*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- Photo on left -->
|
||||||
|
<Border Grid.Column="0"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="8"
|
||||||
|
VerticalAlignment="Top">
|
||||||
|
<ScrollViewer HorizontalScrollBarVisibility="Auto"
|
||||||
|
VerticalScrollBarVisibility="Auto"
|
||||||
|
ZoomMode="Enabled"
|
||||||
|
MaxHeight="500">
|
||||||
|
<Image Source="{Binding PhotoImageSource}"
|
||||||
|
Stretch="Uniform"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</ScrollViewer>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Info on right -->
|
||||||
|
<ScrollViewer Grid.Column="1"
|
||||||
|
VerticalScrollBarVisibility="Auto"
|
||||||
|
HorizontalScrollBarVisibility="Disabled">
|
||||||
|
<StackPanel Spacing="16" Padding="8">
|
||||||
|
<!-- Same content as narrow template -->
|
||||||
|
<!-- Machine -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Machine" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoMachineName, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Name" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoMachineName}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoMachineCompany, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Company" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoMachineCompany}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Camera -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Camera" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoCameraManufacturer, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Manufacturer" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoCameraManufacturer}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoCameraModel, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Model" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoCameraModel}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoLensModel, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Lens" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoLensModel}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoSoftwareUsed, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Software" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoSoftwareUsed}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Exposure Settings -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Exposure Settings" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoAperture, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Aperture" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoAperture}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoExposureTime, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Exposure Time" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoExposureTime}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoExposureMode, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Exposure Mode" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoExposureMode}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoExposureProgram, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Exposure Program" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoExposureProgram}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoIsoRating, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="ISO Rating" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoIsoRating}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Flash & Light -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Flash & Light" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoFlash, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Flash" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoFlash}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoLightSource, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Light Source" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoLightSource}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoMeteringMode, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Metering Mode" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoMeteringMode}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoWhiteBalance, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="White Balance" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoWhiteBalance}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Focal Length -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Focal Length" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoFocalLength, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Focal Length" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoFocalLength}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoFocalLengthEquivalent, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="35mm Equivalent" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoFocalLengthEquivalent}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoDigitalZoomRatio, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Digital Zoom" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoDigitalZoomRatio}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Image Properties -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Image Properties" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoColorSpace, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Color Space" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoColorSpace}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoContrast, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Contrast" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoContrast}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoSaturation, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Saturation" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoSaturation}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoSharpness, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Sharpness" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoSharpness}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoOrientation, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Orientation" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoOrientation}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoSceneCaptureType, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Scene Capture Type" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoSceneCaptureType}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Resolution -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Resolution" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoHorizontalResolution, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Horizontal Resolution" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoHorizontalResolution}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoVerticalResolution, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Vertical Resolution" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoVerticalResolution}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoResolutionUnit, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Resolution Unit" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoResolutionUnit}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- File & Metadata -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="File & Metadata" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoOriginalExtension, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Original Format" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoOriginalExtension}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoCreationDate, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Date Taken" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoCreationDate}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoUploadDate, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Upload Date" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoUploadDate}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoExifVersion, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="EXIF Version" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoExifVersion}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoAuthor, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Author" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoAuthor}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoLicenseName, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="License" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoLicenseName}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoComments, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Comments" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoComments}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoSource, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Source" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoSource}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Advanced -->
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock Text="Advanced" FontSize="14" FontWeight="SemiBold" />
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoSensingMethod, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Sensing Method" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoSensingMethod}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Spacing="4" Visibility="{Binding PhotoSubjectDistanceRange, Converter={StaticResource StringToVisibilityConverter}}">
|
||||||
|
<TextBlock Text="Subject Distance Range" FontSize="12" FontWeight="SemiBold" Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding PhotoSubjectDistanceRange}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Border Height="24" />
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</utu:ResponsiveView.WideTemplate>
|
||||||
|
|
||||||
|
</utu:ResponsiveView>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Page>
|
||||||
41
Marechai.App/Presentation/Views/PhotoDetailPage.xaml.cs
Normal file
41
Marechai.App/Presentation/Views/PhotoDetailPage.xaml.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using Marechai.App.Presentation.ViewModels;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Microsoft.UI.Xaml.Navigation;
|
||||||
|
|
||||||
|
namespace Marechai.App.Presentation.Views;
|
||||||
|
|
||||||
|
public sealed partial class PhotoDetailPage : Page
|
||||||
|
{
|
||||||
|
private Guid? _pendingPhotoId;
|
||||||
|
|
||||||
|
public PhotoDetailPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
DataContextChanged += PhotoDetailPage_DataContextChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnNavigatedTo(e);
|
||||||
|
|
||||||
|
Guid? photoId = null;
|
||||||
|
|
||||||
|
if(e.Parameter is PhotoDetailNavigationParameter param) photoId = param.PhotoId;
|
||||||
|
|
||||||
|
if(photoId.HasValue)
|
||||||
|
{
|
||||||
|
_pendingPhotoId = photoId;
|
||||||
|
|
||||||
|
if(DataContext is PhotoDetailViewModel viewModel)
|
||||||
|
_ = viewModel.LoadPhotoCommand.ExecuteAsync(photoId.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PhotoDetailPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||||
|
{
|
||||||
|
if(DataContext is PhotoDetailViewModel viewModel && _pendingPhotoId.HasValue)
|
||||||
|
_ = viewModel.LoadPhotoCommand.ExecuteAsync(_pendingPhotoId.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -235,4 +235,34 @@ public class ComputersService
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches detailed information for a specific photo from the API
|
||||||
|
/// </summary>
|
||||||
|
public async Task<MachinePhotoDto?> GetMachinePhotoDetailsAsync(Guid photoId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Fetching photo details for {PhotoId} from API", photoId);
|
||||||
|
|
||||||
|
MachinePhotoDto? photo = await _apiClient.Machines.Photos[photoId].GetAsync();
|
||||||
|
|
||||||
|
if(photo == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Photo {PhotoId} not found", photoId);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("Successfully fetched photo details {PhotoId}", photoId);
|
||||||
|
|
||||||
|
return photo;
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error fetching photo details for {PhotoId} from API", photoId);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user