Notes and Profile Pictures are now working, and Mother and Father selections are no longer just Ids

This commit is contained in:
2026-01-05 21:14:31 -06:00
parent a1fc2f8d7c
commit 178af390d5
5 changed files with 164 additions and 41 deletions

View File

@@ -1,3 +1,4 @@
using System.IO;
using Avalonia; using Avalonia;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core; using Avalonia.Data.Core;
@@ -37,6 +38,8 @@ public partial class App : Application
} }
// Other init stuff here // Other init stuff here
Directory.CreateDirectory(Sys.UserDataPath);
Directory.CreateDirectory(Path.Combine(Sys.UserDataPath, "ImageCache"));
base.OnFrameworkInitializationCompleted(); base.OnFrameworkInitializationCompleted();

View File

@@ -11,7 +11,7 @@
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
x:Name="MainButton"> x:Name="MainButton">
<Grid ColumnDefinitions="Auto, *, Auto"> <Grid ColumnDefinitions="Auto, *, Auto">
<Image x:Name="ProfileImage" Grid.Column="0" Width="80" Height="80" Stretch="UniformToFill" Source="avares://CritterFolio/Assets/Icon.png" /> <Image x:Name="ProfileImage" Grid.Column="0" Width="75" Height="75" Stretch="UniformToFill" Source="avares://CritterFolio/Assets/Icon.png" />
<Label x:Name="ProfileNameLabel" Grid.Column="1" VerticalAlignment="Center" FontSize="18" Margin="20, 0" /> <Label x:Name="ProfileNameLabel" Grid.Column="1" VerticalAlignment="Center" FontSize="18" Margin="20, 0" />
</Grid> </Grid>
</Button> </Button>

View File

@@ -7,6 +7,7 @@ public class Document
{ {
[PrimaryKey, AutoIncrement] [PrimaryKey, AutoIncrement]
public int Id { get; set; } public int Id { get; set; }
public int CritterId { get; set; }
public string Name { get; set; } public string Name { get; set; } = "Document";
public string Description { get; set; } = "A Document";
} }

View File

