Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add button to sprite window to upload sprites #628

Merged
merged 2 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/TrackerCouncil.Smz3.Data/Options/Sprite.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public Sprite(string name, string author, string filePath, SpriteType spriteType
SpriteType = spriteType;
PreviewPath = previewPath;
SpriteOption = spriteOption;
IsUserSprite = filePath.StartsWith(RandomizerDirectories.UserSpritePath);

if (string.IsNullOrEmpty(filePath))
IsDefault = true;
}
Expand All @@ -50,7 +52,7 @@ private Sprite(string name, SpriteType spriteType, bool isDefault, bool isRandom
SpriteType = spriteType;
IsDefault = isDefault;
IsRandomSprite = isRandomSprite;
PreviewPath = Path.Combine(SpritePath, s_folderNames[spriteType], sprite);
PreviewPath = Path.Combine(RandomizerDirectories.SpritePath, s_folderNames[spriteType], sprite);
}

[YamlIgnore]
Expand All @@ -59,9 +61,9 @@ private Sprite(string name, SpriteType spriteType, bool isDefault, bool isRandom
[YamlIgnore]
public string Author { get; set; }

public string FilePath { get; set; } = "";
public string FilePath { get; } = "";

public SpriteType SpriteType { get; set; }
public SpriteType SpriteType { get; }

[YamlIgnore]
public string PreviewPath { get; set; }
Expand All @@ -73,12 +75,15 @@ private Sprite(string name, SpriteType spriteType, bool isDefault, bool isRandom
[YamlIgnore]
public SpriteOptions SpriteOption { get; set; }

public bool IsUserSprite { get; set; }

public bool MatchesFilter(string searchTerm, SpriteFilter spriteFilter) => (string.IsNullOrEmpty(searchTerm) ||
Name.Contains(searchTerm, StringComparison.OrdinalIgnoreCase) ||
Author.Contains(searchTerm, StringComparison.OrdinalIgnoreCase)) &&
((spriteFilter == SpriteFilter.Default && SpriteOption != SpriteOptions.Hide) ||
(spriteFilter == SpriteFilter.Favorited && SpriteOption == SpriteOptions.Favorite) ||
(spriteFilter == SpriteFilter.Hidden && SpriteOption == SpriteOptions.Hide) ||
(spriteFilter == SpriteFilter.User && IsUserSprite) ||
spriteFilter == SpriteFilter.All);

public static bool operator ==(Sprite? a, Sprite? b)
Expand Down Expand Up @@ -119,5 +124,4 @@ public override string ToString()
return string.IsNullOrEmpty(Author) ? Name : $"{Name} by {Author}";
}

public static string SpritePath => RandomizerDirectories.SpritePath;
}
1 change: 1 addition & 0 deletions src/TrackerCouncil.Smz3.Data/Options/SpriteFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ public enum SpriteFilter
Default,
Favorited,
Hidden,
User,
All,
}
5 changes: 4 additions & 1 deletion src/TrackerCouncil.Smz3.Data/RandomizerDirectories.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ public static string SpritePath
}
}

public static string UserSpritePath => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"SMZ3CasRandomizer", "Sprites");

#if DEBUG
public static string SpriteHashYamlFilePath => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SMZ3CasRandomizer", "sprite-hashes-debug.yml");
#else
Expand Down Expand Up @@ -101,5 +104,5 @@ public static string TrackerSpritePath
public static string TrackerSpriteHashYamlFilePath => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SMZ3CasRandomizer", "tracker-sprite-hashes.yml");
#endif

public static string TrackerSpriteInitialJsonFilePath => Path.Combine(SpritePath, "tracker-sprites.json");
public static string TrackerSpriteInitialJsonFilePath => Path.Combine(SpritePath, "tracker-sprites.json");
}
94 changes: 86 additions & 8 deletions src/TrackerCouncil.Smz3.Data/Services/SpriteService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public SpriteService(ILogger<SpriteService> logger, OptionsFactory optionsFactor
_options = optionsFactory.Create();
}

