Added most of the framework for the error window.

This commit is contained in:
alphafetus authored and BobdaFett committed 2023-11-23 18:19:47 -05:00
1 parent bc8f5e4d54
commit d667e86b1b
3 files changed
+38 -44

No files matched your search

+18 -43
View File
@@ -1,19 +1,16 @@
using System; using System;
using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Threading.Tasks; using System.Threading.Tasks;
using PcgsInvUi.Models; using PcgsInvUi.Models;
using System.Text.Json; using System.Text.Json;
using DynamicData.Kernel;
using ReactiveUI; using ReactiveUI;
namespace PcgsInvUi.Services; namespace PcgsInvUi.Services;
/// <summary>
/// Provides an interface into the PCGS Public API.
/// </summary>
public class PcgsClient : ReactiveObject { public class PcgsClient : ReactiveObject {
public int NumApiRequests { public int NumApiRequests {
get => _numApiRequests; get => _numApiRequests;
set => this.RaiseAndSetIfChanged(ref _numApiRequests, value); set => this.RaiseAndSetIfChanged(ref _numApiRequests, value);
@@ -24,12 +21,12 @@ public class PcgsClient : ReactiveObject {
private int _numApiRequests; private int _numApiRequests;
public PcgsClient(string apiKey) { public PcgsClient(string apiKey) {
// I'd like to be able to test the API key upon initialization. // _apiKey = apiKey;
_apiKey = _apiKey =
"E8xivTVN_k4Q8ubk8Xv_uU11U91WX0wDht4S4m4BAf2HPmKnGrZ0J2f9nccM7Ns1VkGoT1SXYR74I7aNaMKqXlJGEy3oobseKV0nGiqu1IKvFkOTVjhV37SWUVExSDFMC6FLzs7xJQIHwkcxr5JFOQNmc4ZytEh_-hmCN3NL-z0fEk98tzBmPJ_F7bq_xNru86QMD2A9yalu_dWe-lCysfyE2bCA2EDqwvWenRYf-0XnNtp6qlxxCMlCd-TDqqRKLC3qefCwpXSemwBiNSP5gbC9pwcKrZugkruuJ0nyxxThZymm"; "E8xivTVN_k4Q8ubk8Xv_uU11U91WX0wDht4S4m4BAf2HPmKnGrZ0J2f9nccM7Ns1VkGoT1SXYR74I7aNaMKqXlJGEy3oobseKV0nGiqu1IKvFkOTVjhV37SWUVExSDFMC6FLzs7xJQIHwkcxr5JFOQNmc4ZytEh_-hmCN3NL-z0fEk98tzBmPJ_F7bq_xNru86QMD2A9yalu_dWe-lCysfyE2bCA2EDqwvWenRYf-0XnNtp6qlxxCMlCd-TDqqRKLC3qefCwpXSemwBiNSP5gbC9pwcKrZugkruuJ0nyxxThZymm";
} }
public async Task<Coin> GetCoinFactsByGrade(int pcgsNumber, string grade, bool plusGrade = false) { public async Task<Coin?> GetCoinFactsByGrade(int pcgsNumber, string grade, bool plusGrade = false) {
Coin newCoin = null; Coin newCoin = null;
using (HttpClient client = new HttpClient()) { using (HttpClient client = new HttpClient()) {
var gradeParam = GetGradeFromString(grade); var gradeParam = GetGradeFromString(grade);
@@ -42,15 +39,12 @@ public class PcgsClient : ReactiveObject {
Console.WriteLine("Got response."); Console.WriteLine("Got response.");
if (response.IsSuccessStatusCode) { if (response.IsSuccessStatusCode) {
// TODO Check for errors indicated by a successful response.
string jsonResponse = await response.Content.ReadAsStringAsync(); string jsonResponse = await response.Content.ReadAsStringAsync();
newCoin = ParseJsonResponse(jsonResponse); newCoin = ParseJsonResponse(jsonResponse);
Console.WriteLine("Coin created."); Console.WriteLine("Coin created.");
} }
else { else {
// TODO Throw HTTP exception. Console.WriteLine($"Error: {response.StatusCode} - {response.ReasonPhrase}");
Console.WriteLine("Error getting coin.");
} }
} }
@@ -65,46 +59,27 @@ public class PcgsClient : ReactiveObject {
// TODO Will eventually create the other methods that are included in the Public API. // TODO Will eventually create the other methods that are included in the Public API.
private Coin ParseJsonResponse(string json) { private Coin? ParseJsonResponse(string json) {
Console.WriteLine(json); Console.WriteLine(json);
Coin newCoin = JsonSerializer.Deserialize<Coin>(json); // TODO Check for errors in the response
Console.WriteLine($"New Coin has pcgs number {newCoin.PCGSNo}"); if (json.Contains("\"ServerMessage\":\"No data found\"")) throw new CoinNotFoundException("No coin found with that PCGS number.");
if (json.Contains("\"IsValidRequest\":true")) throw new InvalidRequestFormatException("Invalid request format.");
string test = JsonSerializer.Serialize(newCoin);
Console.WriteLine(test);
var newCoin = JsonSerializer.Deserialize<Coin>(json);
return newCoin; return newCoin;
} }
} }
/// <summary> // Exception for invalid request format
/// Thrown when the API response indicates that the request was invalid. class InvalidRequestFormatException : Exception {
/// Generally used when the request was formatted incorrectly. public InvalidRequestFormatException() { }
/// </summary> public InvalidRequestFormatException(string message) : base(message) { }
public class InvalidRequestException : Exception { public InvalidRequestFormatException(string message, Exception inner) : base(message, inner) { }
public InvalidRequestException() { }
public InvalidRequestException(string message) : base(message) { }
public InvalidRequestException(string message, Exception inner) : base(message, inner) { }
} }
/// <summary> // Exception for no coin found
/// Thrown when the API response indicates that the coin was not found. class CoinNotFoundException : Exception {
/// Generally used when the PCGS number and grade combo that was requested does not exist in the PCGS database.
/// </summary>
public class CoinNotFoundException : Exception {
public CoinNotFoundException() { } public CoinNotFoundException() { }
public CoinNotFoundException(string message) : base(message) { } public CoinNotFoundException(string message) : base(message) { }
public CoinNotFoundException(string message, Exception inner) : base(message, inner) { } public CoinNotFoundException(string message, Exception inner) : base(message, inner) { }
} }
/// <summary>
/// Thrown when the API returns an HTTP error 401.
/// Generally indicates that the API key is invalid.
/// </summary>
public class ApiAuthorizationException : Exception {
public ApiAuthorizationException() { }
public ApiAuthorizationException(string message) : base(message) { }
public ApiAuthorizationException(string message, Exception inner) : base(message, inner) { }
}
public
+13 -1
View File
@@ -41,6 +41,7 @@ public class MainWindowViewModel : ViewModelBase {
public Interaction<DeleteWindowViewModel, Boolean> ShowDeleteWindow { get; } public Interaction<DeleteWindowViewModel, Boolean> ShowDeleteWindow { get; }
public ReactiveCommand<Unit, Unit> ExportCommand { get; } public ReactiveCommand<Unit, Unit> ExportCommand { get; }
public Interaction<Unit, Uri> ShowExportWindow { get; } public Interaction<Unit, Uri> ShowExportWindow { get; }
public Interaction<Unit, Unit> ShowErrorWindow { get; }
private ViewModelBase _sideContent; private ViewModelBase _sideContent;
private Coin? _selectedCoin; private Coin? _selectedCoin;
@@ -55,6 +56,9 @@ public class MainWindowViewModel : ViewModelBase {
DisplayedList = ConnectedCoinDatabase.Collection; DisplayedList = ConnectedCoinDatabase.Collection;
TotalValue = DisplayedList.Sum(x => x.TotalPrice); TotalValue = DisplayedList.Sum(x => x.TotalPrice);
// Set up the ability to show the error window.
ShowErrorWindow = new Interaction<Unit, Unit>();
// Set up the ability to open the delete window. // Set up the ability to open the delete window.
ShowDeleteWindow = new Interaction<DeleteWindowViewModel, bool>(); ShowDeleteWindow = new Interaction<DeleteWindowViewModel, bool>();
var deleteEnabled = this.WhenAnyValue(x => x.SelectedCoin) var deleteEnabled = this.WhenAnyValue(x => x.SelectedCoin)
@@ -89,7 +93,15 @@ public class MainWindowViewModel : ViewModelBase {
// This is the same as the above, but with a different syntax. // This is the same as the above, but with a different syntax.
newViewModel.OkCommand newViewModel.OkCommand
.Subscribe(async requestStructure => { .Subscribe(async requestStructure => {
ConnectedCoinDatabase.CreateCoin(requestStructure.Item1, requestStructure.Item2, requestStructure.Item3); try {
ConnectedCoinDatabase.CreateCoin(requestStructure.Item1, requestStructure.Item2,
requestStructure.Item3);
}
catch (Exception e) {
// TODO Error handling - create a popup window.
Console.WriteLine(e.Message);
}
// TODO Clear the text boxes.
}); });
// Change TotalValue anytime SelectedCoin.TotalPrice changes. // Change TotalValue anytime SelectedCoin.TotalPrice changes.
+7
View File
@@ -53,4 +53,11 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel> {
throw new Exception("User cancelled the file picker."); throw new Exception("User cancelled the file picker.");
} }
} }
public async Task ShowErrorWindowAsync(InteractionContext<Unit, Unit> interaction) {
var window = new ErrorWindow();
window.DataContext = interaction.Input;
await window.ShowDialog(this);
}
} }