ShowErrorWindow now actually shows the ErrorWindow
This commit is contained in:
1 parent
d667e86b1b
commit
e73f9db02c
10 files changed
+104
-30
No files matched your search
Generated
+1
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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(); });
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -0,0 +1,11 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace PcgsInvUi.Views;
|
||||
|
||||
public partial class ErrorWindow : Window {
|
||||
public ErrorWindow() {
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in new issue
Block a user