public IEnumerable<Sprite> Sprites { get; set; } = new List<Sprite>();
public List<Sprite> Sprites { get; set; } = [];
public IEnumerable<Sprite> LinkSprites => Sprites.Where(x => x.SpriteType == SpriteType.Link);
public IEnumerable<Sprite> SamusSprites => Sprites.Where(x => x.SpriteType == SpriteType.Samus);
public IEnumerable<Sprite> ShipSprites => Sprites.Where(x => x.SpriteType == SpriteType.Ship);
Expand All @@ -33,23 +33,21 @@ public SpriteService(ILogger<SpriteService> logger, OptionsFactory optionsFactor
/// </summary>
public Task LoadSpritesAsync()
{
if (Sprites.Any() || !Directory.Exists(Sprite.SpritePath)) return Task.CompletedTask;
if (Sprites.Any() || !Directory.Exists(RandomizerDirectories.SpritePath)) return Task.CompletedTask;

return Task.Run(() =>
{
var defaults = new List<Sprite>() { Sprite.DefaultSamus, Sprite.DefaultLink, Sprite.DefaultShip, Sprite.RandomSamus, Sprite.RandomLink, Sprite.RandomShip };

var playerSprites = Directory.EnumerateFiles(Sprite.SpritePath, "*.rdc", SearchOption.AllDirectories)
var playerSprites = Directory.EnumerateFiles(RandomizerDirectories.SpritePath, "*.rdc", SearchOption.AllDirectories)
.Select(LoadRdcSprite);

var shipSprites = Directory.EnumerateFiles(Path.Combine(Sprite.SpritePath, "Ships"), "*.ips", SearchOption.AllDirectories)
var shipSprites = Directory.EnumerateFiles(Path.Combine(RandomizerDirectories.SpritePath, "Ships"), "*.ips", SearchOption.AllDirectories)
.Select(LoadIpsSprite);

var sprites = playerSprites.Concat(shipSprites).Concat(defaults).OrderBy(x => x.Name).ToList();

var extraSpriteDirectory =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"SMZ3CasRandomizer", "Sprites");
var extraSpriteDirectory = RandomizerDirectories.UserSpritePath;

if (Directory.Exists(extraSpriteDirectory))
{
Expand All @@ -65,6 +63,50 @@ public Task LoadSpritesAsync()
});
}

public Sprite? AddCustomSprite(string spritePath, string? previewImagePath)
{
var userSpritePath = RandomizerDirectories.UserSpritePath;

if (spritePath.StartsWith(RandomizerDirectories.SpritePath) ||
spritePath.StartsWith(userSpritePath) ||
!File.Exists(spritePath))
{
return null;
}

var destinationSpritePath = Path.Combine(userSpritePath, Path.GetFileName(spritePath));
File.Copy(spritePath, destinationSpritePath, true);
if (File.Exists(previewImagePath))
{
var baseFileName = Path.GetFileNameWithoutExtension(spritePath);
File.Copy(previewImagePath, Path.Combine(userSpritePath, $"{baseFileName}.png"), true);
}

var sprite = new Sprite();
try
{
sprite = ".rdc".Equals(Path.GetExtension(destinationSpritePath), StringComparison.OrdinalIgnoreCase)
? LoadRdcSprite(destinationSpritePath)
: LoadIpsSprite(destinationSpritePath);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to load Sprite {SpritePath}", destinationSpritePath);
}

if (Sprites.Any(x => x.FilePath == destinationSpritePath))
{
var oldSprite = Sprites.First(x => x.FilePath == destinationSpritePath);
oldSprite.Name = sprite.Name;
oldSprite.Author = sprite.Author;
oldSprite.PreviewPath = sprite.PreviewPath;
return oldSprite;
}

Sprites.Add(sprite);
return sprite;
}

/// <summary>
/// Retrieves the random sprite image for the given sprite type
/// </summary>
Expand All @@ -73,7 +115,7 @@ public Task LoadSpritesAsync()
public string GetRandomPreviewImage(SpriteType type)
{
var spriteFolder = type == SpriteType.Ship ? "Ships" : type.ToString();
return Path.Combine(Sprite.SpritePath, spriteFolder, "random.png");
return Path.Combine(RandomizerDirectories.SpritePath, spriteFolder, "random.png");
}

/// <summary>
Expand Down Expand Up @@ -232,4 +274,40 @@ public Sprite GetSprite(SpriteType type)
return sprite;
}

