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.Controls.ApplicationLifetimes;
using Avalonia.Data.Core;
@@ -37,6 +38,8 @@ public partial class App : Application
}
// Other init stuff here
Directory.CreateDirectory(Sys.UserDataPath);
Directory.CreateDirectory(Path.Combine(Sys.UserDataPath, "ImageCache"));
base.OnFrameworkInitializationCompleted();

View File

@@ -11,7 +11,7 @@
VerticalContentAlignment="Center"
x:Name="MainButton">
<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" />
</Grid>
</Button>

View File

@@ -7,6 +7,7 @@ public class Document
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
public int CritterId { 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">
<StackPanel Spacing="10">
<Label Classes="heading1">Info</Label>
<Image x:Name="ProfImage" Width="150" Height="150" Stretch="UniformToFill" Source="avares://CritterFolio/Assets/Icon.png" />
<StackPanel HorizontalAlignment="Stretch">
<Label VerticalAlignment="Center">Name: </Label>
<TextBox x:Name="NameBox" />
@@ -27,6 +28,13 @@
<Label VerticalAlignment="Center">Father: </Label>
<ComboBox x:Name="FatherPicker" />
</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> -->
</StackPanel>
</ScrollViewer>

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Avalonia;
@@ -7,6 +8,8 @@ using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Platform.Storage;
using Avalonia.Threading;
using CritterFolio.DataModels;
using CritterFolio.Services;
@@ -16,6 +19,7 @@ namespace CritterFolio.Pages;
public partial class CritterPage : Page
{
private Critter? _critter;
private List<CritterComboBoxDisplay> _critterDisplays = [];
public CritterPage()
{
@@ -25,32 +29,38 @@ public partial class CritterPage : Page
public void Init(Critter critter)
{
_critter = critter;
UpdateInfo();
PfpButton.Click += OpenFileButton_Clicked;
}
public override void Refresh()
public override async void Refresh()
{
base.Refresh();
CreateHeaderButtons();
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
{
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(() =>
{
FatherPicker.ItemsSource = allCritterIds;
MotherPicker.ItemsSource = allCritterIds;
UpdateInfo();
FatherPicker.ItemsSource = _critterDisplays;
MotherPicker.ItemsSource = _critterDisplays;
});
}
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);
await LoadComboItemsAsync();
NameBox.Text = _critter.Name;
GenderOption.SelectedItem = Enum.GetName(typeof(Gender), _critter.Gender);
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()
@@ -86,14 +145,13 @@ public partial class CritterPage : Page
Classes = { "headerBttn" },
Content = "\ue4a6"
};
delBttn.Foreground = new SolidColorBrush(Colors.DarkRed);
delBttn.Foreground = new SolidColorBrush(Colors.Red);
delBttn.Click += DeleteButtonClicked;
Sys.Navigation?.AddHeaderButton(delBttn);
}
private async void DeleteButtonClicked(object? sender, RoutedEventArgs args)
{
try
{
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);
UpdateInfo();
await UpdateInfo();
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";
}
// Dont need to validate these yet, as they are not required
// // Father ID validation
// if (FatherPicker.SelectedItem is int fatherId)
// {
// _critter.FatherId = fatherId;
// }
// else
// {
// errString += "FatherId is null or invalid somehow. Please report this to the developer\n";
// }
//
// // Mother ID validation
// if (MotherPicker.SelectedItem is int motherId)
// {
// _critter.MotherId = motherId;
// }
// else
// {
// errString += "MotherId is null or invalid somehow. Please report this to the developer\n";
// }
// 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
if (FatherPicker.SelectedItem is CritterComboBoxDisplay father)
{
var id = _critterDisplays.FirstOrDefault(d => d.Id == father.Id);
_critter.FatherId = id?.Id ?? 0;
}
else
{
_critter.FatherId = 0;
}
// Mother ID validation
if (MotherPicker.SelectedItem is CritterComboBoxDisplay mother)
{
var id = _critterDisplays.FirstOrDefault(d => d.Id == mother.Id);
_critter.MotherId = id?.Id ?? 0;
}
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");
}
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());
}
}
}