@@ -7,6 +7,7 @@
<ScrollViewer HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <ScrollViewer HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<StackPanel Spacing="10"> <StackPanel Spacing="10">
<Label Classes="heading1">Info</Label> <Label Classes="heading1">Info</Label>
<Image x:Name="ProfImage" Width="150" Height="150" Stretch="UniformToFill" Source="avares://CritterFolio/Assets/Icon.png" />
<StackPanel HorizontalAlignment="Stretch"> <StackPanel HorizontalAlignment="Stretch">
<Label VerticalAlignment="Center">Name: </Label> <Label VerticalAlignment="Center">Name: </Label>
<TextBox x:Name="NameBox" /> <TextBox x:Name="NameBox" />
@@ -27,6 +28,13 @@
<Label VerticalAlignment="Center">Father: </Label> <Label VerticalAlignment="Center">Father: </Label>
<ComboBox x:Name="FatherPicker" /> <ComboBox x:Name="FatherPicker" />
</StackPanel> </StackPanel>
<StackPanel HorizontalAlignment="Stretch">
<Label VerticalAlignment="Center">Notes: </Label>
<TextBox x:Name="NotesBox" MinHeight="100" AcceptsReturn="True" TextWrapping="Wrap" />
</StackPanel>
<StackPanel>
<Button x:Name="PfpButton">Choose Profile Picture</Button>
</StackPanel>
<!-- <Button x:Name="AddButton" Classes="icon" HorizontalAlignment="Stretch">&#xe3d4;</Button> --> <!-- <Button x:Name="AddButton" Classes="icon" HorizontalAlignment="Stretch">&#xe3d4;</Button> -->
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia; using Avalonia;
@@ -7,6 +8,8 @@ using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Platform.Storage;
using Avalonia.Threading; using Avalonia.Threading;
using CritterFolio.DataModels; using CritterFolio.DataModels;
using CritterFolio.Services; using CritterFolio.Services;
@@ -16,6 +19,7 @@ namespace CritterFolio.Pages;
public partial class CritterPage : Page public partial class CritterPage : Page
{ {
private Critter? _critter; private Critter? _critter;
private List<CritterComboBoxDisplay> _critterDisplays = [];
public CritterPage() public CritterPage()
{ {
@@ -26,31 +30,37 @@ public partial class CritterPage : Page
{ {
_critter = critter; _critter = critter;
UpdateInfo(); PfpButton.Click += OpenFileButton_Clicked;
} }
public override void Refresh() public override async void Refresh()
{ {
base.Refresh(); base.Refresh();
CreateHeaderButtons(); CreateHeaderButtons();
GenderOption.ItemsSource = Enum.GetNames(typeof(Gender)); GenderOption.ItemsSource = Enum.GetNames(typeof(Gender));
LoadComboItemsAsync(); await UpdateInfo();
} }
private async void LoadComboItemsAsync() private async Task LoadComboItemsAsync()
{ {
_critterDisplays.Clear();
_critterDisplays.Add(new CritterComboBoxDisplay(0, "Not set"));
try try
{ {
var allCritters = await DatabaseService.GetAllCritters(); var allCritters = await DatabaseService.GetAllCritters();
var allCritterIds = allCritters.Select(c => c.Id).ToList();
foreach (var critter in allCritters)
{
if (critter.Id == _critter?.Id) continue;
_critterDisplays.Add(new CritterComboBoxDisplay(critter.Id, critter.Name));
}
await Dispatcher.UIThread.InvokeAsync(() => await Dispatcher.UIThread.InvokeAsync(() =>
{ {
FatherPicker.ItemsSource = allCritterIds; FatherPicker.ItemsSource = _critterDisplays;
MotherPicker.ItemsSource = allCritterIds; MotherPicker.ItemsSource = _critterDisplays;
UpdateInfo();
}); });
} }
catch (Exception ex) catch (Exception ex)
@@ -59,15 +69,64 @@ public partial class CritterPage : Page
} }
} }
private void UpdateInfo() private async Task UpdateInfo()
{ {
if (_critter is null) return;
Sys.Navigation?.SetTitle(_critter.Name); Sys.Navigation?.SetTitle(_critter.Name);
await LoadComboItemsAsync();
NameBox.Text = _critter.Name; NameBox.Text = _critter.Name;
GenderOption.SelectedItem = Enum.GetName(typeof(Gender), _critter.Gender); GenderOption.SelectedItem = Enum.GetName(typeof(Gender), _critter.Gender);
BirthdayPicker.SelectedDate = _critter.DateOfBirth; BirthdayPicker.SelectedDate = _critter.DateOfBirth;
MotherPicker.SelectedItem = _critter.FatherId;
FatherPicker.SelectedItem = _critter.FatherId; if (_critter.FatherId != 0)
{
var father = _critterDisplays.FirstOrDefault(c => c.Id == _critter.FatherId);
if (father is null)
{
Logger.LogToFile($"Couldn't find father id: {_critter.FatherId}");
await DialogHelper.ShowMessage($"ERROR: Couldn't find FatherID: {_critter.FatherId}");
return;
}
FatherPicker.SelectedItem = father;
}
else
{
FatherPicker.SelectedItem = _critterDisplays.FirstOrDefault(c => c.Id == 0);
}
if (_critter.MotherId != 0)
{
var mother = _critterDisplays.FirstOrDefault(c => c.Id == _critter.MotherId);
if (mother is null)
{
Logger.LogToFile($"[ERROR] Couldn't find MotherId: {_critter.MotherId}");
await DialogHelper.ShowMessage($"ERROR: Couldn't find MotherId: {_critter.MotherId}");
return;
}
MotherPicker.SelectedItem = mother;
}
else
{
MotherPicker.SelectedItem = _critterDisplays.FirstOrDefault(c => c.Id == 0);
}
NotesBox.Text = _critter.Notes;
if (!string.IsNullOrWhiteSpace(_critter.ProfileImagePath))
{
try
{
var bmp = new Bitmap(_critter.ProfileImagePath);
ProfImage.Source = bmp;
}
catch (Exception e)
{
Console.WriteLine($"Pfp image for {_critter.Id} was moved, deleted, or is corrupt.");
}
}
} }
private void CreateHeaderButtons() private void CreateHeaderButtons()
@@ -86,14 +145,13 @@ public partial class CritterPage : Page
Classes = { "headerBttn" }, Classes = { "headerBttn" },
Content = "\ue4a6" Content = "\ue4a6"
}; };
delBttn.Foreground = new SolidColorBrush(Colors.DarkRed); delBttn.Foreground = new SolidColorBrush(Colors.Red);
delBttn.Click += DeleteButtonClicked; delBttn.Click += DeleteButtonClicked;
Sys.Navigation?.AddHeaderButton(delBttn); Sys.Navigation?.AddHeaderButton(delBttn);
} }
private async void DeleteButtonClicked(object? sender, RoutedEventArgs args) private async void DeleteButtonClicked(object? sender, RoutedEventArgs args)
{ {
try try
{ {
var result = await DialogHelper.ShowConfirmationDialog("Are you sure you want to delete this critter?"); var result = await DialogHelper.ShowConfirmationDialog("Are you sure you want to delete this critter?");
@@ -125,7 +183,7 @@ public partial class CritterPage : Page
} }
await DatabaseService.UpdateCritter(_critter); await DatabaseService.UpdateCritter(_critter);
UpdateInfo(); await UpdateInfo();
await DialogHelper.ShowMessage($"Critter '{_critter.Name}' saved!"); await DialogHelper.ShowMessage($"Critter '{_critter.Name}' saved!");
} }
@@ -164,28 +222,81 @@ public partial class CritterPage : Page
errString += "Birthday is invalid somehow. Please report this to the developer\n"; errString += "Birthday is invalid somehow. Please report this to the developer\n";
} }
// Dont need to validate these yet, as they are not required // TODO: Change the way that fatherid and motherid work, it should show names, not the ids, but still link back to the id
// // Father ID validation // Father ID validation
// if (FatherPicker.SelectedItem is int fatherId) if (FatherPicker.SelectedItem is CritterComboBoxDisplay father)
// { {
// _critter.FatherId = fatherId; var id = _critterDisplays.FirstOrDefault(d => d.Id == father.Id);
// } _critter.FatherId = id?.Id ?? 0;
// else }
// { else
// errString += "FatherId is null or invalid somehow. Please report this to the developer\n"; {
// } _critter.FatherId = 0;
// }
// // Mother ID validation
// if (MotherPicker.SelectedItem is int motherId) // Mother ID validation
// { if (MotherPicker.SelectedItem is CritterComboBoxDisplay mother)
// _critter.MotherId = motherId; {
// } var id = _critterDisplays.FirstOrDefault(d => d.Id == mother.Id);
// else _critter.MotherId = id?.Id ?? 0;
// { }
// errString += "MotherId is null or invalid somehow. Please report this to the developer\n"; else
// } {
_critter.MotherId = 0;
}
if (_critter.MotherId == _critter.FatherId && _critter.MotherId > 0 && _critter.FatherId > 0)
{
errString += "Mother and Father cannot be the same";
}
_critter.Notes = NotesBox.Text ?? "";
return errString != "" ? (false, errString) : (true, "No errors"); return errString != "" ? (false, errString) : (true, "No errors");
} }
private class CritterComboBoxDisplay(int id, string name)
{
public int Id { get; set; } = id;
public string Name { get; set; } = name;
public override string ToString() => Name;
}
private async void OpenFileButton_Clicked(object? sender, RoutedEventArgs args)
{
var topLevel = TopLevel.GetTopLevel(this);
var files = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
Title = "Open Image File",
AllowMultiple = false,
FileTypeFilter = [new FilePickerFileType("image"){Patterns = ["*.png", "*.jpg", "*.jpeg"]}]
});
if (files.Count == 0) return;
var file = files[0];
try
{
await using var stream = await file.OpenReadAsync();
// using var streamReader = new StreamReader(stream);
// var fileContent = await streamReader.ReadToEndAsync();
var bmp = new Bitmap(stream);
var path = Path.Combine(Sys.UserDataPath, "ImageCache", $"{_critter.Id}-{_critter.Name}.jpg");
bmp.Save(path);
_critter.ProfileImagePath = path;
await UpdateInfo();
}
catch (Exception e)
{
await DialogHelper.ShowMessage(e.ToString());
}
}
} }