/// <summary>
/// Deletes a user added sprite
/// </summary>
/// <param name="sprite">The sprite to delete</param>
public bool DeleteSprite(Sprite sprite)
{
if (!sprite.IsUserSprite)
{
return false;
}

try
{
if (!string.IsNullOrEmpty(sprite.PreviewPath) && File.Exists(sprite.PreviewPath))
{
File.Delete(sprite.PreviewPath);
}
}
catch (Exception e)
{
_logger.LogError(e, "Failed to delete sprite preview file");
}

try
{
File.Delete(sprite.FilePath);
Sprites.Remove(sprite);
return true;
}
catch (Exception e)
{
_logger.LogError(e, "Failed to delete sprite preview file");
return false;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ namespace TrackerCouncil.Smz3.Data.Services;
/// <summary>
/// Service for loading tracker speech sprites
/// </summary>
/// <param name="logger"></param>
/// <param name="optionsFactory"></param>
public class TrackerSpriteService(ILogger<TrackerSpriteService> logger, OptionsFactory optionsFactory)
public class TrackerSpriteService(OptionsFactory optionsFactory)
{
private List<TrackerSpeechImagePack> _packs = [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.11" />
<PackageReference Include="MattEqualsCoder.DynamicForms.Core" Version="1.0.1" />
<PackageReference Include="MattEqualsCoder.GitHubReleaseChecker" Version="1.1.2" />
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.0-rc.5" />
Expand Down
104 changes: 92 additions & 12 deletions src/TrackerCouncil.Smz3.Data/ViewModels/SpriteViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Avalonia.Media;
using TrackerCouncil.Smz3.Data.Options;

namespace TrackerCouncil.Smz3.Data.ViewModels;

public class SpriteViewModel : INotifyPropertyChanged
{
private bool _display;
private static readonly IBrush s_defaultIconBrush = Brushes.Silver;
private static readonly IBrush s_starredIconBrush = Brushes.Goldenrod;
private static readonly IBrush s_hiddenIconBrush = Brushes.IndianRed;

private static Dictionary<SpriteType, (int, int)> s_ImageDimensions = new()
private static readonly Dictionary<SpriteType, (int, int)> s_imageDimensions = new()
{
{ SpriteType.Link, (64, 96) }, { SpriteType.Samus, (64, 106) }, { SpriteType.Ship, (248, 92) },
};

private static Dictionary<SpriteType, int> s_Widths = new()
private static readonly Dictionary<SpriteType, int> s_widths = new()
{
{ SpriteType.Link, 250 }, { SpriteType.Samus, 250 }, { SpriteType.Ship, 450 },
{ SpriteType.Link, 235 }, { SpriteType.Samus, 235 }, { SpriteType.Ship, 450 },
};

public SpriteViewModel(Sprite sprite)
Expand All @@ -25,22 +29,68 @@ public SpriteViewModel(Sprite sprite)
Name = sprite.Name;
Author = sprite.Author;
PreviewPath = sprite.PreviewPath;
SpriteOption = sprite.SpriteOption;
Display = sprite.SpriteOption != SpriteOptions.Hide;
PanelWidth = s_Widths[sprite.SpriteType];
ImageWidth = s_ImageDimensions[sprite.SpriteType].Item1;
ImageHeight = s_ImageDimensions[sprite.SpriteType].Item2;
CanFavoriteAndHide = !sprite.IsRandomSprite;
PanelWidth = s_widths[sprite.SpriteType];
ImageWidth = s_imageDimensions[sprite.SpriteType].Item1;
ImageHeight = s_imageDimensions[sprite.SpriteType].Item2;
CanFavorite = !sprite.IsRandomSprite;
CanHide = sprite is { IsUserSprite: false };
CanDelete = sprite is { IsRandomSprite: false, IsUserSprite: true };
IconOpacity = CanFavorite ? 1f : 0.3f;

SetSpriteOption(sprite.SpriteOption);
}

public Sprite Sprite { get; }
public string Name { get; set; }
public string Author { get; set; }
public string PreviewPath { get; set; }
public bool CanFavoriteAndHide { get; set; }
public bool CanFavorite { get; set; }
public int PanelWidth { get; }
public int ImageWidth { get; }
public int ImageHeight { get; }
public float IconOpacity { get; }

private string? _previewPath;
public string? PreviewPath
{
get => _previewPath;
set => SetField(ref _previewPath, value);
}

private bool _canHide;
public bool CanHide
{
get => _canHide;
set => SetField(ref _canHide, value);
}

private bool _canDelete;
public bool CanDelete
{
get => _canDelete;
set => SetField(ref _canDelete, value);
}

private IBrush? _starBrush = s_defaultIconBrush;
public IBrush? StarBrush
{
get => _starBrush;
set => SetField(ref _starBrush, value);
}

private IBrush? _hideBrush = s_defaultIconBrush;
public IBrush? HideBrush
{
get => _hideBrush;
set => SetField(ref _hideBrush, value);
}

private IBrush? _deleteBrush = s_defaultIconBrush;
public IBrush? DeleteBrush
{
get => _deleteBrush;
set => SetField(ref _deleteBrush, value);
}

public SpriteOptions SpriteOption
{
Expand All @@ -50,7 +100,7 @@ public SpriteOptions SpriteOption
Sprite.SpriteOption = value;
OnPropertyChanged();
OnPropertyChanged(nameof(IsFavorite));
OnPropertyChanged(nameof(IsNotFavorite));
OnPropertyChanged(nameof(IsHidden));
}
}

Expand All @@ -64,7 +114,37 @@ public bool Display

public bool IsFavorite => SpriteOption == SpriteOptions.Favorite;

public bool IsNotFavorite => !IsFavorite;
public bool IsHidden => SpriteOption == SpriteOptions.Hide;

public void SetSpriteOption(SpriteOptions option)
{
SpriteOption = option;

if (Sprite.IsRandomSprite)
{
StarBrush = s_defaultIconBrush;
HideBrush = s_defaultIconBrush;
return;
}
else if (option == SpriteOptions.Default)
{
StarBrush = s_defaultIconBrush;
HideBrush = s_defaultIconBrush;
DeleteBrush = s_defaultIconBrush;
}
else if (option == SpriteOptions.Favorite)
{
StarBrush = s_starredIconBrush;
HideBrush = s_defaultIconBrush;
DeleteBrush = s_defaultIconBrush;
}
else if (option == SpriteOptions.Hide)
{
StarBrush = s_defaultIconBrush;
HideBrush = s_hiddenIconBrush;
DeleteBrush = s_defaultIconBrush;
}
}

public event PropertyChangedEventHandler? PropertyChanged;

Expand Down
Loading