diff --git a/PcgsInvUi/App.axaml b/PcgsInvUi/App.axaml index 14b1cc2..9c6bf98 100644 --- a/PcgsInvUi/App.axaml +++ b/PcgsInvUi/App.axaml @@ -3,12 +3,12 @@ x:Class="PcgsInvUi.App" xmlns:local="using:PcgsInvUi" RequestedThemeVariant="Light"> - + - + - + diff --git a/PcgsInvUi/App.axaml.cs b/PcgsInvUi/App.axaml.cs index b4c71cb..5a54503 100644 --- a/PcgsInvUi/App.axaml.cs +++ b/PcgsInvUi/App.axaml.cs @@ -7,23 +7,18 @@ using PcgsInvUi.Views; namespace PcgsInvUi; -public partial class App : Application -{ - public override void Initialize() - { +public partial class App : Application { + public override void Initialize() { AvaloniaXamlLoader.Load(this); } - public override void OnFrameworkInitializationCompleted() - { + public override void OnFrameworkInitializationCompleted() { base.OnFrameworkInitializationCompleted(); - - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) - { + + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { var coins = new Services.CoinCollection(); - - desktop.MainWindow = new MainWindow - { + + desktop.MainWindow = new MainWindow { DataContext = new MainWindowViewModel(coins), }; } diff --git a/PcgsInvUi/Models/Coin.cs b/PcgsInvUi/Models/Coin.cs index a275fcd..ee6ebe6 100644 --- a/PcgsInvUi/Models/Coin.cs +++ b/PcgsInvUi/Models/Coin.cs @@ -3,55 +3,52 @@ using ReactiveUI; namespace PcgsInvUi.Models; -public class Coin : ReactiveObject -{ - public string PCGSNo - { +public class Coin : ReactiveObject { + public string PCGSNo { get => _pcgsNo; set => this.RaiseAndSetIfChanged(ref _pcgsNo, value); } + private string _pcgsNo; - public string Name - { + public string Name { get => _name; set => this.RaiseAndSetIfChanged(ref _name, value); } + private string _name; - public int Year - { + public int Year { get => _year; set => this.RaiseAndSetIfChanged(ref _year, value); } + private int _year; - public string Denomination - { + public string Denomination { get => _denomination; set => this.RaiseAndSetIfChanged(ref _denomination, value); } + private string _denomination; - public string MintMark - { + public string MintMark { get => _mintMark; set => this.RaiseAndSetIfChanged(ref _mintMark, value); } + private string _mintMark; - public string Grade - { + public string Grade { get => _grade; set => this.RaiseAndSetIfChanged(ref _grade, value); } + private string _grade; - public double PriceGuideValue - { + public double PriceGuideValue { get => _priceGuideValue; - set - { + set { TotalPrice = value * Quantity; this.RaiseAndSetIfChanged(ref _priceGuideValue, value); } @@ -59,67 +56,65 @@ public class Coin : ReactiveObject private double _priceGuideValue; - public string CoinFactsLink - { + public string CoinFactsLink { get => _coinFactsLink; set => this.RaiseAndSetIfChanged(ref _coinFactsLink, value); } + private string _coinFactsLink; - public string MajorVariety - { + public string MajorVariety { get => _majorVariety; set => this.RaiseAndSetIfChanged(ref _majorVariety, value); } + private string _majorVariety; - public string MinorVariety - { + public string MinorVariety { get => _minorVariety; set => this.RaiseAndSetIfChanged(ref _minorVariety, value); } + private string _minorVariety; - public string DieVariety - { + public string DieVariety { get => _dieVariety; set => this.RaiseAndSetIfChanged(ref _dieVariety, value); } + private string _dieVariety; - public string SeriesName - { + public string SeriesName { get => _seriesName; set => this.RaiseAndSetIfChanged(ref _seriesName, value); } + private string _seriesName; - public string Category - { + public string Category { get => _category; set => this.RaiseAndSetIfChanged(ref _category, value); } + private string _category; - public string Designation - { + public string Designation { get => _designation; set => this.RaiseAndSetIfChanged(ref _designation, value); } + private string _designation; - public int CertificateNumber - { + public int CertificateNumber { get => _certificateNumber; set => this.RaiseAndSetIfChanged(ref _certificateNumber, value); } + private int _certificateNumber; - public int Quantity - { + public int Quantity { get => _quantity; - set - { + set { TotalPrice = value * PriceGuideValue; this.RaiseAndSetIfChanged(ref _quantity, value); } @@ -127,29 +122,28 @@ public class Coin : ReactiveObject private int _quantity; - public double TotalPrice - { + public double TotalPrice { get => _totalPrice; set => this.RaiseAndSetIfChanged(ref _totalPrice, value); } + private double _totalPrice; - public double PaidFor - { + public double PaidFor { get => _paidFor; set => this.RaiseAndSetIfChanged(ref _paidFor, value); } + private double _paidFor; - public string Notes - { + public string Notes { get => _notes; set => this.RaiseAndSetIfChanged(ref _notes, value); } + private string _notes; - - public Coin() - { + + public Coin() { PCGSNo = ""; Name = ""; Year = 0; @@ -168,7 +162,5 @@ public class Coin : ReactiveObject Quantity = 0; PaidFor = 0; Notes = ""; - - } } \ No newline at end of file diff --git a/PcgsInvUi/PcgsInvUi.csproj b/PcgsInvUi/PcgsInvUi.csproj index e47733f..a1ce9f5 100644 --- a/PcgsInvUi/PcgsInvUi.csproj +++ b/PcgsInvUi/PcgsInvUi.csproj @@ -1,85 +1,86 @@  - - WinExe - net6.0 - enable - true - app.manifest - true - + + WinExe + net6.0 + enable + true + app.manifest + true + - - - - + + + + - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - + + + - - - + + + - - - + + + - - - + + + diff --git a/PcgsInvUi/Program.cs b/PcgsInvUi/Program.cs index 177ca67..e1f58b0 100644 --- a/PcgsInvUi/Program.cs +++ b/PcgsInvUi/Program.cs @@ -4,8 +4,7 @@ using System; namespace PcgsInvUi; -class Program -{ +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. @@ -20,4 +19,4 @@ class Program .WithInterFont() .LogToTrace() .UseReactiveUI(); -} +} \ No newline at end of file diff --git a/PcgsInvUi/Services/CoinCollection.cs b/PcgsInvUi/Services/CoinCollection.cs index 7852adf..dc89845 100644 --- a/PcgsInvUi/Services/CoinCollection.cs +++ b/PcgsInvUi/Services/CoinCollection.cs @@ -3,10 +3,8 @@ using PcgsInvUi.Models; namespace PcgsInvUi.Services; -public class CoinCollection -{ - public IEnumerable GetItems() => new[] - { +public class CoinCollection { + public IEnumerable GetItems() => new[] { new Coin(), new Coin(), new Coin(), diff --git a/PcgsInvUi/Services/Database.cs b/PcgsInvUi/Services/Database.cs index 9dc4a04..9b8bc19 100644 --- a/PcgsInvUi/Services/Database.cs +++ b/PcgsInvUi/Services/Database.cs @@ -1,6 +1,5 @@ namespace PcgsInvUi.Services; -public class Database -{ - // TODO Create a database using SQLite. +public class Database { + public Database() { } } \ No newline at end of file diff --git a/PcgsInvUi/Services/PcgsClient.cs b/PcgsInvUi/Services/PcgsClient.cs index aece00c..791f3fe 100644 --- a/PcgsInvUi/Services/PcgsClient.cs +++ b/PcgsInvUi/Services/PcgsClient.cs @@ -4,31 +4,26 @@ using System.Net.Http.Headers; using System.Threading.Tasks; // using Newtonsoft.Json; using PcgsInvUi.Models; - using System.Text.Json; using System.Text.Json.Serialization; namespace PcgsInvUi.Services; -public class PcgsClient -{ +public class PcgsClient { private string _apiUri = "https://api.pcgs.com/publicapi"; private readonly string _apiKey; - public PcgsClient(string apiKey) - { + public PcgsClient(string apiKey) { // _apiKey = apiKey; _apiKey = "E8xivTVN_k4Q8ubk8Xv_uU11U91WX0wDht4S4m4BAf2HPmKnGrZ0J2f9nccM7Ns1VkGoT1SXYR74I7aNaMKqXlJGEy3oobseKV0nGiqu1IKvFkOTVjhV37SWUVExSDFMC6FLzs7xJQIHwkcxr5JFOQNmc4ZytEh_-hmCN3NL-z0fEk98tzBmPJ_F7bq_xNru86QMD2A9yalu_dWe-lCysfyE2bCA2EDqwvWenRYf-0XnNtp6qlxxCMlCd-TDqqRKLC3qefCwpXSemwBiNSP5gbC9pwcKrZugkruuJ0nyxxThZymm"; } - public async Task GetCoinFactsByGrade(int pcgsNumber, string grade, bool plusGrade = false) - { + public async Task GetCoinFactsByGrade(int pcgsNumber, string grade, bool plusGrade = false) { Coin newCoin = null; - using (HttpClient client = new HttpClient()) - { + using (HttpClient client = new HttpClient()) { var gradeParam = GetGradeFromString(grade); - + string requestUri = $"{_apiUri}/coindetail/GetCoinFactsByGrade/?PCGSNo={pcgsNumber}&GradeNo={gradeParam}&PlusGrade={plusGrade}"; client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", _apiKey); @@ -36,14 +31,12 @@ public class PcgsClient HttpResponseMessage response = await client.GetAsync(requestUri); Console.WriteLine("Got response."); - if (response.IsSuccessStatusCode) - { + if (response.IsSuccessStatusCode) { string jsonResponse = await response.Content.ReadAsStringAsync(); newCoin = ParseJsonResponse(jsonResponse); Console.WriteLine("Coin created."); } - else - { + else { Console.WriteLine($"Error: {response.StatusCode} - {response.ReasonPhrase}"); } } @@ -51,24 +44,22 @@ public class PcgsClient return newCoin; } - private int GetGradeFromString(string grade) - { + private int GetGradeFromString(string grade) { var actualGrade = int.Parse(grade.Substring(grade.Length - 2)); Console.WriteLine($"Grade is {actualGrade}"); return actualGrade; } - + // TODO Will eventually create the other methods that are included in the Public API. - - private Coin ParseJsonResponse(string json) - { + + private Coin ParseJsonResponse(string json) { Console.WriteLine(json); Coin newCoin = JsonSerializer.Deserialize(json); Console.WriteLine($"New Coin has pcgs number {newCoin.PCGSNo}"); string test = JsonSerializer.Serialize(newCoin); Console.WriteLine(test); - + return newCoin; } } \ No newline at end of file diff --git a/PcgsInvUi/ViewLocator.cs b/PcgsInvUi/ViewLocator.cs index 8ee75d9..b80701a 100644 --- a/PcgsInvUi/ViewLocator.cs +++ b/PcgsInvUi/ViewLocator.cs @@ -5,23 +5,19 @@ using PcgsInvUi.ViewModels; namespace PcgsInvUi; -public class ViewLocator : IDataTemplate -{ - public Control Build(object data) - { +public class ViewLocator : IDataTemplate { + public Control Build(object data) { var name = data.GetType().FullName!.Replace("ViewModel", "View"); var type = Type.GetType(name); - if (type != null) - { + if (type != null) { return (Control)Activator.CreateInstance(type)!; } - + return new TextBlock { Text = "Not Found: " + name }; } - public bool Match(object data) - { + public bool Match(object data) { return data is ViewModelBase; } } \ No newline at end of file diff --git a/PcgsInvUi/ViewModels/CoinListViewModel.cs b/PcgsInvUi/ViewModels/CoinListViewModel.cs index 19fb367..a8285fa 100644 --- a/PcgsInvUi/ViewModels/CoinListViewModel.cs +++ b/PcgsInvUi/ViewModels/CoinListViewModel.cs @@ -5,19 +5,18 @@ using ReactiveUI; namespace PcgsInvUi.ViewModels; -public class CoinListViewModel : ViewModelBase -{ +public class CoinListViewModel : ViewModelBase { public ObservableCollection CoinCollection { get; set; } private float _totalValue; - public float TotalValue - { + + public float TotalValue { get => _totalValue; set => this.RaiseAndSetIfChanged(ref _totalValue, value); } + public Coin? SelectedCoin { get; set; } - - public CoinListViewModel(IEnumerable items) - { + + public CoinListViewModel(IEnumerable items) { CoinCollection = new ObservableCollection(items); TotalValue = 0; } diff --git a/PcgsInvUi/ViewModels/DeleteWindowViewModel.cs b/PcgsInvUi/ViewModels/DeleteWindowViewModel.cs index 409a067..54623cf 100644 --- a/PcgsInvUi/ViewModels/DeleteWindowViewModel.cs +++ b/PcgsInvUi/ViewModels/DeleteWindowViewModel.cs @@ -4,14 +4,12 @@ using ReactiveUI; namespace PcgsInvUi.ViewModels; -public class DeleteWindowViewModel : ViewModelBase -{ +public class DeleteWindowViewModel : ViewModelBase { public ReactiveCommand OkCommand { get; } public ReactiveCommand CancelCommand { get; } - public DeleteWindowViewModel() - { - OkCommand = ReactiveCommand.Create(() => (object)true); + public DeleteWindowViewModel() { + OkCommand = ReactiveCommand.Create(() => (object)true); CancelCommand = ReactiveCommand.Create(window => window.Close()); } } \ No newline at end of file diff --git a/PcgsInvUi/ViewModels/EditViewModel.cs b/PcgsInvUi/ViewModels/EditViewModel.cs index 836e354..3572169 100644 --- a/PcgsInvUi/ViewModels/EditViewModel.cs +++ b/PcgsInvUi/ViewModels/EditViewModel.cs @@ -5,14 +5,12 @@ using ReactiveUI; namespace PcgsInvUi.ViewModels; -public class EditViewModel : ViewModelBase -{ +public class EditViewModel : ViewModelBase { public Coin CurrentCoin { get; set; } - + public ReactiveCommand OkCommand { get; } - public EditViewModel(Coin coin) - { + public EditViewModel(Coin coin) { CurrentCoin = coin; var okEnabled = this.WhenAnyValue( @@ -23,7 +21,7 @@ public class EditViewModel : ViewModelBase !string.IsNullOrWhiteSpace(grade) && (quantity != 0) ); - + // Setup OkCommand - all Coin-related properties must be non-whitespace. OkCommand = ReactiveCommand.Create(() => { }); } diff --git a/PcgsInvUi/ViewModels/FindWindowViewModel.cs b/PcgsInvUi/ViewModels/FindWindowViewModel.cs index f3551de..6e7b70f 100644 --- a/PcgsInvUi/ViewModels/FindWindowViewModel.cs +++ b/PcgsInvUi/ViewModels/FindWindowViewModel.cs @@ -3,7 +3,6 @@ using ReactiveUI; namespace PcgsInvUi.ViewModels; -public class FindWindowViewModel : ViewModelBase -{ +public class FindWindowViewModel : ViewModelBase { public ReactiveCommand OkCommand { get; } = ReactiveCommand.Create(() => (object)1); } \ No newline at end of file diff --git a/PcgsInvUi/ViewModels/MainWindowViewModel.cs b/PcgsInvUi/ViewModels/MainWindowViewModel.cs index 39b1b7b..121f328 100644 --- a/PcgsInvUi/ViewModels/MainWindowViewModel.cs +++ b/PcgsInvUi/ViewModels/MainWindowViewModel.cs @@ -19,80 +19,78 @@ namespace PcgsInvUi.ViewModels; // TODO API request tracker (1000 per day) // TODO API update schedules (per month? manual override? needs to store a date of last update in the coin object) -public class MainWindowViewModel : ViewModelBase -{ - public ViewModelBase SidebarContent - { +public class MainWindowViewModel : ViewModelBase { + public ViewModelBase SidebarContent { get => _sideContent; private set => this.RaiseAndSetIfChanged(ref _sideContent, value); } + public ObservableCollection CoinCollection { get; set; } public ObservableCollection DisplayedList { get; set; } - public Coin? SelectedCoin - { + + public Coin? SelectedCoin { get => _selectedCoin; set => this.RaiseAndSetIfChanged(ref _selectedCoin, value); } - public double TotalValue - { + + public double TotalValue { get => _totalValue; set => this.RaiseAndSetIfChanged(ref _totalValue, value); } + public ReactiveCommand DeleteCommand { get; } public Interaction ShowDeleteWindow { get; } public ReactiveCommand FindCommand { get; } public Interaction ShowFindWindow { get; } - + private ViewModelBase _sideContent; private Coin? _selectedCoin; private double _totalValue; private PcgsClient _pcgsClient; - public MainWindowViewModel(CoinCollection coins) - { + public MainWindowViewModel(CoinCollection coins) { var newViewModel = new NewViewModel(); _sideContent = newViewModel; DisplayedList = CoinCollection = new ObservableCollection(coins.GetItems()); - _pcgsClient = new PcgsClient("eAb8gS0I2XAvT_5gJeiGJaglMia1Tk-oB4kJUK6kuafyrny_S61vIJY-Ikl4nCQM67wrdxzUqLVWTV2kBSxD3d5XNBHxHnYBhcSS6dOPug0hZaF3qAv56df3gYSzOGh9Tif5y0eP3Iw0LrqKDr1Hj-dk6SV6GKog2IIqCPQhhHH8FMTWBTYO-_O8cx7qLdM5GM8KlTsic6g3VRUhM8EA_4OO04dCfmNLGhqINRl3jGZ0Q4ziI8fng2bVWsIyteqiPzUn10rIQ3-OPpqVZG_DxeOmOejj4GzbUNyqUOajy-nr5rYY"); - + _pcgsClient = new PcgsClient( + "eAb8gS0I2XAvT_5gJeiGJaglMia1Tk-oB4kJUK6kuafyrny_S61vIJY-Ikl4nCQM67wrdxzUqLVWTV2kBSxD3d5XNBHxHnYBhcSS6dOPug0hZaF3qAv56df3gYSzOGh9Tif5y0eP3Iw0LrqKDr1Hj-dk6SV6GKog2IIqCPQhhHH8FMTWBTYO-_O8cx7qLdM5GM8KlTsic6g3VRUhM8EA_4OO04dCfmNLGhqINRl3jGZ0Q4ziI8fng2bVWsIyteqiPzUn10rIQ3-OPpqVZG_DxeOmOejj4GzbUNyqUOajy-nr5rYY"); + // Set up the ability to open the delete window. ShowDeleteWindow = new Interaction(); var deleteEnabled = this.WhenAnyValue(x => x.SelectedCoin) .Select(x => x != null); - DeleteCommand = ReactiveCommand.CreateFromTask(async () => - { + DeleteCommand = ReactiveCommand.CreateFromTask(async () => { var deleteViewModel = new DeleteWindowViewModel(); var result = await ShowDeleteWindow.Handle(deleteViewModel); - if (result) CoinCollection.Remove(SelectedCoin); // possible null deref - ignored due to button being disabled. + if (result) + CoinCollection.Remove(SelectedCoin); // possible null deref - ignored due to button being disabled. }, deleteEnabled); // Set up the ability to open the find window. ShowFindWindow = new Interaction(); var findEnabled = this.WhenAnyValue(x => x.CoinCollection.Count, x => x > 0); - FindCommand = ReactiveCommand.CreateFromTask(async () => - { + FindCommand = ReactiveCommand.CreateFromTask(async () => { var findViewModel = new FindWindowViewModel(); var result = await ShowFindWindow.Handle(findViewModel); // Find the coin with the matching ID. The issue is that there could be multiple - so we need to return a list. // Perhaps a secondary viewmodel? return new Coin(); }, findEnabled); - + // 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 => - { + .Subscribe(async requestStructure => { var newCoin = await _pcgsClient.GetCoinFactsByGrade(requestStructure.Item1, requestStructure.Item2); newCoin.Quantity = requestStructure.Item3; CoinCollection.Add(newCoin); TotalValue += newCoin.Quantity * newCoin.PriceGuideValue; }); - + // Change TotalValue anytime SelectedCoin.TotalPrice changes. // Possible null deref - ignored due to null values summing to 0. this.WhenAnyValue(x => x.SelectedCoin.TotalPrice) - .Subscribe(_ => TotalValue = CoinCollection.Sum(x => x.TotalPrice) ); + .Subscribe(_ => TotalValue = CoinCollection.Sum(x => x.TotalPrice)); } -} +} \ No newline at end of file diff --git a/PcgsInvUi/ViewModels/NewViewModel.cs b/PcgsInvUi/ViewModels/NewViewModel.cs index 5bacdac..dca166d 100644 --- a/PcgsInvUi/ViewModels/NewViewModel.cs +++ b/PcgsInvUi/ViewModels/NewViewModel.cs @@ -4,31 +4,29 @@ using ReactiveUI; namespace PcgsInvUi.ViewModels; -public class NewViewModel : ViewModelBase -{ +public class NewViewModel : ViewModelBase { private string _pcgsNumber = ""; private string _grade = ""; private string _quantity = ""; - - public string PcgsNumber - { + + public string PcgsNumber { get => _pcgsNumber; set => this.RaiseAndSetIfChanged(ref _pcgsNumber, value); } - public string Grade - { + + public string Grade { get => _grade; set => this.RaiseAndSetIfChanged(ref _grade, value); } - public string Quantity - { + + public string Quantity { get => _quantity; set => this.RaiseAndSetIfChanged(ref _quantity, value); } + public List GradesList { get; } - public NewViewModel() - { + public NewViewModel() { var okEnabled = this.WhenAnyValue( x => x.PcgsNumber, x => x.Grade, @@ -40,9 +38,8 @@ public class NewViewModel : ViewModelBase OkCommand = ReactiveCommand.Create( () => (int.Parse(PcgsNumber), Grade, int.Parse(Quantity)), okEnabled); - - ClearCommand = ReactiveCommand.Create(() => - { + + ClearCommand = ReactiveCommand.Create(() => { PcgsNumber = ""; Grade = ""; Quantity = ""; @@ -50,8 +47,7 @@ public class NewViewModel : ViewModelBase // 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. - GradesList = new List - { + GradesList = new List { "P-01", "FR-02", "AG-03", @@ -84,8 +80,7 @@ public class NewViewModel : ViewModelBase "MS-70" }; } - + public ReactiveCommand OkCommand { get; } public ReactiveCommand ClearCommand { get; } - } \ No newline at end of file diff --git a/PcgsInvUi/ViewModels/ViewModelBase.cs b/PcgsInvUi/ViewModels/ViewModelBase.cs index 6ea13e7..03a9024 100644 --- a/PcgsInvUi/ViewModels/ViewModelBase.cs +++ b/PcgsInvUi/ViewModels/ViewModelBase.cs @@ -2,6 +2,4 @@ namespace PcgsInvUi.ViewModels; -public class ViewModelBase : ReactiveObject -{ -} +public class ViewModelBase : ReactiveObject { } \ No newline at end of file diff --git a/PcgsInvUi/Views/DeleteWindow.axaml b/PcgsInvUi/Views/DeleteWindow.axaml index 9571f7a..f4c756c 100644 --- a/PcgsInvUi/Views/DeleteWindow.axaml +++ b/PcgsInvUi/Views/DeleteWindow.axaml @@ -7,18 +7,18 @@ Width="325" Height="100" WindowStartupLocation="CenterOwner" Title="DeleteWindow"> -