| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 |
- using Avalonia;
- using Avalonia.Collections;
- using Avalonia.Media.Imaging;
- using Avalonia.Threading;
- using Ryujinx.Ava.Common.Locale;
- using Ryujinx.Ava.UI.Helpers;
- using Ryujinx.Ava.UI.Windows;
- using Ryujinx.Common;
- using Ryujinx.Common.Configuration;
- using Ryujinx.Common.Utilities;
- using Ryujinx.Ui.Common.Models.Amiibo;
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.IO;
- using System.Linq;
- using System.Net.Http;
- using System.Text;
- using System.Threading.Tasks;
- using AmiiboJsonSerializerContext = Ryujinx.Ui.Common.Models.Amiibo.AmiiboJsonSerializerContext;
- namespace Ryujinx.Ava.UI.ViewModels
- {
- public class AmiiboWindowViewModel : BaseModel, IDisposable
- {
- private const string DefaultJson = "{ \"amiibo\": [] }";
- private const float AmiiboImageSize = 350f;
- private readonly string _amiiboJsonPath;
- private readonly byte[] _amiiboLogoBytes;
- private readonly HttpClient _httpClient;
- private readonly StyleableWindow _owner;
- private Bitmap _amiiboImage;
- private List<AmiiboApi> _amiiboList;
- private AvaloniaList<AmiiboApi> _amiibos;
- private ObservableCollection<string> _amiiboSeries;
- private int _amiiboSelectedIndex;
- private int _seriesSelectedIndex;
- private bool _enableScanning;
- private bool _showAllAmiibo;
- private bool _useRandomUuid;
- private string _usage;
-
- private static readonly AmiiboJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
- public AmiiboWindowViewModel(StyleableWindow owner, string lastScannedAmiiboId, string titleId)
- {
- _owner = owner;
- _httpClient = new HttpClient { Timeout = TimeSpan.FromMilliseconds(5000) };
- LastScannedAmiiboId = lastScannedAmiiboId;
- TitleId = titleId;
- Directory.CreateDirectory(Path.Join(AppDataManager.BaseDirPath, "system", "amiibo"));
- _amiiboJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", "Amiibo.json");
- _amiiboList = new List<AmiiboApi>();
- _amiiboSeries = new ObservableCollection<string>();
- _amiibos = new AvaloniaList<AmiiboApi>();
- _amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.Ui.Common/Resources/Logo_Amiibo.png");
- _ = LoadContentAsync();
- }
- public AmiiboWindowViewModel() { }
- public string TitleId { get; set; }
- public string LastScannedAmiiboId { get; set; }
- public UserResult Response { get; private set; }
- public bool UseRandomUuid
- {
- get => _useRandomUuid;
- set
- {
- _useRandomUuid = value;
- OnPropertyChanged();
- }
- }
- public bool ShowAllAmiibo
- {
- get => _showAllAmiibo;
- set
- {
- _showAllAmiibo = value;
- #pragma warning disable 4014
- ParseAmiiboData();
- #pragma warning restore 4014
- OnPropertyChanged();
- }
- }
- public AvaloniaList<AmiiboApi> AmiiboList
- {
- get => _amiibos;
- set
- {
- _amiibos = value;
- OnPropertyChanged();
- }
- }
- public ObservableCollection<string> AmiiboSeries
- {
- get => _amiiboSeries;
- set
- {
- _amiiboSeries = value;
- OnPropertyChanged();
- }
- }
- public int SeriesSelectedIndex
- {
- get => _seriesSelectedIndex;
- set
- {
- _seriesSelectedIndex = value;
- FilterAmiibo();
- OnPropertyChanged();
- }
- }
- public int AmiiboSelectedIndex
- {
- get => _amiiboSelectedIndex;
- set
- {
- _amiiboSelectedIndex = value;
- EnableScanning = _amiiboSelectedIndex >= 0 && _amiiboSelectedIndex < _amiibos.Count;
- SetAmiiboDetails();
- OnPropertyChanged();
- }
- }
- public Bitmap AmiiboImage
- {
- get => _amiiboImage;
- set
- {
- _amiiboImage = value;
- OnPropertyChanged();
- }
- }
- public string Usage
- {
- get => _usage;
- set
- {
- _usage = value;
- OnPropertyChanged();
- }
- }
- public bool EnableScanning
- {
- get => _enableScanning;
- set
- {
- _enableScanning = value;
- OnPropertyChanged();
- }
- }
- public void Dispose()
- {
- _httpClient.Dispose();
- }
- private async Task LoadContentAsync()
- {
- string amiiboJsonString = DefaultJson;
- if (File.Exists(_amiiboJsonPath))
- {
- amiiboJsonString = await File.ReadAllTextAsync(_amiiboJsonPath);
- if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).LastUpdated))
- {
- amiiboJsonString = await DownloadAmiiboJson();
- }
- }
- else
- {
- try
- {
- amiiboJsonString = await DownloadAmiiboJson();
- }
- catch
- {
- ShowInfoDialog();
- }
- }
- _amiiboList = JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).Amiibo;
- _amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
- ParseAmiiboData();
- }
- private void ParseAmiiboData()
- {
- _amiiboSeries.Clear();
- _amiibos.Clear();
- for (int i = 0; i < _amiiboList.Count; i++)
- {
- if (!_amiiboSeries.Contains(_amiiboList[i].AmiiboSeries))
- {
- if (!ShowAllAmiibo)
- {
- foreach (AmiiboApiGamesSwitch game in _amiiboList[i].GamesSwitch)
- {
- if (game != null)
- {
- if (game.GameId.Contains(TitleId))
- {
- AmiiboSeries.Add(_amiiboList[i].AmiiboSeries);
- break;
- }
- }
- }
- }
- else
- {
- AmiiboSeries.Add(_amiiboList[i].AmiiboSeries);
- }
- }
- }
- if (LastScannedAmiiboId != "")
- {
- SelectLastScannedAmiibo();
- }
- else
- {
- SeriesSelectedIndex = 0;
- }
- }
- private void SelectLastScannedAmiibo()
- {
- AmiiboApi scanned = _amiiboList.FirstOrDefault(amiibo => amiibo.GetId() == LastScannedAmiiboId);
- SeriesSelectedIndex = AmiiboSeries.IndexOf(scanned.AmiiboSeries);
- AmiiboSelectedIndex = AmiiboList.IndexOf(scanned);
- }
- private void FilterAmiibo()
- {
- _amiibos.Clear();
- if (_seriesSelectedIndex < 0)
- {
- return;
- }
- List<AmiiboApi> amiiboSortedList = _amiiboList
- .Where(amiibo => amiibo.AmiiboSeries == _amiiboSeries[SeriesSelectedIndex])
- .OrderBy(amiibo => amiibo.Name).ToList();
- for (int i = 0; i < amiiboSortedList.Count; i++)
- {
- if (!_amiibos.Contains(amiiboSortedList[i]))
- {
- if (!_showAllAmiibo)
- {
- foreach (AmiiboApiGamesSwitch game in amiiboSortedList[i].GamesSwitch)
- {
- if (game != null)
- {
- if (game.GameId.Contains(TitleId))
- {
- _amiibos.Add(amiiboSortedList[i]);
- break;
- }
- }
- }
- }
- else
- {
- _amiibos.Add(amiiboSortedList[i]);
- }
- }
- }
- AmiiboSelectedIndex = 0;
- }
- private void SetAmiiboDetails()
- {
- ResetAmiiboPreview();
- Usage = string.Empty;
- if (_amiiboSelectedIndex < 0)
- {
- return;
- }
- AmiiboApi selected = _amiibos[_amiiboSelectedIndex];
- string imageUrl = _amiiboList.FirstOrDefault(amiibo => amiibo.Equals(selected)).Image;
- string usageString = "";
- for (int i = 0; i < _amiiboList.Count; i++)
- {
- if (_amiiboList[i].Equals(selected))
- {
- bool writable = false;
- foreach (AmiiboApiGamesSwitch item in _amiiboList[i].GamesSwitch)
- {
- if (item.GameId.Contains(TitleId))
- {
- foreach (AmiiboApiUsage usageItem in item.AmiiboUsage)
- {
- usageString += Environment.NewLine +
- $"- {usageItem.Usage.Replace("/", Environment.NewLine + "-")}";
- writable = usageItem.Write;
- }
- }
- }
- if (usageString.Length == 0)
- {
- usageString = LocaleManager.Instance[LocaleKeys.Unknown] + ".";
- }
- Usage = $"{LocaleManager.Instance[LocaleKeys.Usage]} {(writable ? $" ({LocaleManager.Instance[LocaleKeys.Writable]})" : "")} : {usageString}";
- }
- }
- _ = UpdateAmiiboPreview(imageUrl);
- }
- private async Task<bool> NeedsUpdate(DateTime oldLastModified)
- {
- try
- {
- HttpResponseMessage response =
- await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/"));
- if (response.IsSuccessStatusCode)
- {
- return response.Content.Headers.LastModified != oldLastModified;
- }
- return false;
- }
- catch
- {
- ShowInfoDialog();
- return false;
- }
- }
- private async Task<string> DownloadAmiiboJson()
- {
- HttpResponseMessage response = await _httpClient.GetAsync("https://amiibo.ryujinx.org/");
- if (response.IsSuccessStatusCode)
- {
- string amiiboJsonString = await response.Content.ReadAsStringAsync();
- using (FileStream amiiboJsonStream = File.Create(_amiiboJsonPath, 4096, FileOptions.WriteThrough))
- {
- amiiboJsonStream.Write(Encoding.UTF8.GetBytes(amiiboJsonString));
- }
- return amiiboJsonString;
- }
- await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle],
- LocaleManager.Instance[LocaleKeys.DialogAmiiboApiFailFetchMessage],
- LocaleManager.Instance[LocaleKeys.InputDialogOk],
- "",
- LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
- Close();
- return DefaultJson;
- }
- private void Close()
- {
- Dispatcher.UIThread.Post(_owner.Close);
- }
- private async Task UpdateAmiiboPreview(string imageUrl)
- {
- HttpResponseMessage response = await _httpClient.GetAsync(imageUrl);
- if (response.IsSuccessStatusCode)
- {
- byte[] amiiboPreviewBytes = await response.Content.ReadAsByteArrayAsync();
- using (MemoryStream memoryStream = new(amiiboPreviewBytes))
- {
- Bitmap bitmap = new(memoryStream);
- double ratio = Math.Min(AmiiboImageSize / bitmap.Size.Width,
- AmiiboImageSize / bitmap.Size.Height);
- int resizeHeight = (int)(bitmap.Size.Height * ratio);
- int resizeWidth = (int)(bitmap.Size.Width * ratio);
- AmiiboImage = bitmap.CreateScaledBitmap(new PixelSize(resizeWidth, resizeHeight));
- }
- }
- }
- private void ResetAmiiboPreview()
- {
- using (MemoryStream memoryStream = new(_amiiboLogoBytes))
- {
- Bitmap bitmap = new(memoryStream);
- AmiiboImage = bitmap;
- }
- }
- private async void ShowInfoDialog()
- {
- await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle],
- LocaleManager.Instance[LocaleKeys.DialogAmiiboApiConnectErrorMessage],
- LocaleManager.Instance[LocaleKeys.InputDialogOk],
- "",
- LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
- }
- }
- }
|