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/Views/CoinListView.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/MainWindow.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\PcgsInvUi.AssemblyInfo.cs"/>
<Compile Remove="obj\**"/>
<Compile Remove="Services\CoinCollection.cs" />
</ItemGroup>
+2 -2
View File
@@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.ReactiveUI;
using System;
using PcgsInvUi.ViewModels;
namespace PcgsInvUi;
@@ -9,8 +10,7 @@ class Program {
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
public static void Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
+14 -4
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.Data.SQLite;
using System.Threading.Tasks;
using PcgsInvUi.Models;
namespace PcgsInvUi.Services;
@@ -109,9 +110,10 @@ public class CoinDatabase {
// Execute the command.
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...");
// 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.
@@ -119,13 +121,21 @@ public class CoinDatabase {
if (coin is not null) {
coin.Quantity += quantity;
SaveCoin("CollectionTable", coin);
return PcgsClient.ErrorType.None;
}
else {
// Build a new coin with the API and insert it.
var newCoin = await _pcgsClient.GetCoinFactsByGrade(pcgsNumber, grade);
// Otherwise, build a new coin with the API and insert it.
var apiResult = await _pcgsClient.GetCoinFactsByGrade(pcgsNumber, grade);
if (apiResult.Item1 == PcgsClient.ErrorType.None) {
var newCoin = apiResult.Item2;
newCoin.Quantity = quantity;
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) {
+15 -11
View File
@@ -11,6 +11,13 @@ using ReactiveUI;
namespace PcgsInvUi.Services;
public class PcgsClient : ReactiveObject {
public enum ErrorType {
None,
NoCoinFound,
InvalidRequestFormat,
ApiKeyInvalid
}
public int NumApiRequests {
get => _numApiRequests;
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";
}
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;
using (HttpClient client = new HttpClient()) {
var gradeParam = GetGradeFromString(grade);
@@ -40,15 +47,12 @@ public class PcgsClient : ReactiveObject {
if (response.IsSuccessStatusCode) {
string jsonResponse = await response.Content.ReadAsStringAsync();
newCoin = ParseJsonResponse(jsonResponse);
Console.WriteLine("Coin created.");
}
else {
Console.WriteLine($"Error: {response.StatusCode} - {response.ReasonPhrase}");
var parsedResponse = ParseJsonResponse(jsonResponse);
return parsedResponse;
}
}
return newCoin;
return (ErrorType.ApiKeyInvalid, null);
}
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.
private Coin? ParseJsonResponse(string json) {
private (ErrorType, Coin?) ParseJsonResponse(string json) {
Console.WriteLine(json);
// 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("\"IsValidRequest\":true")) throw new InvalidRequestFormatException("Invalid request format.");
if (json.Contains("\"ServerMessage\":\"No data found\"")) return (ErrorType.NoCoinFound, null);
if (json.Contains("\"IsValidRequest\":false")) return (ErrorType.InvalidRequestFormat, null);
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 ReactiveCommand<Unit, Unit> ExportCommand { get; }
public Interaction<Unit, Uri> ShowExportWindow { get; }
public Interaction<Unit, Unit> ShowErrorWindow { get; }
public Interaction<ErrorWindowViewModel, Unit> ShowErrorWindow { get; }
private ViewModelBase _sideContent;
private Coin? _selectedCoin;
private double _totalValue;
private PcgsClient _pcgsClient;
public MainWindowViewModel(CoinDatabase coins) {
ConnectedCoinDatabase = coins;
@@ -57,7 +56,7 @@ public class MainWindowViewModel : ViewModelBase {
TotalValue = DisplayedList.Sum(x => x.TotalPrice);
// 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.
ShowDeleteWindow = new Interaction<DeleteWindowViewModel, bool>();
@@ -84,8 +83,10 @@ public class MainWindowViewModel : ViewModelBase {
catch (IOException e) {
// Something is wrong with the file after it's been created.
Console.WriteLine(e.Message);
ShowErrorWindow.Handle(new ErrorWindowViewModel(e.Message));
} catch (Exception e) {
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.
newViewModel.OkCommand
.Subscribe(async requestStructure => {
try {
ConnectedCoinDatabase.CreateCoin(requestStructure.Item1, requestStructure.Item2,
requestStructure.Item3);
}
catch (Exception e) {
// TODO Error handling - create a popup window.
Console.WriteLine(e.Message);
var result = await ConnectedCoinDatabase.CreateCoin(requestStructure.Item1, requestStructure.Item2,
requestStructure.Item3);
switch (result) {
case PcgsClient.ErrorType.ApiKeyInvalid:
Console.WriteLine("API key is invalid - showing window.");
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.
});
// 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)
.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();
this.WhenActivated(d => d(ViewModel!.ShowDeleteWindow.RegisterHandler(ShowDeleteWindowAsync)));
this.WhenActivated(d => d(ViewModel!.ShowExportWindow.RegisterHandler(ShowFilePickerAsync)));
this.WhenActivated(d => d(ViewModel!.ShowErrorWindow.RegisterHandler(ShowErrorWindowAsync)));
// 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();
window.DataContext = interaction.Input;