ShowErrorWindow now actually shows the ErrorWindow

This commit is contained in:
alphafetus authored and BobdaFett committed 2023-11-23 18:19:47 -05:00
1 parent d667e86b1b
commit e73f9db02c
10 files changed
+103 -29

No files matched your search

+1
View File
@@ -6,6 +6,7 @@
<entry key="PcgsInvUi/App.axaml" value="PcgsInvUi/PcgsInvUi.csproj" /> <entry key="PcgsInvUi/App.axaml" value="PcgsInvUi/PcgsInvUi.csproj" />
<entry key="PcgsInvUi/Views/CoinListView.axaml" value="PcgsInvUi/PcgsInvUi.csproj" /> <entry key="PcgsInvUi/Views/CoinListView.axaml" value="PcgsInvUi/PcgsInvUi.csproj" />
<entry key="PcgsInvUi/Views/DeleteWindow.axaml" value="PcgsInvUi/PcgsInvUi.csproj" /> <entry key="PcgsInvUi/Views/DeleteWindow.axaml" value="PcgsInvUi/PcgsInvUi.csproj" />
<entry key="PcgsInvUi/Views/ErrorWindow.axaml" value="PcgsInvUi/PcgsInvUi.csproj" />
<entry key="PcgsInvUi/Views/FindWindow.axaml" value="PcgsInvUi/PcgsInvUi.csproj" /> <entry key="PcgsInvUi/Views/FindWindow.axaml" value="PcgsInvUi/PcgsInvUi.csproj" />
<entry key="PcgsInvUi/Views/MainWindow.axaml" value="PcgsInvUi/PcgsInvUi.csproj" /> <entry key="PcgsInvUi/Views/MainWindow.axaml" value="PcgsInvUi/PcgsInvUi.csproj" />
<entry key="PcgsInvUi/Views/MainWindowOld.axaml" value="PcgsInvUi/PcgsInvUi.csproj" /> <entry key="PcgsInvUi/Views/MainWindowOld.axaml" value="PcgsInvUi/PcgsInvUi.csproj" />
+1
View File
@@ -62,6 +62,7 @@
<Compile Include="obj\Debug\net6.0\.NETCoreApp,Version=v6.0.AssemblyAttributes.cs"/> <Compile Include="obj\Debug\net6.0\.NETCoreApp,Version=v6.0.AssemblyAttributes.cs"/>
<Compile Include="obj\Debug\net6.0\PcgsInvUi.AssemblyInfo.cs"/> <Compile Include="obj\Debug\net6.0\PcgsInvUi.AssemblyInfo.cs"/>
<Compile Remove="obj\**"/> <Compile Remove="obj\**"/>
<Compile Remove="Services\CoinCollection.cs" />
</ItemGroup> </ItemGroup>
+2 -2
View File
@@ -1,6 +1,7 @@
using Avalonia; using Avalonia;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
using System; using System;
using PcgsInvUi.ViewModels;
namespace PcgsInvUi; namespace PcgsInvUi;
@@ -9,8 +10,7 @@ class Program {
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break. // yet and stuff might break.
[STAThread] [STAThread]
public static void Main(string[] args) => BuildAvaloniaApp() public static void Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
.StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer. // Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp() public static AppBuilder BuildAvaloniaApp()
+14 -4
View File
@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Data.SQLite; using System.Data.SQLite;
using System.Threading.Tasks;
using PcgsInvUi.Models; using PcgsInvUi.Models;
namespace PcgsInvUi.Services; namespace PcgsInvUi.Services;
@@ -109,9 +110,10 @@ public class CoinDatabase {
// Execute the command. // Execute the command.
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
Console.WriteLine("Coin inserted.");
} }
public async void CreateCoin(int pcgsNumber, string grade, int quantity) { public async Task<PcgsClient.ErrorType> CreateCoin(int pcgsNumber, string grade, int quantity) {
Console.WriteLine("Creating coin..."); Console.WriteLine("Creating coin...");
// Create a coin by calling the API, then insert it into the database. // Create a coin by calling the API, then insert it into the database.
// First, check if the coin already exists - if it does, just update the quantity by adding the amount entered. // First, check if the coin already exists - if it does, just update the quantity by adding the amount entered.
@@ -119,13 +121,21 @@ public class CoinDatabase {
if (coin is not null) { if (coin is not null) {
coin.Quantity += quantity; coin.Quantity += quantity;
SaveCoin("CollectionTable", coin); SaveCoin("CollectionTable", coin);
return PcgsClient.ErrorType.None;
} }
else {
// Build a new coin with the API and insert it. // Otherwise, build a new coin with the API and insert it.
var newCoin = await _pcgsClient.GetCoinFactsByGrade(pcgsNumber, grade); var apiResult = await _pcgsClient.GetCoinFactsByGrade(pcgsNumber, grade);
if (apiResult.Item1 == PcgsClient.ErrorType.None) {
var newCoin = apiResult.Item2;
newCoin.Quantity = quantity; newCoin.Quantity = quantity;
InsertCoin(newCoin); InsertCoin(newCoin);
Collection.Add(newCoin);
return PcgsClient.ErrorType.None;
} }
Console.WriteLine("Error getting coin from API - {0}", apiResult.Item1);
return apiResult.Item1;
} }
public Coin? GetCoin(int pcgsNumber, string grade) { public Coin? GetCoin(int pcgsNumber, string grade) {
+15 -11
View File
@@ -11,6 +11,13 @@ using ReactiveUI;
namespace PcgsInvUi.Services; namespace PcgsInvUi.Services;
public class PcgsClient : ReactiveObject { public class PcgsClient : ReactiveObject {
public enum ErrorType {
None,
NoCoinFound,
InvalidRequestFormat,
ApiKeyInvalid
}
public int NumApiRequests { public int NumApiRequests {
get => _numApiRequests; get => _numApiRequests;
set => this.RaiseAndSetIfChanged(ref _numApiRequests, value); set => this.RaiseAndSetIfChanged(ref _numApiRequests, value);
@@ -26,7 +33,7 @@ public class PcgsClient : ReactiveObject {
"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<(ErrorType, 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);
@@ -40,15 +47,12 @@ public class PcgsClient : ReactiveObject {
if (response.IsSuccessStatusCode) { if (response.IsSuccessStatusCode) {
string jsonResponse = await response.Content.ReadAsStringAsync(); string jsonResponse = await response.Content.ReadAsStringAsync();
newCoin = ParseJsonResponse(jsonResponse); var parsedResponse = ParseJsonResponse(jsonResponse);
Console.WriteLine("Coin created."); return parsedResponse;
}
else {
Console.WriteLine($"Error: {response.StatusCode} - {response.ReasonPhrase}");
} }
} }
return newCoin; return (ErrorType.ApiKeyInvalid, null);
} }
private int GetGradeFromString(string grade) { private int GetGradeFromString(string grade) {
@@ -59,14 +63,14 @@ 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 (ErrorType, Coin?) ParseJsonResponse(string json) {
Console.WriteLine(json); Console.WriteLine(json);
// TODO Check for errors in the response // TODO Check for errors in the response
if (json.Contains("\"ServerMessage\":\"No data found\"")) throw new CoinNotFoundException("No coin found with that PCGS number."); if (json.Contains("\"ServerMessage\":\"No data found\"")) return (ErrorType.NoCoinFound, null);
if (json.Contains("\"IsValidRequest\":true")) throw new InvalidRequestFormatException("Invalid request format."); if (json.Contains("\"IsValidRequest\":false")) return (ErrorType.InvalidRequestFormat, null);
var newCoin = JsonSerializer.Deserialize<Coin>(json); var newCoin = JsonSerializer.Deserialize<Coin>(json);
return newCoin; return (ErrorType.None, newCoin);
} }
} }
@@ -0,0 +1,22 @@
using System;
using System.Reactive;
using ReactiveUI;
using PcgsInvUi.Views;
namespace PcgsInvUi.ViewModels;
public class ErrorWindowViewModel : ViewModelBase {
public Exception DisplayedException {
get => _message;
set => this.RaiseAndSetIfChanged(ref _message, value);
}
private Exception _message;
public ReactiveCommand<ErrorWindow, Unit> CloseCommand { get; }
public ErrorWindowViewModel(string message) {
CloseCommand = ReactiveCommand.Create<ErrorWindow>(window => { window.Close(); });
}
}
+22 -11
View File
@@ -41,12 +41,11 @@ 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; } public Interaction<ErrorWindowViewModel, Unit> ShowErrorWindow { get; }
private ViewModelBase _sideContent; private ViewModelBase _sideContent;
private Coin? _selectedCoin; private Coin? _selectedCoin;
private double _totalValue; private double _totalValue;
private PcgsClient _pcgsClient;
public MainWindowViewModel(CoinDatabase coins) { public MainWindowViewModel(CoinDatabase coins) {
ConnectedCoinDatabase = coins; ConnectedCoinDatabase = coins;
@@ -57,7 +56,7 @@ public class MainWindowViewModel : ViewModelBase {
TotalValue = DisplayedList.Sum(x => x.TotalPrice); TotalValue = DisplayedList.Sum(x => x.TotalPrice);
// Set up the ability to show the error window. // Set up the ability to show the error window.
ShowErrorWindow = new Interaction<Unit, Unit>(); ShowErrorWindow = new Interaction<ErrorWindowViewModel, 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>();
@@ -84,8 +83,10 @@ public class MainWindowViewModel : ViewModelBase {
catch (IOException e) { catch (IOException e) {
// Something is wrong with the file after it's been created. // Something is wrong with the file after it's been created.
Console.WriteLine(e.Message); Console.WriteLine(e.Message);
ShowErrorWindow.Handle(new ErrorWindowViewModel(e.Message));
} catch (Exception e) { } catch (Exception e) {
Console.WriteLine(e.Message); Console.WriteLine(e.Message);
ShowErrorWindow.Handle(new ErrorWindowViewModel(e.Message));
} }
}); });
@@ -93,19 +94,29 @@ 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 => {
try { var result = await ConnectedCoinDatabase.CreateCoin(requestStructure.Item1, requestStructure.Item2,
ConnectedCoinDatabase.CreateCoin(requestStructure.Item1, requestStructure.Item2, requestStructure.Item3);
requestStructure.Item3);
} switch (result) {
catch (Exception e) { case PcgsClient.ErrorType.ApiKeyInvalid:
// TODO Error handling - create a popup window. Console.WriteLine("API key is invalid - showing window.");
Console.WriteLine(e.Message); await ShowErrorWindow.Handle(new ErrorWindowViewModel("API key is invalid - authorization failed."));
break;
case PcgsClient.ErrorType.InvalidRequestFormat:
Console.WriteLine("Request format is invalid - showing window.");
await ShowErrorWindow.Handle(new ErrorWindowViewModel("Request format is invalid."));
break;
case PcgsClient.ErrorType.NoCoinFound:
Console.WriteLine("No coin was found with the given parameters.");
await ShowErrorWindow.Handle(new ErrorWindowViewModel("No coin was found with the given parameters."));
break;
} }
// TODO Clear the text boxes. // TODO Clear the text boxes.
}); });
// Change TotalValue anytime SelectedCoin.TotalPrice changes. // Change TotalValue anytime SelectedCoin.TotalPrice changes.
// Possible null deref - ignored due to null values summing to 0. // Possible null deref - how do you remove this?
this.WhenAnyValue(x => x.SelectedCoin.TotalPrice) this.WhenAnyValue(x => x.SelectedCoin.TotalPrice)
.Subscribe(_ => TotalValue = ConnectedCoinDatabase.Collection.Sum(x => x.TotalPrice)); .Subscribe(_ => TotalValue = ConnectedCoinDatabase.Collection.Sum(x => x.TotalPrice));
} }
+13
View File
@@ -0,0 +1,13 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:PcgsInvUi.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="PcgsInvUi.Views.ErrorWindow" x:DataType="viewModels:ErrorWindowViewModel"
Title="ErrorWindow">
<Grid RowDefinitions="2">
<TextBlock Text="{Binding DisplayedException.Message}" />
<Button Content="OK" Command="{Binding CloseCommand}" />
</Grid>
</Window>
+11
View File
@@ -0,0 +1,11 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace PcgsInvUi.Views;
public partial class ErrorWindow : Window {
public ErrorWindow() {
InitializeComponent();
}
}
+2 -1
View File
@@ -14,6 +14,7 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel> {
InitializeComponent(); InitializeComponent();
this.WhenActivated(d => d(ViewModel!.ShowDeleteWindow.RegisterHandler(ShowDeleteWindowAsync))); this.WhenActivated(d => d(ViewModel!.ShowDeleteWindow.RegisterHandler(ShowDeleteWindowAsync)));
this.WhenActivated(d => d(ViewModel!.ShowExportWindow.RegisterHandler(ShowFilePickerAsync))); this.WhenActivated(d => d(ViewModel!.ShowExportWindow.RegisterHandler(ShowFilePickerAsync)));
this.WhenActivated(d => d(ViewModel!.ShowErrorWindow.RegisterHandler(ShowErrorWindowAsync)));
// this.WhenActivated(d => d(ViewModel!.ShowFindWindow.RegisterHandler(ShowFindWindowAsync))); // this.WhenActivated(d => d(ViewModel!.ShowFindWindow.RegisterHandler(ShowFindWindowAsync)));
} }
@@ -54,7 +55,7 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel> {
} }
} }
public async Task ShowErrorWindowAsync(InteractionContext<Unit, Unit> interaction) { public async Task ShowErrorWindowAsync(InteractionContext<ErrorWindowViewModel, Unit> interaction) {
var window = new ErrorWindow(); var window = new ErrorWindow();
window.DataContext = interaction.Input; window.DataContext = interaction.Input;