From 34657b9b78a76954f89c6ed8dd181f974887a621 Mon Sep 17 00:00:00 2001 From: Lynne Date: Tue, 15 Jun 2021 10:34:11 +1000 Subject: [PATCH] formatting that makes it look slightly less icky --- AddItemDialogue.cs | 7 +- MainWindow.cs | 302 +++++++++++++++++++++---------------------- Settings.cs | 8 +- SettingsWindow.cs | 28 ++-- YahooAuctionsItem.cs | 47 +++---- 5 files changed, 192 insertions(+), 200 deletions(-) diff --git a/AddItemDialogue.cs b/AddItemDialogue.cs index 594d71f..73123c1 100644 --- a/AddItemDialogue.cs +++ b/AddItemDialogue.cs @@ -5,13 +5,14 @@ namespace Buypeeb { private readonly Entry entryURL; private readonly Entry entryName; - public AddItemDialogue() : this(new Builder("add.glade")) { } + public AddItemDialogue() : this(new Builder("add.glade")) { + } private AddItemDialogue(Builder builder) : base(builder.GetObject("DialogueAdd").Handle) { Title = "Add item"; builder.Autoconnect(this); - entryURL = (Entry)builder.GetObject("EntryAddURL"); - entryName = (Entry)builder.GetObject("EntryAddName"); + entryURL = (Entry) builder.GetObject("EntryAddURL"); + entryName = (Entry) builder.GetObject("EntryAddName"); DeleteEvent += Window_Shutdown; } diff --git a/MainWindow.cs b/MainWindow.cs index 1e1dafc..916f3c4 100755 --- a/MainWindow.cs +++ b/MainWindow.cs @@ -39,7 +39,6 @@ using Timeout = GLib.Timeout; namespace Buypeeb { [SuppressMessage("ReSharper", "UnusedMember.Local")] internal class MainWindow : Window { - private string location; private JsonSerializerOptions jsonOptions; @@ -52,46 +51,40 @@ namespace Buypeeb { // that way we don't need to constantly do "builder.GetObject"s // when that is done, you can use the cache array to replace everything from here... - private Box selectionViewBox; - private Label endingLabel; + private readonly Box selectionViewBox; + private readonly Label endingLabel; private bool queueActive; - private SearchEntry searchEntry; - private Dictionary filterChecks = new Dictionary(); + private readonly SearchEntry searchEntry; + private readonly Dictionary filterChecks = new Dictionary(); // ...to here. private static SemaphoreSlim taskLimit = new SemaphoreSlim(6); - private Queue updateQueue = new Queue(); - private IEnumerable filterQuery { - get { - // father forgive me for i have lynned - return - from item in settings.watchlist.Values.ToList() - where (item.favourite != filterChecks["Favourites"].Active || - item.favourite == filterChecks["NonFavourites"].Active) && - (item.Available != filterChecks["Active"].Active || - item.Available == filterChecks["Ended"].Active) && - (item.endingToday != filterChecks["EndingToday"].Active || - item.endingToday == filterChecks["EndingAfterToday"].Active) && - (item.hasWinPrice != filterChecks["WithWinPrice"].Active || - item.hasWinPrice == filterChecks["WithNoWinPrice"].Active) && - (String.IsNullOrWhiteSpace(searchEntry.Text) || - item.name.ToLower().Contains(searchEntry.Text.ToLower()) || - item.originalName.ToLower().Contains(searchEntry.Text.ToLower())) - select item; - } - } - private IEnumerable outdatedItemQuery { - get { - // only returns items that meet all of the following: - // - marked as "ready", as in, they aren't in the process of updating - // - not updated since the interval - return - from item in settings.watchlist.Values.ToList() - where item.Ready && settings.ItemNotUpdatedSinceInterval(item) - select item; - } - } + private readonly Queue updateQueue = new Queue(); + + private IEnumerable filterQuery => + // father forgive me for i have lynned + from item in settings.watchlist.Values.ToList() + where (item.favourite != filterChecks["Favourites"].Active || + item.favourite == filterChecks["NonFavourites"].Active) && + (item.Available != filterChecks["Active"].Active || + item.Available == filterChecks["Ended"].Active) && + (item.endingToday != filterChecks["EndingToday"].Active || + item.endingToday == filterChecks["EndingAfterToday"].Active) && + (item.hasWinPrice != filterChecks["WithWinPrice"].Active || + item.hasWinPrice == filterChecks["WithNoWinPrice"].Active) && + (string.IsNullOrWhiteSpace(searchEntry.Text) || + item.name.ToLower().Contains(searchEntry.Text.ToLower()) || + item.originalName.ToLower().Contains(searchEntry.Text.ToLower())) + select item; + + private IEnumerable outdatedItemQuery => + // only returns items that meet all of the following: + // - marked as "ready", as in, they aren't in the process of updating + // - not updated since the interval + from item in settings.watchlist.Values.ToList() + where item.Ready && settings.ItemNotUpdatedSinceInterval(item) + select item; private YahooAuctionsItem selectedItem { get { @@ -101,11 +94,12 @@ namespace Buypeeb { } itemTreeView.Selection.GetSelected(out var iter); - return (YahooAuctionsItem)itemTreeView.Model.GetValue(iter, 0); + return (YahooAuctionsItem) itemTreeView.Model.GetValue(iter, 0); } } - public MainWindow() : this(new Builder("main.glade")) { } + public MainWindow() : this(new Builder("main.glade")) { + } private MainWindow(Builder builder) : base(builder.GetObject("wndMain").Handle) { jsonOptions = new JsonSerializerOptions { @@ -114,11 +108,12 @@ namespace Buypeeb { if (Environment.OSVersion.Platform == PlatformID.Win32NT) { // C:\Users\Beebus\AppData\Roaming\Lynnear Software\buypeeb - location = System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%APPDATA%"), "Lynnear Software", "buypeeb"); - } - else { + location = System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%APPDATA%"), "Lynnear Software", + "buypeeb"); + } else { // ~/.config/Lynnear Software/buypeeb - location = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "Lynnear Software", "buypeeb"); + location = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", + "Lynnear Software", "buypeeb"); } var userdata = System.IO.Path.Combine(location, "userdata.json"); @@ -126,38 +121,39 @@ namespace Buypeeb { try { var j = File.ReadAllText(userdata); settings = JsonSerializer.Deserialize(j); - } - catch { + } catch { // ??? Console.WriteLine("oops"); Application.Quit(); } - - } - else { + } else { settings = new Settings(); } + SaveSettings(); Title = "Buypeeb"; this.builder = builder; builder.Autoconnect(this); - var menuButtonFilter = (MenuButton)builder.GetObject("MenuButtonFilter"); - var menuButtonSort = (MenuButton)builder.GetObject("MenuButtonSort"); - menuButtonFilter.Child = (Image)builder.GetObject("ImageFilter"); - menuButtonSort.Child = (Image)builder.GetObject("ImageSort"); + var menuButtonFilter = (MenuButton) builder.GetObject("MenuButtonFilter"); + var menuButtonSort = (MenuButton) builder.GetObject("MenuButtonSort"); + menuButtonFilter.Child = (Image) builder.GetObject("ImageFilter"); + menuButtonSort.Child = (Image) builder.GetObject("ImageSort"); - selectionViewBox = (Box)builder.GetObject("SelectionViewBox"); - endingLabel = (Label)builder.GetObject("LabelSelectedEnding"); - searchEntry = (SearchEntry)builder.GetObject("FilterSearchEntry"); - foreach (var name in new List { "Favourites", "NonFavourites", "Active", "Ended", "EndingToday", "EndingAfterToday", "WithWinPrice", "WithNoWinPrice" }) { - filterChecks.Add(name, (CheckButton)builder.GetObject($"CheckButtonFilter{name}")); + selectionViewBox = (Box) builder.GetObject("SelectionViewBox"); + endingLabel = (Label) builder.GetObject("LabelSelectedEnding"); + searchEntry = (SearchEntry) builder.GetObject("FilterSearchEntry"); + foreach (var name in new List { + "Favourites", "NonFavourites", "Active", "Ended", "EndingToday", "EndingAfterToday", "WithWinPrice", + "WithNoWinPrice" + }) { + filterChecks.Add(name, (CheckButton) builder.GetObject($"CheckButtonFilter{name}")); filterChecks[name].Active = false; } // bind treeview columns to watchlist instead of needing to manually sync its liststore - itemTreeView = (TreeView)builder.GetObject("TreeViewItems"); + itemTreeView = (TreeView) builder.GetObject("TreeViewItems"); items = new ListStore(typeof(YahooAuctionsItem)); var filteredItems = new TreeModelFilter(items, null) {VisibleFunc = ItemFilter}; @@ -199,10 +195,10 @@ namespace Buypeeb { // TODO: surely there's a better way to do this TreeIter iter; itemTreeView.Model.GetIterFirst(out iter); - var m = (TreeModelFilter)itemTreeView.Model; + var m = (TreeModelFilter) itemTreeView.Model; for (var i = 0; i < itemTreeView.Model.IterNChildren(); i++) { - var x = (YahooAuctionsItem)itemTreeView.Model.GetValue(iter, 0); + var x = (YahooAuctionsItem) itemTreeView.Model.GetValue(iter, 0); if (x.id == id) { return (m.ConvertPathToChildPath(m.GetPath(iter)), m.ConvertIterToChildIter(iter)); } @@ -228,7 +224,6 @@ namespace Buypeeb { using (var fs = File.CreateText(p)) { fs.Write(j); } - } /// @@ -262,6 +257,7 @@ namespace Buypeeb { if (pathAndIter.path != null) { items.EmitRowChanged(pathAndIter.path, pathAndIter.iter); } + if (item == selectedItem) { // if the user has this item selected and it just became ready, enable the selection box and redraw the info selectionViewBox.Sensitive = true; @@ -281,8 +277,7 @@ namespace Buypeeb { UpdateItem(updateQueue.Dequeue()); if (updateQueue.TryPeek(out var _)) { ProcessUpdateQueue(); - } - else { + } else { queueActive = false; } } @@ -302,14 +297,10 @@ namespace Buypeeb { // don't start a new task if there are more than `tasklimit` tasks currently running // this makes sure we don't make 1000 simultaneous requests to yahoo auctions if there are 1000 items on the watchlist taskLimit.Wait(); - Task.Factory.StartNew(() => { - UpdateThread(id); - }).ContinueWith(task => { + Task.Factory.StartNew(() => { UpdateThread(id); }).ContinueWith(task => { taskLimit.Release(); if (renderListWhenDone) { - Application.Invoke(delegate { - RenderList(); - }); + Application.Invoke(delegate { RenderList(); }); } }); } @@ -338,10 +329,7 @@ namespace Buypeeb { } itemTreeView.QueueDraw(); - Task.Factory.StartNew(() => { - ProcessUpdateQueue(); - }); - + Task.Factory.StartNew(() => { ProcessUpdateQueue(); }); } /// @@ -350,7 +338,7 @@ namespace Buypeeb { private void UpdateSelectionView() { // get the currently selected item var item = selectedItem; - var infobox = (Box)builder.GetObject("SelectionInfoBox"); + var infobox = (Box) builder.GetObject("SelectionInfoBox"); if (item == null) { selectionViewBox.Sensitive = false; @@ -363,30 +351,30 @@ namespace Buypeeb { infobox.Visible = true; var info = new Dictionary { - { "Name", item.name }, - { "YahooName", item.originalName }, - { "Price", item.priceJpy }, - { "PriceAUD", item.priceAud }, - { "Ending", "Please wait..." }, - { "Bids", $"{item.Bids}" }, - { "BuyItNow", item.WinPrice == 0 ? "No" : $"{item.winPriceJpy} ({item.winPriceAud})" }, - { "AutoExtension", item.AutoExtension ? "Yes" : "No" }, - { "LastUpdated", $"Last updated: {(item.Ready ? item.LastUpdated.ToString("MMM dd, HH:mm:ss") : "Right now!")}" }, + {"Name", item.name}, + {"YahooName", item.originalName}, + {"Price", item.priceJpy}, + {"PriceAUD", item.priceAud}, + {"Ending", "Please wait..."}, + {"Bids", $"{item.Bids}"}, + {"BuyItNow", item.WinPrice == 0 ? "No" : $"{item.winPriceJpy} ({item.winPriceAud})"}, + {"AutoExtension", item.AutoExtension ? "Yes" : "No"}, + {"LastUpdated", $"Last updated: {(item.Ready ? item.LastUpdated.ToString("MMM dd, HH:mm:ss") : "Right now!")}"}, }; foreach (var row in info) { ((Label) builder.GetObject($"LabelSelected{row.Key}")).Text = row.Value; } + UpdateSelectionEndTime(); - var noteBuffer = (TextBuffer)builder.GetObject("TextBufferSelectedNotes"); + var noteBuffer = (TextBuffer) builder.GetObject("TextBufferSelectedNotes"); noteBuffer.Clear(); - if (!String.IsNullOrWhiteSpace(item.notes)) { + if (!string.IsNullOrWhiteSpace(item.notes)) { noteBuffer.Text = item.notes; } ((ToggleButton) builder.GetObject("ButtonSelectedFavourite")).Active = item.favourite; - } /// @@ -401,8 +389,7 @@ namespace Buypeeb { UseShellExecute = true, }; Process.Start(psi); - } - else { + } else { // let's hope you have xdg-open installed Process.Start("xdg-open", url); } @@ -421,11 +408,7 @@ namespace Buypeeb { type: MessageType.Question, bt: buttonsType, format: message - ); - md.KeepAbove = true; - md.Resizable = false; - md.FocusOnMap = true; - md.Title = "Buypeeb"; + ) {KeepAbove = true, Resizable = false, FocusOnMap = true, Title = "Buypeeb"}; return md; } @@ -437,22 +420,23 @@ namespace Buypeeb { /// the prompt that should be presented to the user /// a string to prefill the input box with /// - private (Boolean accepted, string response) EntryDialogue(string title = "Buypeeb", string message = "Hi there!", string prefill = null) { + private (bool accepted, string response) EntryDialogue( + string title = "Buypeeb", string message = "Hi there!", string prefill = null + ) { var ed = new Dialog( title: title, parent: this, flags: DialogFlags.DestroyWithParent | DialogFlags.Modal, /* button_data: */ "Cancel", ResponseType.Cancel, "OK", ResponseType.Ok - ); + ) {DefaultResponse = ResponseType.Ok, KeepAbove = true}; - ed.DefaultResponse = ResponseType.Ok; - ed.KeepAbove = true; var edLabel = new Label(message); var edEntry = new Entry(); - if (!String.IsNullOrWhiteSpace(prefill)) { + if (!string.IsNullOrWhiteSpace(prefill)) { edEntry.Text = prefill; } + edEntry.ActivatesDefault = true; ed.ContentArea.PackStart(edLabel, true, true, 2); @@ -466,7 +450,7 @@ namespace Buypeeb { ed.ContentArea.MarginEnd = 5; ed.MarginBottom = 5; - var accepted = (ResponseType)ed.Run(); + var accepted = (ResponseType) ed.Run(); var response = edEntry.Text; ed.Dispose(); return (accepted == ResponseType.Ok, response); @@ -477,8 +461,10 @@ namespace Buypeeb { /// /// the id of the radiobutton without the "Sort" prefix private string GetSortType() { - foreach (var name in new List { "NameDescending", "NameAscending", "PriceDescending", "PriceAscending", "EndingDescending", "EndingAscending" }) { - var radio = (RadioMenuItem)builder.GetObject($"Sort{name}"); + foreach (var name in new List { + "NameDescending", "NameAscending", "PriceDescending", "PriceAscending", "EndingDescending", "EndingAscending" + }) { + var radio = (RadioMenuItem) builder.GetObject($"Sort{name}"); if (radio.Active) { return name; } @@ -502,20 +488,15 @@ namespace Buypeeb { var type = GetSortType(); if (type == "NameDescending") { sorted = values.OrderByDescending(item => item.name); - } - else if (type == "NameAscending") { + } else if (type == "NameAscending") { sorted = values.OrderBy(item => item.name); - } - else if (type == "PriceDescending") { + } else if (type == "PriceDescending") { sorted = values.OrderByDescending(item => item.Price); - } - else if (type == "PriceAscending") { + } else if (type == "PriceAscending") { sorted = values.OrderBy(item => item.Price); - } - else if (type == "EndingDescending") { + } else if (type == "EndingDescending") { sorted = values.OrderByDescending(item => item.endDate); - } - else { + } else { sorted = values.OrderBy(item => item.endDate); } @@ -527,8 +508,7 @@ namespace Buypeeb { foreach (var item in sorted.Where(item => !item.favourite)) { items.AppendValues(item); } - } - else { + } else { foreach (var item in sorted) { items.AppendValues(item); } @@ -536,7 +516,9 @@ namespace Buypeeb { ((TreeModelFilter) itemTreeView.Model).Refilter(); - if (id == null) { return; } + if (id == null) { + return; + } // attempt to reselect the item we were just looking at // ReSharper disable once UseDeconstruction @@ -562,8 +544,7 @@ namespace Buypeeb { if (rx.IsMatch(url)) { UpdateItem(settings.Watch(url, name).id, true); RenderList(); - } - else { + } else { var md = MsgBox($"\"{url}\" is not a valid Buyee or Yahoo! Auctions Japan URL.", ButtonsType.Ok); md.Run(); md.Dispose(); @@ -576,7 +557,7 @@ namespace Buypeeb { private void ButtonClearEndedClicked(object sender, EventArgs a) { var md = MsgBox("Are you sure you want to remove all ended auctions from the list?"); - var r = (ResponseType)md.Run(); + var r = (ResponseType) md.Run(); md.Dispose(); if (r != ResponseType.Ok) { return; @@ -598,10 +579,11 @@ namespace Buypeeb { private void ButtonClearAllClicked(object sender, EventArgs a) { var md = MsgBox("Are you sure you want to clear ALL items?"); - if (md.Run() == (int)ResponseType.Ok) { + if (md.Run() == (int) ResponseType.Ok) { settings.watchlist.Clear(); RenderList(); } + md.Dispose(); } @@ -619,20 +601,20 @@ namespace Buypeeb { odf.AddPattern("*.json"); od.AddFilter(odf); - if (od.Run() == (int)ResponseType.Accept) { + if (od.Run() == (int) ResponseType.Accept) { try { var j = File.ReadAllText(od.Filename); settings = JsonSerializer.Deserialize(j); RenderList(); UpdateItems(); - } - catch (Exception e) { + } catch (Exception e) { Console.WriteLine(e); var md = MsgBox($"Failed to load {od.Filename}!\n{e.Message}", ButtonsType.Ok); md.Run(); md.Dispose(); } } + od.Dispose(); } @@ -649,21 +631,19 @@ namespace Buypeeb { ); sd.CurrentName = "userdata.json"; - var sdf = new FileFilter(); - sdf.Name = "JSON files"; + var sdf = new FileFilter {Name = "JSON files"}; sdf.AddMimeType("application/json"); sdf.AddPattern("*.json"); sd.AddFilter(sdf); - if (sd.Run() == (int)ResponseType.Accept) { + if (sd.Run() == (int) ResponseType.Accept) { try { if (!File.Exists(sd.Filename)) { using (var fs = File.CreateText(sd.Filename)) { fs.Write(JsonSerializer.Serialize(settings, jsonOptions)); } } - } - catch (Exception e) { + } catch (Exception e) { Console.WriteLine(e); var md = MsgBox($"Failed to write {sd.Filename}!\n{e.Message}.", ButtonsType.Ok); md.Run(); @@ -698,15 +678,13 @@ namespace Buypeeb { sdf.AddPattern("*.csv"); sd.AddFilter(sdf); - if (sd.Run() == (int)ResponseType.Accept) { + if (sd.Run() == (int) ResponseType.Accept) { try { using (var writer = new StreamWriter(sd.Filename)) using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) { - csv.WriteRecords(settings.watchlist); } - } - catch (Exception e) { + } catch (Exception e) { Console.WriteLine(e); var md = MsgBox($"Failed to write {sd.Filename}!\n{e.Message}.", ButtonsType.Ok); md.Run(); @@ -722,10 +700,12 @@ namespace Buypeeb { foreach (var item in settings.watchlist) { Console.WriteLine(item); } + Console.WriteLine("---\nFilter results:"); foreach (var item in filterQuery) { Console.WriteLine(item); } + Console.WriteLine("---\nListstore contents:"); foreach (object[] item in items) { Console.WriteLine(item[0]); @@ -735,7 +715,7 @@ namespace Buypeeb { private void ButtonQuitClicked(object sender, EventArgs a) { var md = MsgBox("Are you sure you want to quit?"); - var response = (ResponseType)md.Run(); + var response = (ResponseType) md.Run(); md.Dispose(); if (response == ResponseType.Ok) { SaveSettings(); @@ -765,9 +745,11 @@ namespace Buypeeb { private void ButtonSelectedRemoveClicked(object sender, EventArgs a) { var item = selectedItem; - var md = MsgBox($"Are you sure you want to remove the item \"{item.name}\"?"); // TODO: this looks bad being all on one line + var md = MsgBox( + $"Are you sure you want to remove the item \"{item.name}\"?" + ); - var response = (ResponseType)md.Run(); + var response = (ResponseType) md.Run(); md.Dispose(); if (response == ResponseType.Ok) { settings.watchlist.Remove(item.id); @@ -777,7 +759,10 @@ namespace Buypeeb { private void ButtonSelectedRenameClicked(object sender, EventArgs a) { var item = selectedItem; - (var accepted, var response) = EntryDialogue("Rename item", $"Enter a new name for the item \"{item.name}\".", item.name); + var (accepted, response) = EntryDialogue( + "Rename item", $"Enter a new name for the item \"{item.name}\".", item.name + ); + if (accepted) { item.name = response; UpdateSelectionView(); @@ -790,17 +775,17 @@ namespace Buypeeb { // the item is already waiting to be updated return; } + UpdateItem(selectedItem.id); } private void ButtonSelectedFavouriteToggled(object sender, EventArgs args) { - var s = (ToggleButton)sender; + var s = (ToggleButton) sender; selectedItem.favourite = s.Active; if (settings.showFavouritesAtTopOfList) { RenderList(); - } - else { + } else { // i don't know why this is necessary var pathAndIter = GetRow(selectedItem.id); if (pathAndIter.path != null) { @@ -812,20 +797,21 @@ namespace Buypeeb { private void ButtonSelectedNotesClearClicked(object sender, EventArgs args) { var item = selectedItem; var md = MsgBox($"Are you sure you want to clear the notes for \"{item.name}\"?"); - if (md.Run() == (int)ResponseType.Ok) { - var noteBuffer = (TextBuffer)builder.GetObject("TextBufferSelectedNotes"); + if (md.Run() == (int) ResponseType.Ok) { + var noteBuffer = (TextBuffer) builder.GetObject("TextBufferSelectedNotes"); noteBuffer.Clear(); selectedItem.notes = null; } + md.Dispose(); } private void TextViewSelectedNotesFocusOut(object sender, FocusOutEventArgs args) { // the "save" button does nothing, however, when you click the save button, you transfer focus to it, firing this event! // how very sneaky - var noteBuffer = (TextBuffer)builder.GetObject("TextBufferSelectedNotes"); + var noteBuffer = (TextBuffer) builder.GetObject("TextBufferSelectedNotes"); if (selectedItem != null) { - selectedItem.notes = String.IsNullOrWhiteSpace(noteBuffer.Text) ? null : noteBuffer.Text; + selectedItem.notes = string.IsNullOrWhiteSpace(noteBuffer.Text) ? null : noteBuffer.Text; } } @@ -862,12 +848,12 @@ namespace Buypeeb { if (span.Days > 0) { ending += span.ToString("dd' days, '"); // will format twelve days as "12 days, " } + // timespan objects don't contain definitions for the time or date separators, so the colons need to be escaped // `HH` doesn't exist, but `hh` behaves identically // see https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-timespan-format-strings ending += span.ToString(@"hh\:mm\:ss"); - } - else { + } else { ending = "Auction has ended"; } @@ -899,34 +885,39 @@ namespace Buypeeb { // column renderers - private void RenderColumnFavourite(TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter) { - var item = (YahooAuctionsItem)model.GetValue(iter, 0); + private static void RenderColumnFavourite( + TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter + ) { + var item = (YahooAuctionsItem) model.GetValue(iter, 0); ((CellRendererText) cell).Text = item.favourite ? "♥" : ""; } - private void RenderColumnName(TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter) { - var item = (YahooAuctionsItem)model.GetValue(iter, 0); + private static void RenderColumnName(TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter) { + var item = (YahooAuctionsItem) model.GetValue(iter, 0); ((CellRendererText) cell).Text = item.name ?? "Loading..."; } - private void RenderColumnPriceYen(TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter) { - var item = (YahooAuctionsItem)model.GetValue(iter, 0); + private static void RenderColumnPriceYen( + TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter + ) { + var item = (YahooAuctionsItem) model.GetValue(iter, 0); ((CellRendererText) cell).Text = item.Ready ? item.priceJpy : "..."; } - private void RenderColumnPriceAUD(TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter) { - var item = (YahooAuctionsItem)model.GetValue(iter, 0); + private static void RenderColumnPriceAUD( + TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter + ) { + var item = (YahooAuctionsItem) model.GetValue(iter, 0); ((CellRendererText) cell).Text = item.Ready ? item.priceAud : "..."; } private void RenderColumnEnding(TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter) { - var item = (YahooAuctionsItem)model.GetValue(iter, 0); + var item = (YahooAuctionsItem) model.GetValue(iter, 0); var ending = ""; if (item.Ready) { if (!item.Available) { ending = "Ended"; - } - else { + } else { var now = DateTime.Now; var end = item.endDate.ToLocalTime(); // TODO: should we show the year if the auction ends next year? 0uo @@ -934,6 +925,7 @@ namespace Buypeeb { // the auction isn't ending today, so we should show the day it's ending on for clarity ending += end.ToString("MMM d "); } + ending += end.ToString("HH:mm"); if (settings.showSecondsInListView) { // add the seconds on to the end @@ -941,16 +933,18 @@ namespace Buypeeb { } } } + ((CellRendererText) cell).Text = item.Ready ? ending : "..."; } // tree filter private bool ItemFilter(ITreeModel model, TreeIter iter) { - var item = (YahooAuctionsItem)model.GetValue(iter, 0); + var item = (YahooAuctionsItem) model.GetValue(iter, 0); if (item == null) { return true; } + if (item.Price == 0) { // the item has only just been added, so we can't compare it against the filters, since it's missing most of its data return true; diff --git a/Settings.cs b/Settings.cs index 4a3d013..a12b189 100644 --- a/Settings.cs +++ b/Settings.cs @@ -11,9 +11,7 @@ namespace Buypeeb { public bool autosave { get; set; } = true; public bool showFavouritesAtTopOfList { get; set; } = true; - public Dictionary watchlist { - get; set; - } + public Dictionary watchlist { get; set; } public Settings() { // create a new watchlist from an empty dictionary if it's null, which should only happen if either this is the @@ -34,10 +32,10 @@ namespace Buypeeb { int seconds; if (item.favourite) { seconds = item.endingSoon ? favouriteUpdateIntervalCritical : favouriteUpdateInterval; - } - else { + } else { seconds = item.endingSoon ? updateIntervalCritical : updateInterval; } + var later = item.LastUpdated.AddSeconds(seconds); return DateTime.Compare(later, DateTime.UtcNow) < 0; } diff --git a/SettingsWindow.cs b/SettingsWindow.cs index 4bef5f8..36cd2f2 100644 --- a/SettingsWindow.cs +++ b/SettingsWindow.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Gtk; + // ReSharper disable UnusedMember.Local // ReSharper disable UnusedParameter.Local @@ -11,10 +12,14 @@ namespace Buypeeb { private readonly Settings settings; private readonly Builder builder; - private readonly List generalSwitchNames = new List { "ShowSecondsInListView", "Autosave", "ShowFavouritesAtTopOfList" }; - private readonly List updateIntervalEntryNames = new List { "UpdateInterval", "UpdateIntervalCritical", "FavouriteUpdateInterval", "FavouriteUpdateIntervalCritical" }; + private readonly List generalSwitchNames = new List + {"ShowSecondsInListView", "Autosave", "ShowFavouritesAtTopOfList"}; - public SettingsWindow(Settings settings) : this(new Builder("settings.glade"), settings) { } + private readonly List updateIntervalEntryNames = new List + {"UpdateInterval", "UpdateIntervalCritical", "FavouriteUpdateInterval", "FavouriteUpdateIntervalCritical"}; + + public SettingsWindow(Settings settings) : this(new Builder("settings.glade"), settings) { + } private SettingsWindow(Builder builder, Settings settings) : base(builder.GetObject("WindowSettings").Handle) { Title = "Buypeeb - Settings"; @@ -23,20 +28,20 @@ namespace Buypeeb { builder.Autoconnect(this); foreach (var name in generalSwitchNames) { - var s = (Switch)builder.GetObject($"Switch{name}"); + var s = (Switch) builder.GetObject($"Switch{name}"); generalSwitches.Add(s); s.Active = GetSetting(PropertyName(name)); } foreach (var name in updateIntervalEntryNames) { - var e = (Entry)builder.GetObject($"Entry{name}"); + var e = (Entry) builder.GetObject($"Entry{name}"); updateIntervalEntries.Add(e); e.Text = GetSetting(PropertyName(name)).ToString(); } } private T GetSetting(string property) { - return (T)settings.GetType().GetProperty(property).GetValue(settings, null); + return (T) settings.GetType().GetProperty(property).GetValue(settings, null); } private void SetSetting(string property, T value) { @@ -52,11 +57,10 @@ namespace Buypeeb { // first, validate all the intervals var failed = false; foreach (var name in updateIntervalEntryNames) { - var e = (Entry)builder.GetObject($"Entry{name}"); + var e = (Entry) builder.GetObject($"Entry{name}"); if (!int.TryParse(e.Text, out var result)) { failed = true; - } - else { + } else { if (result < 30 || result > 6000) { failed = true; } @@ -66,7 +70,8 @@ namespace Buypeeb { continue; } - var md = new MessageDialog(this, DialogFlags.Modal, MessageType.Error, ButtonsType.Ok, "Update intervals must be a whole number between 30 and 6000."); + var md = new MessageDialog(this, DialogFlags.Modal, MessageType.Error, ButtonsType.Ok, + "Update intervals must be a whole number between 30 and 6000."); md.Run(); md.Dispose(); return; @@ -81,6 +86,7 @@ namespace Buypeeb { foreach (var name in generalSwitchNames) { SetSetting(PropertyName(name), ((Switch) builder.GetObject($"Switch{name}")).Active); } + Dispose(); } @@ -88,4 +94,4 @@ namespace Buypeeb { Dispose(); } } -} \ No newline at end of file +} diff --git a/YahooAuctionsItem.cs b/YahooAuctionsItem.cs index ee94c31..a6d1a8e 100644 --- a/YahooAuctionsItem.cs +++ b/YahooAuctionsItem.cs @@ -8,11 +8,9 @@ using CsvHelper.Configuration.Attributes; namespace Buypeeb { internal class YahooAuctionsItem { - [JsonIgnore] - public string url => $"https://page.auctions.yahoo.co.jp/jp/auction/{id}"; + [JsonIgnore] public string url => $"https://page.auctions.yahoo.co.jp/jp/auction/{id}"; - [JsonIgnore] - public string buyeeUrl => $"https://buyee.jp/item/yahoo/auction/{id}"; + [JsonIgnore] public string buyeeUrl => $"https://buyee.jp/item/yahoo/auction/{id}"; // any items with a getter will be saved to userdata.json // anything that's configurable by the user, such as the custom name, should be saved @@ -20,8 +18,7 @@ namespace Buypeeb { // i'm also saving the original name to make it easier to tell what the items are in the userdata.json // there's not really a need for it i guess but it's my program and i can do what i want // anything with the attribute [Ignore] won't be put in the CSV, and things with [JsonIgnore] won't be put in userdata.json - [Ignore] - public string id { get; } + [Ignore] public string id { get; } public string name { get; set; } public int Price; public int WinPrice; @@ -44,26 +41,19 @@ namespace Buypeeb { } } - [JsonIgnore] - public string priceJpy => $"¥{Price}"; + [JsonIgnore] public string priceJpy => $"¥{Price}"; - [JsonIgnore] - public string winPriceJpy => $"¥{WinPrice}"; + [JsonIgnore] public string winPriceJpy => $"¥{WinPrice}"; - [Ignore, JsonIgnore] - public string priceAud => $"${(Price / 75.0):f2}"; + [Ignore, JsonIgnore] public string priceAud => $"${(Price / 75.0):f2}"; - [Ignore, JsonIgnore] - public string winPriceAud => $"${(WinPrice / 75.0):f2}"; + [Ignore, JsonIgnore] public string winPriceAud => $"${(WinPrice / 75.0):f2}"; - [Ignore, JsonIgnore] - public bool endingToday => endDate.DayOfYear == DateTime.UtcNow.DayOfYear; + [Ignore, JsonIgnore] public bool endingToday => endDate.DayOfYear == DateTime.UtcNow.DayOfYear; - [Ignore, JsonIgnore] - public bool hasWinPrice => WinPrice != 0; + [Ignore, JsonIgnore] public bool hasWinPrice => WinPrice != 0; - [Ignore, JsonIgnore] - public bool endingSoon => DateTime.Compare(DateTime.UtcNow.AddMinutes(10), endDate) > 0; + [Ignore, JsonIgnore] public bool endingSoon => DateTime.Compare(DateTime.UtcNow.AddMinutes(10), endDate) > 0; private bool success { get; set; } // TODO: custom setter that throws an exception if set to false or something idk @@ -78,26 +68,29 @@ namespace Buypeeb { public void Update(string html) { // TODO: handle all the parsing errors and weird interpretation that could possibly happen here - var rx = new Regex(@"var pageData ?= ?(\{.+?\});", RegexOptions.Singleline); // TODO: maybe compile and match the regex in another thread + var rx = new Regex(@"var pageData ?= ?(\{.+?\});", + RegexOptions.Singleline); // TODO: maybe compile and match the regex in another thread var m = rx.Match(html); Dictionary> jFull; try { // master forgive me, but i must go all out, just this once... jFull = JsonSerializer.Deserialize>>(m.Groups[1].Value); - } - catch { + } catch { Console.WriteLine("oh jeez oh man oh jeez oh man oh jeez oh man"); Console.WriteLine(m.Groups[1].Value); throw; } - var jst = TimeZoneInfo.CreateCustomTimeZone("JST", new TimeSpan(9, 0, 0), "Japan Standard Time", "Japen Standard Time"); + var jst = TimeZoneInfo.CreateCustomTimeZone("JST", new TimeSpan(9, 0, 0), "Japan Standard Time", + "Japen Standard Time"); var j = jFull["items"]; originalName = j["productName"]; - StartDate = TimeZoneInfo.ConvertTimeToUtc(DateTime.ParseExact(j["starttime"], "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), jst); - endDate = TimeZoneInfo.ConvertTimeToUtc(DateTime.ParseExact(j["endtime"], "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), jst); + StartDate = TimeZoneInfo.ConvertTimeToUtc( + DateTime.ParseExact(j["starttime"], "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), jst); + endDate = TimeZoneInfo.ConvertTimeToUtc( + DateTime.ParseExact(j["endtime"], "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), jst); LastUpdated = DateTime.UtcNow; Available = j["isClosed"] == "0"; @@ -105,7 +98,7 @@ namespace Buypeeb { success = int.TryParse(j["winPrice"], out WinPrice); success = int.TryParse(j["bids"], out Bids); - if (String.IsNullOrWhiteSpace(name)) { + if (string.IsNullOrWhiteSpace(name)) { name = originalName; }