diff --git a/PcgsInvUi/Services/PcgsClient.cs b/PcgsApi/PcgsClient.cs
similarity index 65%
rename from PcgsInvUi/Services/PcgsClient.cs
rename to PcgsApi/PcgsClient.cs
index 0f70915..d16e001 100644
--- a/PcgsInvUi/Services/PcgsClient.cs
+++ b/PcgsApi/PcgsClient.cs
@@ -1,40 +1,34 @@
-using System;
-using System.Net.Http;
-using System.Net.Http.Headers;
-using System.Threading.Tasks;
-using PcgsInvUi.Models;
+using System.Net.Http.Headers;
using System.Text.Json;
using ReactiveUI;
+using ReactiveUI.SourceGenerators;
-namespace PcgsInvUi.Services;
+namespace PcgsApi;
-public class PcgsClient : ReactiveObject {
+public partial class PcgsClient : ReactiveObject {
public enum ErrorType {
None,
NoCoinFound,
InvalidRequestFormat,
ApiKeyInvalid
}
-
- public int NumApiRequests {
- get => _numApiRequests;
- set => this.RaiseAndSetIfChanged(ref _numApiRequests, value);
- }
-
- private string _apiUri = "https://api.pcgs.com/publicapi";
- private readonly string _apiKey;
- private int _numApiRequests;
+
+ protected readonly string _apiKey;
+
+ protected readonly string _apiUri = "https://api.pcgs.com/publicapi";
///
- /// Creates a new instance of the PcgsClient class.
- /// Although this is a constructor, it's meant to be called only from the CreateClient method.
+ /// Creates a new instance of the PcgsClient class.
+ /// Although this is a constructor, it's meant to be called only from the CreateClient method.
///
private PcgsClient(string apiKey) {
_apiKey = apiKey;
}
-
+
+ [Reactive] private int _numApiRequests;
+
///
- /// Creates a new instance of the PcgsClient class.
+ /// Creates a new instance of the PcgsClient class.
///
/// The api key to use for requests.
/// A new instance of the PcgsClient class, or null if the key is invalid.
@@ -47,83 +41,87 @@ public class PcgsClient : ReactiveObject {
}
///
- /// Sends a request to the API to verify the credentials.
+ /// Sends a request to the API to verify the credentials.
///
/// A boolean indicating whether or not the credentials are valid.
public async Task VerifyCredentials() {
// Create a way to check if the api key given is valid
// I think the best way to do this is to make a request to the api and see if it returns the expected response.
- var result = await this.GetCoinFactsByGrade(1, "AG-03"); // This is a known invalid coin id - this is because the api is very fast with invalid requests.
+ var result =
+ await GetCoinFactsByGrade(1,
+ "AG-03"); // This is a known invalid coin id - this is because the api is very fast with invalid requests.
if (result.Item1 == ErrorType.ApiKeyInvalid) return false;
return true;
}
///
- /// Gets the coin information for a given PCGS number and grade.
+ /// Gets the coin information for a given PCGS number and grade.
///
/// The PCGS number of the coin.
/// The grade of the coin.
/// Whether or not the coin is a plus grade.
/// A tuple containing the error type and the coin information.
- public async Task<(ErrorType, Coin?)> GetCoinFactsByGrade(int pcgsNumber, string grade, bool plusGrade = false) {
- using (HttpClient client = new HttpClient()) {
+ public async Task<(ErrorType, PcgsCoin?)>
+ GetCoinFactsByGrade(int pcgsNumber, string grade, bool plusGrade = false) {
+ using (var client = new HttpClient()) {
var gradeParam = GetGradeFromString(grade);
- string requestUri =
+ var requestUri =
$"{_apiUri}/coindetail/GetCoinFactsByGrade/?PCGSNo={pcgsNumber}&GradeNo={gradeParam}&PlusGrade={plusGrade}";
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", _apiKey);
Console.WriteLine($"Sending request to {requestUri}");
- HttpResponseMessage response = await client.GetAsync(requestUri);
+ var response = await client.GetAsync(requestUri);
Console.WriteLine("Got response.");
if (response.IsSuccessStatusCode) {
// Check response for errors.
- string jsonResponse = await response.Content.ReadAsStringAsync();
+ var jsonResponse = await response.Content.ReadAsStringAsync();
var parsedResponse = ParseJsonResponse(jsonResponse);
return parsedResponse;
}
}
-
+
return (ErrorType.ApiKeyInvalid, null);
}
///
- /// Utility function to parse the grade number from the grade string passed from the front end.
+ /// Utility function to parse the grade number from the grade string passed from the front end.
///
/// The grade string.
/// The grade number.
private int GetGradeFromString(string grade) {
- var actualGrade = int.Parse(grade.Substring(grade.Length - 2)); // Throws an exception if the grade doesn't exist.
+ var actualGrade =
+ int.Parse(grade.Substring(grade.Length - 2)); // Throws an exception if the grade doesn't exist.
Console.WriteLine($"Grade is {actualGrade}");
return actualGrade;
}
///
- /// Parses the json response from the api.
+ /// Parses the json response from the api.
///
/// The json response.
/// A tuple containing an error type and the coin information.
- private (ErrorType, Coin?) ParseJsonResponse(string json) {
+ private (ErrorType, PcgsCoin?) ParseJsonResponse(string json) {
Console.WriteLine(json);
// Check for errors in the response
if (json.Contains("\"ServerMessage\":\"No data found\"")) return (ErrorType.NoCoinFound, null);
if (json.Contains("\"IsValidRequest\":false")) return (ErrorType.InvalidRequestFormat, null);
- var newCoin = JsonSerializer.Deserialize(json);
+ var newCoin = JsonSerializer.Deserialize(json);
return (ErrorType.None, newCoin);
}
}
// Exception for invalid request format
-class InvalidRequestFormatException : Exception {
+internal class InvalidRequestFormatException : Exception {
public InvalidRequestFormatException() { }
public InvalidRequestFormatException(string message) : base(message) { }
public InvalidRequestFormatException(string message, Exception inner) : base(message, inner) { }
}
// Exception for no coin found
-class CoinNotFoundException : Exception {
+internal class CoinNotFoundException : Exception {
public CoinNotFoundException() { }
public CoinNotFoundException(string message) : base(message) { }
public CoinNotFoundException(string message, Exception inner) : base(message, inner) { }
-}
+}
\ No newline at end of file
diff --git a/PcgsApi/PcgsCoin.cs b/PcgsApi/PcgsCoin.cs
new file mode 100644
index 0000000..95c7683
--- /dev/null
+++ b/PcgsApi/PcgsCoin.cs
@@ -0,0 +1,38 @@
+using System.Diagnostics;
+using System.Reactive.Linq;
+using ReactiveUI;
+using ReactiveUI.SourceGenerators;
+
+namespace PcgsApi;
+
+public partial class PcgsCoin : ReactiveObject {
+ [Reactive] private string _pcgsNumber;
+ [Reactive] private string _name;
+ [Reactive] private int _year;
+ [Reactive] private string _denomination;
+ [Reactive] private string _mintMark;
+ [Reactive] private string _grade;
+ [Reactive] private string _coinFactsLink;
+ [Reactive] private string _majorVariety;
+ [Reactive] private string _minorVariety;
+ [Reactive] private string _dieVariety;
+ [Reactive] private string _seriesName;
+ [Reactive] private string _category;
+ [Reactive] private string _designation;
+ [Reactive] private int _certificateNumber;
+ [Reactive] private double _paidFor;
+ [Reactive] private string _notes;
+ [Reactive] private int _quantity;
+ [Reactive] private double _priceGuideValue;
+ [ObservableAsProperty] private double _totalPrice;
+
+ public PcgsCoin() {
+ _totalPriceHelper = this.WhenAnyValue(
+ x => x.Quantity,
+ x => x.PriceGuideValue,
+ (quantity, price) => quantity * price
+ )
+ .Do(_ => Debug.WriteLine("PcgsCoin total price calculated"))
+ .ToProperty(this, nameof(TotalPrice));
+ }
+}
\ No newline at end of file
diff --git a/PcgsInv/Models/CoinCollection.cs b/PcgsInv/Models/CoinCollection.cs
new file mode 100644
index 0000000..92b926c
--- /dev/null
+++ b/PcgsInv/Models/CoinCollection.cs
@@ -0,0 +1,47 @@
+using ReactiveUI;
+using ReactiveUI.SourceGenerators;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Linq;
+using System.Reactive.Linq;
+using DynamicData;
+using DynamicData.Binding;
+using PcgsApi;
+
+namespace PcgsInv.Models;
+
+///
+/// Contains all information related to a collection of coins.
+///
+public partial class CoinCollection : ReactiveObject {
+ ///
+ /// The name of the collection.
+ ///
+ [Reactive] private string _name;
+
+ ///
+ /// The collection of objects.
+ ///
+ [Reactive] private ObservableCollection _coins;
+
+ ///
+ /// The total value of the collection.
+ ///
+ [ObservableAsProperty] private double _totalValue;
+
+ ///
+ /// Creates a new CoinCollection instance.
+ ///
+ public CoinCollection() {
+ Name = string.Empty;
+ Coins = [];
+
+ Coins.ToObservableChangeSet()
+ .AutoRefresh(x => x.TotalPrice)
+ .ToCollection()
+ .Select(coins => coins.Sum(c => c.TotalPrice))
+ .ToProperty(this, nameof(TotalValue), out _totalValueHelper);
+ }
+}
\ No newline at end of file
diff --git a/PcgsInvUi/App.axaml b/PcgsInvUi/App.axaml
index 0855646..636641b 100644
--- a/PcgsInvUi/App.axaml
+++ b/PcgsInvUi/App.axaml
@@ -1,7 +1,6 @@
diff --git a/PcgsInvUi/App.axaml.cs b/PcgsInvUi/App.axaml.cs
index 8501681..84910bc 100644
--- a/PcgsInvUi/App.axaml.cs
+++ b/PcgsInvUi/App.axaml.cs
@@ -7,7 +7,7 @@ using PcgsInvUi.Views;
namespace PcgsInvUi;
-public partial class App : Application {
+public class App : Application {
public override void Initialize() {
AvaloniaXamlLoader.Load(this);
}
@@ -17,14 +17,13 @@ public partial class App : Application {
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) {
var coins = new CoinDatabase();
desktop.MainWindow = new MainWindow {
- DataContext = new MainWindowViewModel(coins),
+ DataContext = new MainWindowViewModel(coins)
};
-
+
// Allow the application to save the database when it exits.
- desktop.Exit += (sender, args) => {
- coins.UpdateCollection("CollectionTable");
- };
+ desktop.Exit += (sender, args) => { coins.UpdateCollection("CollectionTable"); };
}
+
base.OnFrameworkInitializationCompleted();
}
-}
+}
\ No newline at end of file
diff --git a/PcgsInvUi/CMakeLists.txt b/PcgsInvUi/CMakeLists.txt
index 7c894f7..bc5220c 100644
--- a/PcgsInvUi/CMakeLists.txt
+++ b/PcgsInvUi/CMakeLists.txt
@@ -5,33 +5,33 @@ project(PcgsInvUi LANGUAGES CSharp)
include(CSharpUtilities)
add_executable(PcgsInvUi
- App.axaml.cs
- Program.cs
- ViewLocator.cs
- App.axaml
- app.manifest
- Models/Coin.cs
- Services/CoinCollection.cs
- Services/CoinDatabase.cs
- Services/PcgsClient.cs
- ViewModels/CoinListViewModel.cs
- ViewModels/DeleteWindowViewModel.cs
- ViewModels/EditViewModel.cs
- ViewModels/ErrorWindowViewModel.cs
- ViewModels/FindWindowViewModel.cs
- ViewModels/MainWindowViewModel.cs
- ViewModels/NewViewModel.cs
- ViewModels/ViewModelBase.cs
- Views/DeleteWindow.axaml
- Views/DeleteWindow.axaml.cs
- Views/ErrorWindow.axaml
- Views/ErrorWindow.axaml.cs
- Views/FindWindow.axaml
- Views/FindWindow.axaml.cs
- Views/MainWindow.axaml
- Views/MainWindow.axaml.cs
- Views/NewView.axaml
- Views/NewView.axaml.cs
+ App.axaml.cs
+ Program.cs
+ ViewLocator.cs
+ App.axaml
+ app.manifest
+ Models/Coin.cs
+ Services/CoinCollection.cs
+ Services/CoinDatabase.cs
+ Services/PcgsClient.cs
+ ViewModels/CoinListViewModel.cs
+ ViewModels/DeleteWindowViewModel.cs
+ ViewModels/EditViewModel.cs
+ ViewModels/ErrorWindowViewModel.cs
+ ViewModels/FindWindowViewModel.cs
+ ViewModels/MainWindowViewModel.cs
+ ViewModels/NewViewModel.cs
+ ViewModels/ViewModelBase.cs
+ Views/DeleteWindow.axaml
+ Views/DeleteWindow.axaml.cs
+ Views/ErrorWindow.axaml
+ Views/ErrorWindow.axaml.cs
+ Views/FindWindow.axaml
+ Views/FindWindow.axaml.cs
+ Views/MainWindow.axaml
+ Views/MainWindow.axaml.cs
+ Views/NewView.axaml
+ Views/NewView.axaml.cs
)
# Set the .NET Framework version for the executable.
@@ -43,5 +43,5 @@ set(CMAKE_CSharp_FLAGS "/langversion:latest")
# Add the .NET reference libraries as dependencies.
set_property(TARGET PcgsInvUi PROPERTY VS_DOTNET_REFERENCES
- "Microsoft.CSharp"
+ "Microsoft.CSharp"
)
diff --git a/PcgsInvUi/Models/Coin.cs b/PcgsInvUi/Models/Coin.cs
deleted file mode 100644
index 2d9e8bf..0000000
--- a/PcgsInvUi/Models/Coin.cs
+++ /dev/null
@@ -1,165 +0,0 @@
-using ReactiveUI;
-
-namespace PcgsInvUi.Models;
-
-public class Coin : ReactiveObject {
- public string PCGSNo {
- get => _pcgsNo;
- set => this.RaiseAndSetIfChanged(ref _pcgsNo, value);
- }
-
- private string _pcgsNo;
-
- public string Name {
- get => _name;
- set => this.RaiseAndSetIfChanged(ref _name, value);
- }
-
- private string _name;
-
- public int Year {
- get => _year;
- set => this.RaiseAndSetIfChanged(ref _year, value);
- }
-
- private int _year;
-
- public string Denomination {
- get => _denomination;
- set => this.RaiseAndSetIfChanged(ref _denomination, value);
- }
-
- private string _denomination;
-
- public string MintMark {
- get => _mintMark;
- set => this.RaiseAndSetIfChanged(ref _mintMark, value);
- }
-
- private string _mintMark;
-
- public string Grade {
- get => _grade;
- set => this.RaiseAndSetIfChanged(ref _grade, value);
- }
-
- private string _grade;
-
- public double PriceGuideValue {
- get => _priceGuideValue;
- set {
- TotalPrice = value * Quantity;
- this.RaiseAndSetIfChanged(ref _priceGuideValue, value);
- }
- }
-
- private double _priceGuideValue;
-
- public string CoinFactsLink {
- get => _coinFactsLink;
- set => this.RaiseAndSetIfChanged(ref _coinFactsLink, value);
- }
-
- private string _coinFactsLink;
-
- public string MajorVariety {
- get => _majorVariety;
- set => this.RaiseAndSetIfChanged(ref _majorVariety, value);
- }
-
- private string _majorVariety;
-
- public string MinorVariety {
- get => _minorVariety;
- set => this.RaiseAndSetIfChanged(ref _minorVariety, value);
- }
-
- private string _minorVariety;
-
- public string DieVariety {
- get => _dieVariety;
- set => this.RaiseAndSetIfChanged(ref _dieVariety, value);
- }
-
- private string _dieVariety;
-
- public string SeriesName {
- get => _seriesName;
- set => this.RaiseAndSetIfChanged(ref _seriesName, value);
- }
-
- private string _seriesName;
-
- public string Category {
- get => _category;
- set => this.RaiseAndSetIfChanged(ref _category, value);
- }
-
- private string _category;
-
- public string Designation {
- get => _designation;
- set => this.RaiseAndSetIfChanged(ref _designation, value);
- }
-
- private string _designation;
-
- public int CertificateNumber {
- get => _certificateNumber;
- set => this.RaiseAndSetIfChanged(ref _certificateNumber, value);
- }
-
- private int _certificateNumber;
-
- public int Quantity {
- get => _quantity;
- set {
- TotalPrice = value * PriceGuideValue;
- this.RaiseAndSetIfChanged(ref _quantity, value);
- }
- }
-
- private int _quantity;
-
- public double TotalPrice {
- get => _totalPrice;
- set => this.RaiseAndSetIfChanged(ref _totalPrice, value);
- }
-
- private double _totalPrice;
-
- public double PaidFor {
- get => _paidFor;
- set => this.RaiseAndSetIfChanged(ref _paidFor, value);
- }
-
- private double _paidFor;
-
- public string Notes {
- get => _notes;
- set => this.RaiseAndSetIfChanged(ref _notes, value);
- }
-
- private string _notes;
-
- public Coin() {
- PCGSNo = "";
- Name = "";
- Year = 0;
- Denomination = "";
- MintMark = "";
- Grade = "";
- PriceGuideValue = 0;
- CoinFactsLink = "";
- MajorVariety = "";
- MinorVariety = "";
- DieVariety = "";
- SeriesName = "";
- Category = "";
- Designation = "";
- CertificateNumber = 0;
- Quantity = 0;
- PaidFor = 0;
- Notes = "";
- }
-}
\ No newline at end of file
diff --git a/PcgsInvUi/PcgsInvUi.csproj b/PcgsInvUi/PcgsInvUi.csproj
index 11fa9a3..07462f8 100644
--- a/PcgsInvUi/PcgsInvUi.csproj
+++ b/PcgsInvUi/PcgsInvUi.csproj
@@ -1,13 +1,14 @@
WinExe
- net6.0
+ net10.0enabletrueapp.manifesttrueBobdaFett0.0.5
+ latestmajor
@@ -17,16 +18,17 @@
-
-
-
-
-
+
+
+
+
+
-
-
+
+
+
-
+
@@ -65,7 +67,7 @@
-
+
@@ -90,6 +92,11 @@
-
+
+
+
+
+
+
diff --git a/PcgsInvUi/Program.cs b/PcgsInvUi/Program.cs
index cc1d9e7..d9d4aeb 100644
--- a/PcgsInvUi/Program.cs
+++ b/PcgsInvUi/Program.cs
@@ -1,22 +1,24 @@
-using Avalonia;
+using System;
+using Avalonia;
using Avalonia.ReactiveUI;
-using System;
-using PcgsInvUi.ViewModels;
namespace PcgsInvUi;
-class Program {
+internal class Program {
// Initialization code. Don't use any Avalonia, third-party APIs or any
// 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()
- => AppBuilder.Configure()
+ public static AppBuilder BuildAvaloniaApp() {
+ return AppBuilder.Configure()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace()
.UseReactiveUI();
+ }
}
\ No newline at end of file
diff --git a/PcgsInvUi/Services/CoinDatabase.cs b/PcgsInvUi/Services/CoinDatabase.cs
index 03e6cc1..cd175fb 100644
--- a/PcgsInvUi/Services/CoinDatabase.cs
+++ b/PcgsInvUi/Services/CoinDatabase.cs
@@ -1,22 +1,17 @@
using System;
using System.Collections.ObjectModel;
using System.Data.SQLite;
+using System.IO;
using System.Threading.Tasks;
-using PcgsInvUi.Models;
namespace PcgsInvUi.Services;
public class CoinDatabase {
- public SQLiteConnection Connection { get; set; }
- private Boolean IsConnected { get; set; }
- public ObservableCollection Collection { get; set; }
- public Boolean IsClientConnected { get; set; }
-
private PcgsClient? _pcgsClient;
-
+
///
- /// Creates and initilizes a new instance of the CoinDatabase.
- /// Must call TryInitApiClient() after creating a new instance.
+ /// Creates and initilizes a new instance of the CoinDatabase.
+ /// Must call TryInitApiClient() after creating a new instance.
///
public CoinDatabase() {
// Create a connection to SQLite
@@ -25,13 +20,18 @@ public class CoinDatabase {
CreateCollection("CollectionTable");
CreateApiTable();
Console.WriteLine("Connected to database.");
- Collection = new ObservableCollection();
+ Collection = new ObservableCollection();
GetCollection("CollectionTable");
Console.WriteLine("Got collection.");
}
+ public SQLiteConnection Connection { get; set; }
+ private bool IsConnected { get; set; }
+ public ObservableCollection Collection { get; set; }
+ public bool IsClientConnected { get; set; }
+
///
- /// Destructor. Currently not used, due to the strange nature of desktop applications.
+ /// Destructor. Currently not used, due to the strange nature of desktop applications.
///
~CoinDatabase() {
Console.WriteLine("Destructor called, saving collection.");
@@ -40,14 +40,14 @@ public class CoinDatabase {
// Close the connection.
Connection.Close();
}
-
+
///
- /// Attempts to intitialize the API client by selecting the API key from the database.
+ /// Attempts to intitialize the API client by selecting the API key from the database.
///
/// True if the API key was found, false otherwise.
public async Task TryInitApiClient() {
Console.Write("Attempting to initialize API client... ");
- SQLiteCommand cmd = Connection.CreateCommand();
+ var cmd = Connection.CreateCommand();
cmd.CommandText = "SELECT API_KEY FROM ApiTable";
using (var reader = cmd.ExecuteReader()) {
@@ -70,13 +70,14 @@ public class CoinDatabase {
Console.WriteLine("Failed. API key not found.");
}
}
+
return IsClientConnected;
}
///
- /// Atttempts to initialize the PCGS API client.
+ /// Atttempts to initialize the PCGS API client.
///
- /// The API key to verify.
+ /// The API key to verify.
/// A Task with a return value that returns true if the client intializes properly.
public async Task TryInitApiClient(string apiKey) {
Console.Write("Attempting to initialize API client with key param... ");
@@ -98,23 +99,23 @@ public class CoinDatabase {
}
///
- /// Gets the collection from the database and stores it in the Collection property.
- /// Creates the collection table if it does not exist already.
+ /// Gets the collection from the database and stores it in the Collection property.
+ /// Creates the collection table if it does not exist already.
///
/// The SQLiteConnection that corresponds to the connected database.
private SQLiteConnection CreateConnection() {
// Check if database exists.
- if (!System.IO.File.Exists("coin_collection")) {
+ if (!File.Exists("coin_collection")) {
// If not, create the database.
Console.Write("Creating database... ");
SQLiteConnection.CreateFile("coin_collection.sqlite");
Console.WriteLine("Done.");
}
-
+
// Create a connection to the database.
- SQLiteConnection connection =
+ var connection =
new SQLiteConnection("DataSource=coin_collection");
-
+
// Open the connection.
try {
connection.Open();
@@ -128,7 +129,7 @@ public class CoinDatabase {
}
///
- /// Creates the table that stores the API key and the number of requests remaining.
+ /// Creates the table that stores the API key and the number of requests remaining.
///
public void CreateApiTable() {
// Create a table to store the API key and the number of requests remaining.
@@ -139,12 +140,12 @@ public class CoinDatabase {
}
// Create a SQL command.
- SQLiteCommand cmd = Connection.CreateCommand();
+ var cmd = Connection.CreateCommand();
cmd.CommandText =
- "CREATE TABLE IF NOT EXISTS ApiTable (" +
- "API_KEY TEXT, " +
- "REQUESTS_REMAINING INTEGER, " +
- "PRIMARY KEY(API_KEY))";
+ "CREATE TABLE IF NOT EXISTS ApiTable (" +
+ "API_KEY TEXT, " +
+ "REQUESTS_REMAINING INTEGER, " +
+ "PRIMARY KEY(API_KEY))";
// Execute the command
cmd.ExecuteNonQuery();
@@ -152,7 +153,7 @@ public class CoinDatabase {
}
///
- /// Creates a table to store the collection.
+ /// Creates a table to store the collection.
///
public void CreateCollection(string collectionName) {
// Create a table to store the collection.
@@ -161,9 +162,9 @@ public class CoinDatabase {
Console.WriteLine("Not connected to database.");
return;
}
-
+
// Create a SQL command.
- SQLiteCommand cmd = Connection.CreateCommand();
+ var cmd = Connection.CreateCommand();
cmd.CommandText =
$"CREATE TABLE IF NOT EXISTS {collectionName} (" +
"PCGS_NUMBER TEXT," +
@@ -184,16 +185,16 @@ public class CoinDatabase {
"QUANTITY INTEGER," +
"NOTES TEXT," +
"PRIMARY KEY(PCGS_NUMBER, GRADE))";
-
+
// Execute the command.
cmd.ExecuteNonQuery();
Console.WriteLine("Collection table initialized.");
}
///
- /// Inserts a Coin object into the database.
+ /// Inserts a Coin object into the database.
///
- public void InsertCoin(Coin coin) {
+ public void InsertCoin(PcgsCoin pcgsCoin) {
Console.WriteLine("Inserting coin...");
// Use our existing connection to insert a coin to the database.
if (!IsConnected) {
@@ -201,26 +202,26 @@ public class CoinDatabase {
Console.WriteLine("Not connected to database.");
return;
}
-
+
// Create a SQL command.
- SQLiteCommand cmd = Connection.CreateCommand();
+ var cmd = Connection.CreateCommand();
cmd.CommandText =
"INSERT INTO CollectionTable (PCGS_NUMBER, GRADE, YEAR," +
"DENOMINATION, MINT_MARK, PRICE_GUIDE_VALUE, COIN_FACTS_LINK," +
"MAJOR_VARIETY, MINOR_VARIETY, DIE_VARIETY, SERIES_NAME, CATEGORY, DESIGNATION," +
"CERT_NUM, QUANTITY, NOTES) " +
- $"VALUES ('{coin.PCGSNo}', '{coin.Grade}', {coin.Year}, '{coin.Denomination}', '{coin.MintMark}', {coin.PriceGuideValue}," +
- $"'{coin.CoinFactsLink}', '{coin.MajorVariety}', '{coin.MinorVariety}', '{coin.DieVariety}', '{coin.SeriesName}', " +
- $"'{coin.Category}', '{coin.Designation}', {coin.CertificateNumber}, {coin.Quantity}, @Notes)";
- cmd.Parameters.AddWithValue("@Notes", coin.Notes);
-
+ $"VALUES ('{pcgsCoin.PcgsNumber}', '{pcgsCoin.Grade}', {pcgsCoin.Year}, '{pcgsCoin.Denomination}', '{pcgsCoin.MintMark}', {pcgsCoin.PriceGuideValue}," +
+ $"'{pcgsCoin.CoinFactsLink}', '{pcgsCoin.MajorVariety}', '{pcgsCoin.MinorVariety}', '{pcgsCoin.DieVariety}', '{pcgsCoin.SeriesName}', " +
+ $"'{pcgsCoin.Category}', '{pcgsCoin.Designation}', {pcgsCoin.CertificateNumber}, {pcgsCoin.Quantity}, @Notes)";
+ cmd.Parameters.AddWithValue("@Notes", pcgsCoin.Notes);
+
// Execute the command.
cmd.ExecuteNonQuery();
Console.WriteLine("Coin inserted.");
}
///
- /// Creates a Coin object and saves it to the database.
+ /// Creates a Coin object and saves it to the database.
///
/// The PCGS number of the coin.
/// The grade of the coin.
@@ -236,7 +237,7 @@ public class CoinDatabase {
SaveCoin("CollectionTable", coin);
return PcgsClient.ErrorType.None;
}
-
+
// Otherwise, build a new coin with the API and insert it.
var apiResult = await _pcgsClient.GetCoinFactsByGrade(pcgsNumber, grade);
if (apiResult.Item1 == PcgsClient.ErrorType.None) {
@@ -246,68 +247,68 @@ public class CoinDatabase {
Collection.Add(newCoin);
return PcgsClient.ErrorType.None;
}
-
+
Console.WriteLine("Error getting coin from API - {0}", apiResult.Item1);
return apiResult.Item1;
}
-
+
///
- /// Gets a coin from the database.
+ /// Gets a coin from the database.
///
/// The PCGS number of the coin.
/// The grade of the coin.
/// The coin if it exists, null otherwise.
- public Coin? GetCoin(int pcgsNumber, string grade) {
+ public PcgsCoin? GetCoin(int pcgsNumber, string grade) {
Console.WriteLine($"Getting coin {pcgsNumber}, {grade}...");
- int gradeInt = GetGradeFromString(grade);
-
+ var gradeInt = GetGradeFromString(grade);
+
// Check the collection to see if the coin exists.
// We can't make a more efficient algorithm since there's not really an ordering to the collection.
- foreach (var coin in Collection) {
- if (coin.PCGSNo == pcgsNumber.ToString() && coin.Grade.Contains(gradeInt.ToString())) { // This has the possibility of a false positive for single digit grades.
+ foreach (var coin in Collection)
+ if (coin.PcgsNumber == pcgsNumber.ToString() && coin.Grade.Contains(gradeInt.ToString())) {
+ // This has the possibility of a false positive for single digit grades.
if (gradeInt < 10)
- if (char.IsDigit(coin.Grade[3])) continue; // TODO For right now, we're going to assume that the first 2 characters are ciruclation strings, and the next 2 are grade numbers.
+ if (char.IsDigit(coin.Grade[3]))
+ continue; // TODO For right now, we're going to assume that the first 2 characters are ciruclation strings, and the next 2 are grade numbers.
Console.WriteLine("Found coin.");
return coin;
}
- }
-
+
Console.WriteLine("Couldn't find coin.");
return null;
}
///
- /// Used to get all Coin objects within the database.
+ /// Used to get all Coin objects within the database.
///
/// The name of the collection table.
public void GetCollection(string collectionName) {
Console.WriteLine("Getting collection...");
- SQLiteCommand cmd = Connection.CreateCommand();
+ var cmd = Connection.CreateCommand();
cmd.CommandText = $"SELECT * FROM {collectionName}";
-
+
using (var reader = cmd.ExecuteReader()) {
- while (reader.Read()) {
+ while (reader.Read())
// Create coin from reader then add to list.
Collection.Add(CoinFromReader(reader));
- }
}
}
///
- /// Creates a CSV formatted string from a collection.
+ /// Creates a CSV formatted string from a collection.
///
/// The name of the collection table.
/// A CSV formatted string.
- public String CollectionToCSV(string collectionName) {
+ public string CollectionToCSV(string collectionName) {
var cmd = Connection.CreateCommand();
cmd.CommandText = $"SELECT * FROM {collectionName}";
var headersCommand = Connection.CreateCommand();
headersCommand.CommandText = $"PRAGMA table_info({collectionName})";
-
+
var resultString = "";
var numHeaders = 0;
-
+
// Get the headers.
using (var reader = headersCommand.ExecuteReader()) {
while (reader.Read()) {
@@ -322,23 +323,20 @@ public class CoinDatabase {
using (var reader = cmd.ExecuteReader()) {
while (reader.Read()) {
// Read information from the reader, then add to CSV string.
- for (int i = 0; i < numHeaders; i++) {
+ for (var i = 0; i < numHeaders; i++) {
// Get the type of each column.
var type = reader.GetFieldType(i);
Console.WriteLine("Type: " + type);
- if (type == typeof(Int64)) {
+ if (type == typeof(long))
resultString += reader.GetInt32(i) + ",";
- }
- else if (type == typeof(Double)) {
+ else if (type == typeof(double))
resultString += reader.GetDouble(i) + ",";
- }
- else if (type == typeof(String)) {
+ else if (type == typeof(string))
resultString += reader.GetString(i) + ",";
- }
- else {
+ else
resultString += "NULL" + ",";
- }
}
+
resultString += "\n";
}
}
@@ -347,91 +345,91 @@ public class CoinDatabase {
}
///
- /// Saves a Coin object to the database.
+ /// Saves a Coin object to the database.
///
/// The name of the collection table.
- /// The coin to save.
- public void SaveCoin(string collectionName, Coin coin) {
+ /// The coin to save.
+ public void SaveCoin(string collectionName, PcgsCoin pcgsCoin) {
// Get and replace the coin from the database.
Console.WriteLine("Saving coin...");
- SQLiteCommand cmd = Connection.CreateCommand();
+ var cmd = Connection.CreateCommand();
cmd.CommandText = $"UPDATE {collectionName} " +
- $"SET YEAR = {coin.Year}, " +
- $"DENOMINATION = \'{coin.Denomination}\', " +
- $"MINT_MARK = \'{coin.MintMark}\', " +
- $"PRICE_GUIDE_VALUE = \'{coin.PriceGuideValue}\', " +
- $"COIN_FACTS_LINK = \'{coin.CoinFactsLink}\', " +
- $"MAJOR_VARIETY = \'{coin.MajorVariety}\', " +
- $"MINOR_VARIETY = \'{coin.MinorVariety}\', " +
- $"DIE_VARIETY = \'{coin.DieVariety}\', " +
- $"SERIES_NAME = \'{coin.SeriesName}\', " +
- $"CATEGORY = \'{coin.Category}\', " +
- $"DESIGNATION = \'{coin.Designation}\', " +
- $"CERT_NUM = \'{coin.CertificateNumber}\', " +
- $"QUANTITY = {coin.Quantity}, " +
- $"NOTES = @Notes " +
- $"WHERE PCGS_NUMBER = {coin.PCGSNo} AND GRADE = \'{coin.Grade}\'";
- cmd.Parameters.AddWithValue("@Notes", coin.Notes);
+ $"SET YEAR = {pcgsCoin.Year}, " +
+ $"DENOMINATION = \'{pcgsCoin.Denomination}\', " +
+ $"MINT_MARK = \'{pcgsCoin.MintMark}\', " +
+ $"PRICE_GUIDE_VALUE = \'{pcgsCoin.PriceGuideValue}\', " +
+ $"COIN_FACTS_LINK = \'{pcgsCoin.CoinFactsLink}\', " +
+ $"MAJOR_VARIETY = \'{pcgsCoin.MajorVariety}\', " +
+ $"MINOR_VARIETY = \'{pcgsCoin.MinorVariety}\', " +
+ $"DIE_VARIETY = \'{pcgsCoin.DieVariety}\', " +
+ $"SERIES_NAME = \'{pcgsCoin.SeriesName}\', " +
+ $"CATEGORY = \'{pcgsCoin.Category}\', " +
+ $"DESIGNATION = \'{pcgsCoin.Designation}\', " +
+ $"CERT_NUM = \'{pcgsCoin.CertificateNumber}\', " +
+ $"QUANTITY = {pcgsCoin.Quantity}, " +
+ $"NOTES = @Notes " +
+ $"WHERE PCGS_NUMBER = {pcgsCoin.PcgsNumber} AND GRADE = \'{pcgsCoin.Grade}\'";
+ cmd.Parameters.AddWithValue("@Notes", pcgsCoin.Notes);
Console.WriteLine(cmd.CommandText);
// Execute the command.
cmd.ExecuteNonQuery();
}
///
- /// Synchronizes the database with the current contents of the specified collection.
+ /// Synchronizes the database with the current contents of the specified collection.
///
/// The name of the collection table.
public void UpdateCollection(string collectionName) {
// Update the database with the contents of the collection.
// TODO This is a very inefficient way of doing this. I should be able to do this in one command.
- foreach (var coin in Collection) {
- SaveCoin(collectionName, coin); // CAREFUL! This will not create a coin if it doesn't currently exist.
- }
+ foreach (var coin in
+ Collection)
+ SaveCoin(collectionName, coin); // CAREFUL! This will not create a coin if it doesn't currently exist.
}
-
+
///
- /// Creates a Coin from the information in a reader specifically from this database.
+ /// Creates a Coin from the information in a reader specifically from this database.
///
/// The reader to get the information from.
- private Coin CoinFromReader(SQLiteDataReader reader) {
+ private PcgsCoin CoinFromReader(SQLiteDataReader reader) {
// Create a coin while filtering out any possible null values - they throw exceptions.
- Coin coin = new Coin();
- if (!reader.IsDBNull(0)) coin.PCGSNo = reader.GetString(0);
- if (!reader.IsDBNull(1)) coin.Grade = reader.GetString(1);
- if (!reader.IsDBNull(2)) coin.Year = reader.GetInt32(2);
- if (!reader.IsDBNull(3)) coin.Denomination = reader.GetString(3);
- if (!reader.IsDBNull(4)) coin.MintMark = reader.GetString(4);
- if (!reader.IsDBNull(5)) coin.PriceGuideValue = reader.GetDouble(5);
- if (!reader.IsDBNull(6)) coin.CoinFactsLink = reader.GetString(6);
- if (!reader.IsDBNull(7)) coin.MajorVariety = reader.GetString(7);
- if (!reader.IsDBNull(8)) coin.MinorVariety = reader.GetString(8);
- if (!reader.IsDBNull(9)) coin.DieVariety = reader.GetString(9);
- if (!reader.IsDBNull(10)) coin.SeriesName = reader.GetString(10);
- if (!reader.IsDBNull(11)) coin.Category = reader.GetString(11);
- if (!reader.IsDBNull(12)) coin.Designation = reader.GetString(12);
- if (!reader.IsDBNull(13)) coin.CertificateNumber = reader.GetInt32(13);
- if (!reader.IsDBNull(14)) coin.Quantity = reader.GetInt32(14);
- if (!reader.IsDBNull(15)) coin.Notes = reader.GetString(15);
- coin.TotalPrice = coin.Quantity * coin.PriceGuideValue;
- return coin;
+ PcgsCoin pcgsCoin = new PcgsCoin();
+ if (!reader.IsDBNull(0)) pcgsCoin.PcgsNumber = reader.GetString(0);
+ if (!reader.IsDBNull(1)) pcgsCoin.Grade = reader.GetString(1);
+ if (!reader.IsDBNull(2)) pcgsCoin.Year = reader.GetInt32(2);
+ if (!reader.IsDBNull(3)) pcgsCoin.Denomination = reader.GetString(3);
+ if (!reader.IsDBNull(4)) pcgsCoin.MintMark = reader.GetString(4);
+ if (!reader.IsDBNull(5)) pcgsCoin.PriceGuideValue = reader.GetDouble(5);
+ if (!reader.IsDBNull(6)) pcgsCoin.CoinFactsLink = reader.GetString(6);
+ if (!reader.IsDBNull(7)) pcgsCoin.MajorVariety = reader.GetString(7);
+ if (!reader.IsDBNull(8)) pcgsCoin.MinorVariety = reader.GetString(8);
+ if (!reader.IsDBNull(9)) pcgsCoin.DieVariety = reader.GetString(9);
+ if (!reader.IsDBNull(10)) pcgsCoin.SeriesName = reader.GetString(10);
+ if (!reader.IsDBNull(11)) pcgsCoin.Category = reader.GetString(11);
+ if (!reader.IsDBNull(12)) pcgsCoin.Designation = reader.GetString(12);
+ if (!reader.IsDBNull(13)) pcgsCoin.CertificateNumber = reader.GetInt32(13);
+ if (!reader.IsDBNull(14)) pcgsCoin.Quantity = reader.GetInt32(14);
+ if (!reader.IsDBNull(15)) pcgsCoin.Notes = reader.GetString(15);
+ // pcgsCoin.TotalPrice = pcgsCoin.Quantity * pcgsCoin.PriceGuideValue;
+ return pcgsCoin;
}
-
+
///
- /// Deletes a Coin object from the database.
+ /// Deletes a Coin object from the database.
///
- /// The coin to delete.
- public void DeleteCoin(Coin delCoin) {
- SQLiteCommand cmd = Connection.CreateCommand();
+ /// The coin to delete.
+ public void DeleteCoin(PcgsCoin delPcgsCoin) {
+ var cmd = Connection.CreateCommand();
cmd.CommandText = "DELETE FROM CollectionTable WHERE PCGS_NUMBER = @PcgsNumber AND GRADE = @Grade";
- cmd.Parameters.AddWithValue("@PcgsNumber", delCoin.PCGSNo);
- cmd.Parameters.AddWithValue("@Grade", delCoin.Grade);
-
+ cmd.Parameters.AddWithValue("@PcgsNumber", delPcgsCoin.PcgsNumber);
+ cmd.Parameters.AddWithValue("@Grade", delPcgsCoin.Grade);
+
cmd.ExecuteNonQuery();
}
-
+
///
- /// Gets the grade from a string returned from the main window.
- /// These are always in a format similar to "MS-65", so we can just get the last two characters.
+ /// Gets the grade from a string returned from the main window.
+ /// These are always in a format similar to "MS-65", so we can just get the last two characters.
///
/// The grade string.
private int GetGradeFromString(string grade) {
@@ -443,4 +441,4 @@ public class CoinDatabase {
public class NotConnectedToDatabaseException : Exception {
public NotConnectedToDatabaseException() : base("Not connected to database.") { }
-}
+}
\ No newline at end of file
diff --git a/PcgsInvUi/ViewLocator.cs b/PcgsInvUi/ViewLocator.cs
index b80701a..2e041d8 100644
--- a/PcgsInvUi/ViewLocator.cs
+++ b/PcgsInvUi/ViewLocator.cs
@@ -10,9 +10,7 @@ public class ViewLocator : IDataTemplate {
var name = data.GetType().FullName!.Replace("ViewModel", "View");
var type = Type.GetType(name);
- if (type != null) {
- return (Control)Activator.CreateInstance(type)!;
- }
+ if (type != null) return (Control)Activator.CreateInstance(type)!;
return new TextBlock { Text = "Not Found: " + name };
}
diff --git a/PcgsInvUi/ViewModels/ApiKeyViewModel.cs b/PcgsInvUi/ViewModels/ApiKeyViewModel.cs
index 468b2dd..50048c8 100644
--- a/PcgsInvUi/ViewModels/ApiKeyViewModel.cs
+++ b/PcgsInvUi/ViewModels/ApiKeyViewModel.cs
@@ -1,30 +1,18 @@
-using ReactiveUI;
-using System.Reactive;
+using System.Diagnostics;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
namespace PcgsInvUi.ViewModels;
-public class ApiKeyViewModel : ViewModelBase {
- public string ApiKeyInput {
- get => _apiKeyInput;
- set => this.RaiseAndSetIfChanged(ref _apiKeyInput, value);
+public partial class ApiKeyViewModel : ViewModelBase {
+ [ObservableProperty]
+ public partial string ApiKeyInput { get; set; }
+
+ [ObservableProperty]
+ public partial bool OkEnabled { get; set; }
+
+ [RelayCommand]
+ public void OkCommand() {
+ Debug.WriteLine("Running OkCommand from ApiKeyViewModel");
}
- private string _apiKeyInput = "";
-
- public bool OkEnabled {
- get => _okEnabled;
- set => this.RaiseAndSetIfChanged(ref _okEnabled, value);
- }
- private bool _okEnabled;
-
- public ReactiveCommand OkCommand { get; }
-
- public ApiKeyViewModel() {
- var okEnabled = this.WhenAnyValue(
- x => x.ApiKeyInput,
- x => !string.IsNullOrWhiteSpace(x));
-
-
- // Get the API key from the user.
- OkCommand = ReactiveCommand.Create(() => ApiKeyInput, okEnabled);
- }
-}
+}
\ No newline at end of file
diff --git a/PcgsInvUi/ViewModels/CoinListViewModel.cs b/PcgsInvUi/ViewModels/CoinListViewModel.cs
index a8285fa..030a772 100644
--- a/PcgsInvUi/ViewModels/CoinListViewModel.cs
+++ b/PcgsInvUi/ViewModels/CoinListViewModel.cs
@@ -1,23 +1,20 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
-using PcgsInvUi.Models;
-using ReactiveUI;
+using CommunityToolkit.Mvvm.ComponentModel;
namespace PcgsInvUi.ViewModels;
-public class CoinListViewModel : ViewModelBase {
- public ObservableCollection CoinCollection { get; set; }
- private float _totalValue;
-
- public float TotalValue {
- get => _totalValue;
- set => this.RaiseAndSetIfChanged(ref _totalValue, value);
- }
-
- public Coin? SelectedCoin { get; set; }
-
- public CoinListViewModel(IEnumerable items) {
- CoinCollection = new ObservableCollection(items);
+public partial class CoinListViewModel : ViewModelBase {
+ public CoinListViewModel(IEnumerable items) {
+ CoinCollection = new ObservableCollection(items);
TotalValue = 0;
}
+
+ public ObservableCollection CoinCollection { get; set; }
+
+ [ObservableProperty]
+ public partial float TotalValue { get; set; }
+
+ [ObservableProperty]
+ public partial PcgsCoin? SelectedCoin { get; set; }
}
\ No newline at end of file
diff --git a/PcgsInvUi/ViewModels/DeleteWindowViewModel.cs b/PcgsInvUi/ViewModels/DeleteWindowViewModel.cs
index db4b132..f924e79 100644
--- a/PcgsInvUi/ViewModels/DeleteWindowViewModel.cs
+++ b/PcgsInvUi/ViewModels/DeleteWindowViewModel.cs
@@ -4,11 +4,11 @@ using ReactiveUI;
namespace PcgsInvUi.ViewModels;
public class DeleteWindowViewModel : ViewModelBase {
- public ReactiveCommand OkCommand { get; }
- public ReactiveCommand CancelCommand { get; }
-
public DeleteWindowViewModel() {
OkCommand = ReactiveCommand.Create(() => (object)true);
CancelCommand = ReactiveCommand.Create(() => (object)false);
}
-}
+
+ public ReactiveCommand OkCommand { get; }
+ public ReactiveCommand CancelCommand { get; }
+}
\ No newline at end of file
diff --git a/PcgsInvUi/ViewModels/EditViewModel.cs b/PcgsInvUi/ViewModels/EditViewModel.cs
index cf64977..8df81f2 100644
--- a/PcgsInvUi/ViewModels/EditViewModel.cs
+++ b/PcgsInvUi/ViewModels/EditViewModel.cs
@@ -1,27 +1,26 @@
using System.Reactive;
-using PcgsInvUi.Models;
using ReactiveUI;
namespace PcgsInvUi.ViewModels;
public class EditViewModel : ViewModelBase {
- public Coin CurrentCoin { get; set; }
-
- public ReactiveCommand OkCommand { get; }
-
- public EditViewModel(Coin coin) {
- CurrentCoin = coin;
+ public EditViewModel(PcgsCoin pcgsCoin) {
+ CurrentPcgsCoin = pcgsCoin;
var okEnabled = this.WhenAnyValue(
- x => x.CurrentCoin.PCGSNo,
- x => x.CurrentCoin.Grade,
- x => x.CurrentCoin.Quantity,
+ x => x.CurrentPcgsCoin.PcgsNumber,
+ x => x.CurrentPcgsCoin.Grade,
+ x => x.CurrentPcgsCoin.Quantity,
(id, grade, quantity) => !string.IsNullOrWhiteSpace(id) &&
!string.IsNullOrWhiteSpace(grade) &&
- (quantity != 0)
+ quantity != 0
);
// Setup OkCommand - all Coin-related properties must be non-whitespace.
OkCommand = ReactiveCommand.Create(() => { });
}
-}
+
+ public PcgsCoin CurrentPcgsCoin { get; set; }
+
+ public ReactiveCommand OkCommand { get; }
+}
\ No newline at end of file
diff --git a/PcgsInvUi/ViewModels/ErrorWindowViewModel.cs b/PcgsInvUi/ViewModels/ErrorWindowViewModel.cs
index 68ed391..885c42c 100644
--- a/PcgsInvUi/ViewModels/ErrorWindowViewModel.cs
+++ b/PcgsInvUi/ViewModels/ErrorWindowViewModel.cs
@@ -1,23 +1,22 @@
-using System.Reactive;
-using ReactiveUI;
+using Avalonia.Controls;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
-namespace PcgsInvUi.ViewModels;
+namespace PcgsInvUi.ViewModels;
-public class ErrorWindowViewModel : ViewModelBase {
+public partial class ErrorWindowViewModel : ViewModelBase {
+ private readonly Window _dialog;
- public string DisplayedMessage {
- get => _message;
- set => this.RaiseAndSetIfChanged(ref _message, value);
- }
- private string _message;
-
- public ReactiveCommand CloseCommand { get; }
-
- public ErrorWindowViewModel(string message)
- {
- _message = message;
-
- CloseCommand = ReactiveCommand.Create(() => (object)false);
+ public ErrorWindowViewModel(Window dialog, string message) {
+ _dialog = dialog;
+ Message = message;
}
-}
+ [ObservableProperty]
+ public partial string Message { get; set; }
+
+ [RelayCommand]
+ public void Close() {
+ _dialog.Close();
+ }
+}
\ No newline at end of file
diff --git a/PcgsInvUi/ViewModels/MainWindowViewModel.cs b/PcgsInvUi/ViewModels/MainWindowViewModel.cs
index 2291d54..74341ed 100644
--- a/PcgsInvUi/ViewModels/MainWindowViewModel.cs
+++ b/PcgsInvUi/ViewModels/MainWindowViewModel.cs
@@ -1,45 +1,19 @@
using System;
using System.Collections.ObjectModel;
using System.IO;
-using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
-using PcgsInvUi.Models;
+using System.Threading.Tasks;
+using CommunityToolkit.Mvvm.ComponentModel;
using PcgsInvUi.Services;
using ReactiveUI;
-using System.Threading.Tasks;
namespace PcgsInvUi.ViewModels;
-public class MainWindowViewModel : ViewModelBase {
- public ViewModelBase SidebarContent {
- get => _sideContent;
- private set => this.RaiseAndSetIfChanged(ref _sideContent, value);
- }
- public ObservableCollection DisplayedList { get; set; }
- public CoinDatabase ConnectedCoinDatabase { get; set; }
- public Coin? SelectedCoin {
- get => _selectedCoin;
- set => this.RaiseAndSetIfChanged(ref _selectedCoin, value);
- }
- public double TotalValue {
- get => _totalValue;
- set => this.RaiseAndSetIfChanged(ref _totalValue, value);
- }
-
- public ReactiveCommand DeleteCommand { get; }
- public Interaction ShowDeleteWindow { get; }
- public ReactiveCommand ExportCommand { get; }
- public Interaction ShowExportWindow { get; }
- public Interaction ShowErrorWindow { get; }
-
- private ViewModelBase _sideContent;
- private Coin? _selectedCoin;
- private double _totalValue;
-
+public partial class MainWindowViewModel : ViewModelBase {
public MainWindowViewModel(CoinDatabase coins) {
ConnectedCoinDatabase = coins;
- var keyFound = Task.Run(() => coins.TryInitApiClient()).Result;
+ var keyFound = Task.Run(coins.TryInitApiClient).Result;
Console.WriteLine("Function completed.");
var newViewModel = new NewViewModel();
var apiKeyViewModel = new ApiKeyViewModel();
@@ -48,21 +22,25 @@ public class MainWindowViewModel : ViewModelBase {
TotalValue = DisplayedList.Sum(x => x.TotalPrice);
// Setup interaction to show ApiKeyWindow
- apiKeyViewModel.OkCommand.Subscribe(async apiKey => {
+ apiKeyViewModel.OkCommandCommand.Subscribe(async apiKey => {
if (await ConnectedCoinDatabase.TryInitApiClient(apiKey))
- SidebarContent = newViewModel; // Must assign this to the observable property rather than private variable.
- });
+ SidebarContent =
+ newViewModel; // Must assign this to the observable property rather than private variable.
+ });
// Check if API key must be entered.
if (!keyFound) {
Console.WriteLine("API key must be entered by user.");
// Show the API key input view.
- _sideContent = apiKeyViewModel;
- } else _sideContent = newViewModel;
-
+ SidebarContent = apiKeyViewModel;
+ }
+ else {
+ SidebarContent = newViewModel;
+ }
+
// Set up the ability to show the error window.
ShowErrorWindow = new Interaction();
-
+
// Set up the ability to open the delete window.
ShowDeleteWindow = new Interaction();
var deleteEnabled = this.WhenAnyValue(x => x.SelectedCoin)
@@ -89,23 +67,25 @@ public class MainWindowViewModel : ViewModelBase {
// Something is wrong with the file after it's been created.
Console.WriteLine(e.Message);
await ShowErrorWindow.Handle(new ErrorWindowViewModel(e.Message));
- } catch (Exception e) {
+ }
+ catch (Exception e) {
Console.WriteLine(e.Message);
await ShowErrorWindow.Handle(new ErrorWindowViewModel(e.Message));
}
});
-
+
// Subscribe to SidebarContent.OkCommand, which is an IObservable<(int, string, int)>
// This is the same as the above, but with a different syntax.
newViewModel.OkCommand
.Subscribe(async requestStructure => {
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."));
+ await ShowErrorWindow.Handle(
+ new ErrorWindowViewModel("API key is invalid - authorization failed."));
break;
case PcgsClient.ErrorType.InvalidRequestFormat:
Console.WriteLine("Request format is invalid - showing window.");
@@ -113,14 +93,15 @@ public class MainWindowViewModel : ViewModelBase {
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."));
+ await ShowErrorWindow.Handle(
+ new ErrorWindowViewModel("No coin was found with the given parameters."));
break;
}
-
+
// Clear the text boxes.
newViewModel.ClearText();
});
-
+
// Update TotalValue anytime a coin's quantity changes.
// Possible null reference is currently ignored - SelectedCoin will never be null.
this.WhenAnyValue(x => x.SelectedCoin.TotalPrice)
@@ -132,10 +113,28 @@ public class MainWindowViewModel : ViewModelBase {
};
}
+ [ObservableProperty]
+ public partial ViewModelBase SidebarContent { get; private set; }
+
+ public ObservableCollection DisplayedList { get; set; }
+ public CoinDatabase ConnectedCoinDatabase { get; set; }
+
+ [ObservableProperty]
+ public partial PcgsCoin? SelectedCoin { get; set; }
+
+ [ObservableProperty]
+ public partial double TotalValue { get; set; }
+
+ public ReactiveCommand DeleteCommand { get; }
+ public Interaction ShowDeleteWindow { get; }
+ public ReactiveCommand ExportCommand { get; }
+ public Interaction ShowExportWindow { get; }
+ public Interaction ShowErrorWindow { get; }
+
// Create destructor to save the database when the application exits.
// This is necessary because the database is initialized in this class.
~MainWindowViewModel() {
Console.WriteLine("Running MainWindowViewModel destructor.");
ConnectedCoinDatabase.UpdateCollection("CollectionTable");
}
-}
+}
\ No newline at end of file
diff --git a/PcgsInvUi/ViewModels/NewViewModel.cs b/PcgsInvUi/ViewModels/NewViewModel.cs
index 3909324..5467e7f 100644
--- a/PcgsInvUi/ViewModels/NewViewModel.cs
+++ b/PcgsInvUi/ViewModels/NewViewModel.cs
@@ -1,31 +1,14 @@
-using System.Reactive;
-using System.Collections.Generic;
+using System.Collections.Generic;
+using System.Reactive;
using ReactiveUI;
namespace PcgsInvUi.ViewModels;
public class NewViewModel : ViewModelBase {
- private string _pcgsNumber = "";
private string _grade = "";
+ private string _pcgsNumber = "";
private string _quantity = "";
- public string PcgsNumber {
- get => _pcgsNumber;
- set => this.RaiseAndSetIfChanged(ref _pcgsNumber, value);
- }
-
- public string Grade {
- get => _grade;
- set => this.RaiseAndSetIfChanged(ref _grade, value);
- }
-
- public string Quantity {
- get => _quantity;
- set => this.RaiseAndSetIfChanged(ref _quantity, value);
- }
-
- public List GradesList { get; }
-
public NewViewModel() {
var okEnabled = this.WhenAnyValue(
x => x.PcgsNumber,
@@ -39,9 +22,7 @@ public class NewViewModel : ViewModelBase {
() => (int.Parse(PcgsNumber), Grade, int.Parse(Quantity)),
okEnabled);
- ClearCommand = ReactiveCommand.Create(() => {
- ClearText();
- });
+ ClearCommand = ReactiveCommand.Create(() => { ClearText(); });
// Initialize grade values for use in the view.
// This must be typed out manually, as there is no way to get a list of grades from the API.
@@ -79,15 +60,32 @@ public class NewViewModel : ViewModelBase {
};
}
+ public string PcgsNumber {
+ get => _pcgsNumber;
+ set => this.RaiseAndSetIfChanged(ref _pcgsNumber, value);
+ }
+
+ public string Grade {
+ get => _grade;
+ set => this.RaiseAndSetIfChanged(ref _grade, value);
+ }
+
+ public string Quantity {
+ get => _quantity;
+ set => this.RaiseAndSetIfChanged(ref _quantity, value);
+ }
+
+ public List GradesList { get; }
+
public ReactiveCommand OkCommand { get; }
public ReactiveCommand ClearCommand { get; }
///
- /// Clears the text fields.
+ /// Clears the text fields.
///
public void ClearText() {
PcgsNumber = "";
Grade = "";
Quantity = "";
}
-}
+}
\ No newline at end of file
diff --git a/PcgsInvUi/ViewModels/ViewModelBase.cs b/PcgsInvUi/ViewModels/ViewModelBase.cs
index 03a9024..8df3a4e 100644
--- a/PcgsInvUi/ViewModels/ViewModelBase.cs
+++ b/PcgsInvUi/ViewModels/ViewModelBase.cs
@@ -1,5 +1,5 @@
-using ReactiveUI;
+using CommunityToolkit.Mvvm.ComponentModel;
namespace PcgsInvUi.ViewModels;
-public class ViewModelBase : ReactiveObject { }
\ No newline at end of file
+public class ViewModelBase : ObservableObject { }
\ No newline at end of file
diff --git a/PcgsInvUi/Views/ApiKeyView.axaml b/PcgsInvUi/Views/ApiKeyView.axaml
index e125862..6c2bf46 100644
--- a/PcgsInvUi/Views/ApiKeyView.axaml
+++ b/PcgsInvUi/Views/ApiKeyView.axaml
@@ -1,14 +1,14 @@
+ 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.ApiKeyView" x:DataType="viewModels:ApiKeyViewModel">
-
+
-
+
\ No newline at end of file
diff --git a/PcgsInvUi/Views/ApiKeyView.axaml.cs b/PcgsInvUi/Views/ApiKeyView.axaml.cs
index 74d877c..33f2fb9 100644
--- a/PcgsInvUi/Views/ApiKeyView.axaml.cs
+++ b/PcgsInvUi/Views/ApiKeyView.axaml.cs
@@ -1,9 +1,9 @@
using Avalonia.Controls;
-namespace PcgsInvUi.Views;
+namespace PcgsInvUi.Views;
public partial class ApiKeyView : UserControl {
public ApiKeyView() {
InitializeComponent();
}
-}
+}
\ No newline at end of file
diff --git a/PcgsInvUi/Views/DeleteWindow.axaml b/PcgsInvUi/Views/DeleteWindow.axaml
index b9dabdf..06cd6fa 100644
--- a/PcgsInvUi/Views/DeleteWindow.axaml
+++ b/PcgsInvUi/Views/DeleteWindow.axaml
@@ -21,4 +21,4 @@
HorizontalContentAlignment="Center" IsEnabled="True"
Content="No" Command="{Binding CancelCommand}" />
-
+
\ No newline at end of file
diff --git a/PcgsInvUi/Views/DeleteWindow.axaml.cs b/PcgsInvUi/Views/DeleteWindow.axaml.cs
index 000f574..ca7cd2c 100644
--- a/PcgsInvUi/Views/DeleteWindow.axaml.cs
+++ b/PcgsInvUi/Views/DeleteWindow.axaml.cs
@@ -1,7 +1,7 @@
-using PcgsInvUi.ViewModels;
+using System;
using Avalonia.ReactiveUI;
+using PcgsInvUi.ViewModels;
using ReactiveUI;
-using System;
namespace PcgsInvUi.Views;
@@ -11,4 +11,4 @@ public partial class DeleteWindow : ReactiveWindow {
this.WhenActivated(d => d(ViewModel!.OkCommand.Subscribe(Close)));
this.WhenActivated(d => d(ViewModel!.CancelCommand.Subscribe(Close)));
}
-}
+}
\ No newline at end of file
diff --git a/PcgsInvUi/Views/ErrorWindow.axaml b/PcgsInvUi/Views/ErrorWindow.axaml
index d238b59..3217996 100644
--- a/PcgsInvUi/Views/ErrorWindow.axaml
+++ b/PcgsInvUi/Views/ErrorWindow.axaml
@@ -5,14 +5,14 @@
xmlns:viewModels="clr-namespace:PcgsInvUi.ViewModels"
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="150"
x:Class="PcgsInvUi.Views.ErrorWindow" x:DataType="viewModels:ErrorWindowViewModel"
- Title="Error!" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterOwner"
- x:Name="NameErrorWindow" CanResize="False" >
+ Title="Error!" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterOwner"
+ x:Name="NameErrorWindow" CanResize="False">
+ Content="{Binding Message}" />
-
+
\ No newline at end of file
diff --git a/PcgsInvUi/Views/ErrorWindow.axaml.cs b/PcgsInvUi/Views/ErrorWindow.axaml.cs
index 5044ecd..c5ea379 100644
--- a/PcgsInvUi/Views/ErrorWindow.axaml.cs
+++ b/PcgsInvUi/Views/ErrorWindow.axaml.cs
@@ -1,14 +1,11 @@
-using System;
using Avalonia.ReactiveUI;
using PcgsInvUi.ViewModels;
-using ReactiveUI;
-namespace PcgsInvUi.Views;
+namespace PcgsInvUi.Views;
public partial class ErrorWindow : ReactiveWindow {
- public ErrorWindow()
- {
+ public ErrorWindow() {
InitializeComponent();
this.WhenActivated(d => d(ViewModel!.CloseCommand.Subscribe(Close)));
}
-}
+}
\ No newline at end of file
diff --git a/PcgsInvUi/Views/FindWindow.axaml.cs b/PcgsInvUi/Views/FindWindow.axaml.cs
index 58fd70e..9386827 100644
--- a/PcgsInvUi/Views/FindWindow.axaml.cs
+++ b/PcgsInvUi/Views/FindWindow.axaml.cs
@@ -1,7 +1,7 @@
-using Avalonia.ReactiveUI;
+using System;
+using Avalonia.ReactiveUI;
using PcgsInvUi.ViewModels;
using ReactiveUI;
-using System;
namespace PcgsInvUi.Views;
diff --git a/PcgsInvUi/Views/MainWindow.axaml b/PcgsInvUi/Views/MainWindow.axaml
index 517fede..a3b6ee3 100644
--- a/PcgsInvUi/Views/MainWindow.axaml
+++ b/PcgsInvUi/Views/MainWindow.axaml
@@ -5,7 +5,7 @@
xmlns:viewModels="clr-namespace:PcgsInvUi.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="PcgsInvUi.Views.MainWindow" x:DataType="viewModels:MainWindowViewModel"
- Title="Main Window" WindowStartupLocation="CenterScreen" WindowState="Maximized" >
+ Title="Main Window" WindowStartupLocation="CenterScreen" WindowState="Maximized">
@@ -15,7 +15,7 @@
Content="{Binding SidebarContent}" />
+ IsReadOnly="False" TextWrapping="Wrap" />
@@ -51,7 +51,7 @@
Binding="{Binding PriceGuideValue, StringFormat='${0:0.00}'}"
IsReadOnly="True" />
-
+
\ No newline at end of file
diff --git a/PcgsInvUi/Views/MainWindow.axaml.cs b/PcgsInvUi/Views/MainWindow.axaml.cs
index be6ccd3..cc1c44c 100644
--- a/PcgsInvUi/Views/MainWindow.axaml.cs
+++ b/PcgsInvUi/Views/MainWindow.axaml.cs
@@ -44,15 +44,13 @@ public partial class MainWindow : ReactiveWindow {
SuggestedStartLocation = await StorageProvider.TryGetWellKnownFolderAsync(WellKnownFolder.Documents)
});
- if (file is not null) {
+ if (file is not null)
interationContext.SetOutput(file.Path);
- }
- else {
+ else
// TODO Handle user closing the dialog.
throw new Exception("User cancelled the file picker.");
- }
}
-
+
private async Task ShowErrorWindowAsync(InteractionContext interaction) {
var window = new ErrorWindow();
window.DataContext = interaction.Input;
@@ -60,4 +58,4 @@ public partial class MainWindow : ReactiveWindow {
var result = await window.ShowDialog(this);
interaction.SetOutput(result);
}
-}
+}
\ No newline at end of file
diff --git a/PcgsInvUi/Views/MainWindowRewrite.axaml b/PcgsInvUi/Views/MainWindowRewrite.axaml
new file mode 100644
index 0000000..2c6610f
--- /dev/null
+++ b/PcgsInvUi/Views/MainWindowRewrite.axaml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PcgsInvUi/Views/MainWindowRewrite.axaml.cs b/PcgsInvUi/Views/MainWindowRewrite.axaml.cs
new file mode 100644
index 0000000..d3e2183
--- /dev/null
+++ b/PcgsInvUi/Views/MainWindowRewrite.axaml.cs
@@ -0,0 +1,9 @@
+using Avalonia.Controls;
+
+namespace PcgsInvUi.Views;
+
+public partial class MainWindowRewrite : Window {
+ public MainWindowRewrite() {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/PcgsInvUi/Views/NewView.axaml.cs b/PcgsInvUi/Views/NewView.axaml.cs
index 905418a..7ea982d 100644
--- a/PcgsInvUi/Views/NewView.axaml.cs
+++ b/PcgsInvUi/Views/NewView.axaml.cs
@@ -6,4 +6,4 @@ public partial class NewView : UserControl {
public NewView() {
InitializeComponent();
}
-}
+}
\ No newline at end of file
diff --git a/pcgs-inv.sln b/pcgs-inv.sln
index a9bd7b2..fd4c9d0 100644
--- a/pcgs-inv.sln
+++ b/pcgs-inv.sln
@@ -2,6 +2,10 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PcgsInvUi", "PcgsInvUi\PcgsInvUi.csproj", "{887D7BD0-3E71-435D-82CD-3DAF3187D056}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PcgsInv", "PcgsInv\PcgsInv.csproj", "{8B62E70B-9F3C-4E1B-9E7D-FBADC680E5D0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PcgsApi", "PcgsApi\PcgsApi.csproj", "{08B02A6D-EEA5-4335-AC5B-B1347CEBBE88}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -13,5 +17,13 @@ Global
{887D7BD0-3E71-435D-82CD-3DAF3187D056}.Release|Any CPU.ActiveCfg = Release|Any CPU
{887D7BD0-3E71-435D-82CD-3DAF3187D056}.Release|Any CPU.Build.0 = Release|Any CPU
{887D7BD0-3E71-435D-82CD-3DAF3187D056}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {8B62E70B-9F3C-4E1B-9E7D-FBADC680E5D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8B62E70B-9F3C-4E1B-9E7D-FBADC680E5D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8B62E70B-9F3C-4E1B-9E7D-FBADC680E5D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8B62E70B-9F3C-4E1B-9E7D-FBADC680E5D0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {08B02A6D-EEA5-4335-AC5B-B1347CEBBE88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {08B02A6D-EEA5-4335-AC5B-B1347CEBBE88}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {08B02A6D-EEA5-4335-AC5B-B1347CEBBE88}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {08B02A6D-EEA5-4335-AC5B-B1347CEBBE88}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal