Compare commits
7 commits
1917225f39
...
f897221ea6
Author | SHA1 | Date | |
---|---|---|---|
f897221ea6 | |||
0daccea9fd | |||
f252b52553 | |||
ee947c84a0 | |||
b085198c2d | |||
9ad7e4f288 | |||
11020ed0c4 |
4 changed files with 169 additions and 78 deletions
53
Listing.cs
53
Listing.cs
|
@ -5,43 +5,59 @@ using System.Collections.Generic;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Buypeeb {
|
namespace Buypeeb {
|
||||||
class Listing {
|
class YahooAuctionsItem {
|
||||||
public string url {
|
public string url {
|
||||||
get {
|
get {
|
||||||
return $"https://page.auctions.yahoo.co.jp/jp/auction/{this.id}";
|
return $"https://page.auctions.yahoo.co.jp/jp/auction/{this.id}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string buyee_url {
|
public string buyeeUrl {
|
||||||
get {
|
get {
|
||||||
return $"https://buyee.jp/item/yahoo/auction/{this.id}";
|
return $"https://buyee.jp/item/yahoo/auction/{this.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
|
||||||
|
// the id *must* be saved!
|
||||||
|
// 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
|
||||||
public string id { get; set; }
|
public string id { get; set; }
|
||||||
public string name { get; set; }
|
public string name { get; set; }
|
||||||
public int price = 0;
|
public int price = 0;
|
||||||
public int win_price;
|
public int winPrice;
|
||||||
public string original_name;
|
public string originalName { get; set; }
|
||||||
public bool favourite { get; set; } = false;
|
public bool favourite { get; set; } = false;
|
||||||
// start_date, end_date
|
public DateTime startDate;
|
||||||
|
public DateTime endDate;
|
||||||
|
public DateTime lastUpdated;
|
||||||
public int bids;
|
public int bids;
|
||||||
public bool auto_extension;
|
public bool autoExtension;
|
||||||
public bool ready;
|
public bool ready;
|
||||||
|
public bool available;
|
||||||
|
|
||||||
|
public bool updatedRecently {
|
||||||
|
get {
|
||||||
|
var later = this.lastUpdated.AddSeconds(15);
|
||||||
|
return DateTime.Compare(later, this.lastUpdated) < 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool success { get; set; } // TODO: custom setter that throws an exception if set to false or something idk
|
private bool success { get; set; } // TODO: custom setter that throws an exception if set to false or something idk
|
||||||
|
|
||||||
public Listing(string id, string name) {
|
public YahooAuctionsItem(string id, string name) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.ready = false;
|
this.ready = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Listing() {
|
public YahooAuctionsItem() {
|
||||||
// parameterless constructor for deserialisation
|
// parameterless constructor for deserialisation
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(string html) {
|
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);
|
var m = rx.Match(html);
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
|
@ -55,17 +71,26 @@ namespace Buypeeb {
|
||||||
j_full = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(m.Groups[1].Value);
|
j_full = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(m.Groups[1].Value);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
|
Console.WriteLine("oh jeez oh man oh jeez oh man oh jeez oh man");
|
||||||
|
Console.WriteLine(m.Groups[1].Value);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var jst = TimeZoneInfo.FindSystemTimeZoneById("Asia/Tokyo");
|
||||||
|
|
||||||
var j = j_full["items"];
|
var j = j_full["items"];
|
||||||
this.original_name = j["productName"];
|
this.originalName = j["productName"];
|
||||||
|
this.startDate = TimeZoneInfo.ConvertTimeToUtc(DateTime.ParseExact(j["starttime"], "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), jst);
|
||||||
|
this.endDate = TimeZoneInfo.ConvertTimeToUtc(DateTime.ParseExact(j["endtime"], "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), jst);
|
||||||
|
this.lastUpdated = DateTime.UtcNow;
|
||||||
|
this.available = j["isClosed"] == "0";
|
||||||
|
|
||||||
this.success = int.TryParse(j["price"], out this.price);
|
this.success = int.TryParse(j["price"], out this.price);
|
||||||
this.success = int.TryParse(j["winPrice"], out this.win_price);
|
this.success = int.TryParse(j["winPrice"], out this.winPrice);
|
||||||
this.success = int.TryParse(j["bids"], out this.bids);
|
this.success = int.TryParse(j["bids"], out this.bids);
|
||||||
|
|
||||||
if (String.IsNullOrWhiteSpace(this.name)) {
|
if (String.IsNullOrWhiteSpace(this.name)) {
|
||||||
this.name = this.original_name;
|
this.name = this.originalName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// as far as i can tell, neither the `pageData` nor the `conf` variables in the html seem to store whether or not the auction uses automatic extension
|
// as far as i can tell, neither the `pageData` nor the `conf` variables in the html seem to store whether or not the auction uses automatic extension
|
||||||
|
@ -75,17 +100,17 @@ namespace Buypeeb {
|
||||||
var autoExtensionCheck = new Regex(@"自動延長.+\n.+>(.+)<");
|
var autoExtensionCheck = new Regex(@"自動延長.+\n.+>(.+)<");
|
||||||
m = rx.Match(html);
|
m = rx.Match(html);
|
||||||
if (m.Groups[1].Value != null) {
|
if (m.Groups[1].Value != null) {
|
||||||
this.auto_extension = (m.Groups[1].Value == "あり");
|
this.autoExtension = (m.Groups[1].Value == "あり");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string PriceAUD(bool win = false) {
|
public string PriceAUD(bool win = false) {
|
||||||
double aud = win ? this.win_price / 75.0 : this.price / 75.0;
|
double aud = win ? this.winPrice / 75.0 : this.price / 75.0;
|
||||||
return $"${aud:f2}";
|
return $"${aud:f2}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public string PriceJPY(bool win = false) {
|
public string PriceJPY(bool win = false) {
|
||||||
return win ? $"¥{this.win_price}" : $"¥{this.price}";
|
return win ? $"¥{this.winPrice}" : $"¥{this.price}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
176
MainWindow.cs
176
MainWindow.cs
|
@ -49,13 +49,24 @@ namespace Buypeeb {
|
||||||
|
|
||||||
// TODO: whenever we get something from the builder, cache it for later
|
// TODO: whenever we get something from the builder, cache it for later
|
||||||
// that way we don't need to constantly do "builder.GetObject"s
|
// 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...
|
||||||
|
|
||||||
static SemaphoreSlim tasklimit = new SemaphoreSlim(4);
|
private Box selectionViewBox;
|
||||||
|
private Label endingLabel;
|
||||||
|
|
||||||
private Listing SelectedItem {
|
// ...to here.
|
||||||
|
|
||||||
|
static SemaphoreSlim taskLimit = new SemaphoreSlim(4);
|
||||||
|
|
||||||
|
private YahooAuctionsItem selectedItem {
|
||||||
get {
|
get {
|
||||||
|
if (this.itemTreeView.Selection.CountSelectedRows() == 0) {
|
||||||
|
// avoids incurring the wrath of Gtk-CRITICAL **
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
this.itemTreeView.Selection.GetSelected(out TreeIter iter);
|
this.itemTreeView.Selection.GetSelected(out TreeIter iter);
|
||||||
return (Listing)this.itemTreeView.Model.GetValue(iter, 0);
|
return (YahooAuctionsItem)this.itemTreeView.Model.GetValue(iter, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,10 +105,12 @@ namespace Buypeeb {
|
||||||
builder.Autoconnect(this);
|
builder.Autoconnect(this);
|
||||||
|
|
||||||
this.statusLabel = (Label)builder.GetObject("LabelStatus");
|
this.statusLabel = (Label)builder.GetObject("LabelStatus");
|
||||||
|
this.selectionViewBox = (Box)builder.GetObject("SelectionViewBox");
|
||||||
|
this.endingLabel = (Label)builder.GetObject("LabelSelectedEnding");
|
||||||
|
|
||||||
// bind treeview columns to watchlist instead of needing to manually sync its liststore
|
// bind treeview columns to watchlist instead of needing to manually sync its liststore
|
||||||
this.itemTreeView = (TreeView)builder.GetObject("TreeViewItems");
|
this.itemTreeView = (TreeView)builder.GetObject("TreeViewItems");
|
||||||
this.items = new ListStore(typeof(Listing));
|
this.items = new ListStore(typeof(YahooAuctionsItem));
|
||||||
this.RenderList();
|
this.RenderList();
|
||||||
|
|
||||||
this.itemTreeView.Model = this.items;
|
this.itemTreeView.Model = this.items;
|
||||||
|
@ -115,11 +128,12 @@ namespace Buypeeb {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.UpdateItems();
|
this.UpdateItems();
|
||||||
|
GLib.Timeout.Add(1000, new GLib.TimeoutHandler(UpdateSelectionEndTime));
|
||||||
|
|
||||||
DeleteEvent += Window_Shutdown;
|
DeleteEvent += WindowShutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Window_Shutdown(object sender, DeleteEventArgs args) {
|
private void WindowShutdown(object sender, DeleteEventArgs args) {
|
||||||
SaveSettings();
|
SaveSettings();
|
||||||
Application.Quit();
|
Application.Quit();
|
||||||
}
|
}
|
||||||
|
@ -136,7 +150,7 @@ namespace Buypeeb {
|
||||||
this.itemTreeView.Model.GetIterFirst(out iter);
|
this.itemTreeView.Model.GetIterFirst(out iter);
|
||||||
|
|
||||||
for (int i = 0; i < this.itemTreeView.Model.IterNChildren(); i++) {
|
for (int i = 0; i < this.itemTreeView.Model.IterNChildren(); i++) {
|
||||||
var x = (Listing)this.itemTreeView.Model.GetValue(iter, 0);
|
var x = (YahooAuctionsItem)this.itemTreeView.Model.GetValue(iter, 0);
|
||||||
if (x.id == id) {
|
if (x.id == id) {
|
||||||
return (this.itemTreeView.Model.GetPath(iter), iter);
|
return (this.itemTreeView.Model.GetPath(iter), iter);
|
||||||
}
|
}
|
||||||
|
@ -177,17 +191,16 @@ namespace Buypeeb {
|
||||||
|
|
||||||
using (WebClient client = new WebClient()) {
|
using (WebClient client = new WebClient()) {
|
||||||
// TODO: download should have timeout
|
// TODO: download should have timeout
|
||||||
// item.Update(client.DownloadString(item.url));
|
item.Update(client.DownloadString(item.url));
|
||||||
item.Update(File.ReadAllText("yahoo.html"));
|
// item.Update(File.ReadAllText("yahoo.html"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Gtk.Application.Invoke(delegate {
|
Gtk.Application.Invoke(delegate {
|
||||||
var pathAndIter = this.GetRow(id);
|
var pathAndIter = this.GetRow(id);
|
||||||
this.items.EmitRowChanged(pathAndIter.path, pathAndIter.iter);
|
this.items.EmitRowChanged(pathAndIter.path, pathAndIter.iter);
|
||||||
if (item == this.SelectedItem) {
|
if (item == this.selectedItem) {
|
||||||
// if the user has this item selected and it just became ready, enable the selection box
|
// if the user has this item selected and it just became ready, enable the selection box
|
||||||
var s = (Box)this.builder.GetObject("SelectionViewBox");
|
this.selectionViewBox.Sensitive = true;
|
||||||
s.Sensitive = true;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -195,19 +208,22 @@ namespace Buypeeb {
|
||||||
Console.WriteLine($"{id} updated.");
|
Console.WriteLine($"{id} updated.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateItem(string id) {
|
private void UpdateItem(string id, bool force = false) {
|
||||||
// don't start a new task if there are more than [tasklimit] tasks currently running
|
// 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
|
// this makes sure we don't make 1000 simultaneous requests to yahoo auctions if there are 1000 items on the watchlist
|
||||||
this.settings.watchlist[id].ready = false;
|
if (this.settings.watchlist[id].updatedRecently && !force) {
|
||||||
tasklimit.Wait();
|
// the item has been updated recently, and force is not true
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
taskLimit.Wait();
|
||||||
var t = Task.Factory.StartNew(() => {
|
var t = Task.Factory.StartNew(() => {
|
||||||
this.UpdateThread(id);
|
this.UpdateThread(id);
|
||||||
}).ContinueWith(task => { tasklimit.Release(); });
|
}).ContinueWith(task => { taskLimit.Release(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateItems() {
|
private void UpdateItems() {
|
||||||
var s = (Box)this.builder.GetObject("SelectionViewBox");
|
this.selectionViewBox.Sensitive = false;
|
||||||
s.Sensitive = false;
|
|
||||||
|
|
||||||
var t = Task.Factory.StartNew(() => {
|
var t = Task.Factory.StartNew(() => {
|
||||||
foreach (var item in this.settings.watchlist) {
|
foreach (var item in this.settings.watchlist) {
|
||||||
|
@ -219,31 +235,29 @@ namespace Buypeeb {
|
||||||
|
|
||||||
private void UpdateSelectionView() {
|
private void UpdateSelectionView() {
|
||||||
// get the currently selected item
|
// get the currently selected item
|
||||||
var item = this.SelectedItem;
|
var item = this.selectedItem;
|
||||||
var s = (Box)this.builder.GetObject("SelectionViewBox");
|
|
||||||
var infobox = (Box)this.builder.GetObject("SelectionInfoBox");
|
var infobox = (Box)this.builder.GetObject("SelectionInfoBox");
|
||||||
|
|
||||||
|
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
s.Sensitive = false;
|
this.selectionViewBox.Sensitive = false;
|
||||||
infobox.Visible = false;
|
infobox.Visible = false;
|
||||||
var l = (Label)this.builder.GetObject("LabelSelectedName");
|
var l = (Label)this.builder.GetObject("LabelSelectedName");
|
||||||
l.Text = "buypeeb";
|
l.Text = "buypeeb";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Sensitive = item.ready;
|
this.selectionViewBox.Sensitive = item.ready;
|
||||||
infobox.Visible = true;
|
infobox.Visible = true;
|
||||||
|
|
||||||
var info = new Dictionary<string, string>();
|
var info = new Dictionary<string, string>();
|
||||||
info.Add("Name", item.name);
|
info.Add("Name", item.name);
|
||||||
info.Add("YahooName", item.original_name);
|
info.Add("YahooName", item.originalName);
|
||||||
info.Add("Price", item.PriceJPY());
|
info.Add("Price", item.PriceJPY());
|
||||||
info.Add("PriceAUD", item.PriceAUD());
|
info.Add("PriceAUD", item.PriceAUD());
|
||||||
info.Add("Ending", "whenever");
|
info.Add("Ending", "...");
|
||||||
info.Add("Bids", $"{item.bids}");
|
info.Add("Bids", $"{item.bids}");
|
||||||
info.Add("BuyItNow", item.win_price == 0 ? "No" : $"¥{item.PriceJPY(true)} (${item.PriceAUD(true)})");
|
info.Add("BuyItNow", item.winPrice == 0 ? "No" : $"¥{item.PriceJPY(true)} (${item.PriceAUD(true)})");
|
||||||
info.Add("AutoExtension", item.auto_extension ? "Yes" : "No");
|
info.Add("AutoExtension", item.autoExtension ? "Yes" : "No");
|
||||||
info.Add("LastUpdated", "Last updated: heeeenlo");
|
info.Add("LastUpdated", "Last updated: heeeenlo");
|
||||||
|
|
||||||
foreach (var row in info) {
|
foreach (var row in info) {
|
||||||
|
@ -267,6 +281,22 @@ namespace Buypeeb {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MessageDialog OkCancelDialogue(string message) {
|
||||||
|
var md = new MessageDialog(
|
||||||
|
parent_window: this,
|
||||||
|
flags: DialogFlags.DestroyWithParent | DialogFlags.Modal,
|
||||||
|
type: MessageType.Question,
|
||||||
|
bt: ButtonsType.OkCancel,
|
||||||
|
format: message
|
||||||
|
);
|
||||||
|
md.KeepAbove = true;
|
||||||
|
md.Resizable = false;
|
||||||
|
md.FocusOnMap = true;
|
||||||
|
md.Title = "buypeeb";
|
||||||
|
|
||||||
|
return md;
|
||||||
|
}
|
||||||
|
|
||||||
// show a simple entry dialogue that allows the user to enter text and either cancel or submit it
|
// show a simple entry dialogue that allows the user to enter text and either cancel or submit it
|
||||||
private (Boolean accepted, string response) EntryDialogue(string title = "Buypeeb", string message = "Hi there!", string prefill = null) {
|
private (Boolean accepted, string response) EntryDialogue(string title = "Buypeeb", string message = "Hi there!", string prefill = null) {
|
||||||
Dialog ed = new Dialog(title, null, DialogFlags.DestroyWithParent | DialogFlags.Modal, "Cancel", ResponseType.Cancel, "OK", ResponseType.Ok);
|
Dialog ed = new Dialog(title, null, DialogFlags.DestroyWithParent | DialogFlags.Modal, "Cancel", ResponseType.Cancel, "OK", ResponseType.Ok);
|
||||||
|
@ -289,7 +319,7 @@ namespace Buypeeb {
|
||||||
ed.ContentArea.MarginTop = 5;
|
ed.ContentArea.MarginTop = 5;
|
||||||
ed.ContentArea.MarginStart = 5;
|
ed.ContentArea.MarginStart = 5;
|
||||||
ed.ContentArea.MarginEnd = 5;
|
ed.ContentArea.MarginEnd = 5;
|
||||||
ed.ActionArea.MarginBottom = 5; // TODO: apparently actionarea is obsolete
|
ed.MarginBottom = 5;
|
||||||
|
|
||||||
ResponseType accepted = (ResponseType)ed.Run();
|
ResponseType accepted = (ResponseType)ed.Run();
|
||||||
string response = edEntry.Text;
|
string response = edEntry.Text;
|
||||||
|
@ -344,14 +374,7 @@ namespace Buypeeb {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ButtonQuitClicked(object sender, EventArgs a) {
|
private void ButtonQuitClicked(object sender, EventArgs a) {
|
||||||
MessageDialog md = new MessageDialog(
|
var md = this.OkCancelDialogue("Are you sure you want to quit?");
|
||||||
parent_window: this,
|
|
||||||
flags: DialogFlags.DestroyWithParent | DialogFlags.Modal,
|
|
||||||
type: MessageType.Question,
|
|
||||||
bt: ButtonsType.OkCancel,
|
|
||||||
format: "Are you sure you want to quit?"
|
|
||||||
);
|
|
||||||
md.KeepAbove = true;
|
|
||||||
|
|
||||||
ResponseType response = (ResponseType)md.Run();
|
ResponseType response = (ResponseType)md.Run();
|
||||||
md.Dispose();
|
md.Dispose();
|
||||||
|
@ -366,24 +389,17 @@ namespace Buypeeb {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ButtonViewBuyeeClicked(object sender, EventArgs a) {
|
private void ButtonViewBuyeeClicked(object sender, EventArgs a) {
|
||||||
this.OpenUrl(this.SelectedItem.buyee_url);
|
this.OpenUrl(this.selectedItem.buyeeUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ButtonViewYahooClicked(object sender, EventArgs a) {
|
private void ButtonViewYahooClicked(object sender, EventArgs a) {
|
||||||
this.OpenUrl(this.SelectedItem.url);
|
this.OpenUrl(this.selectedItem.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ButtonSelectedRemoveClicked(object sender, EventArgs a) {
|
private void ButtonSelectedRemoveClicked(object sender, EventArgs a) {
|
||||||
var item = this.SelectedItem;
|
var item = this.selectedItem;
|
||||||
|
|
||||||
MessageDialog md = new MessageDialog(
|
var md = this.OkCancelDialogue($"Are you sure you want to remove the item \"{item.name}\"?"); // TODO: this looks bad being all on one line
|
||||||
parent_window: this,
|
|
||||||
flags: DialogFlags.DestroyWithParent | DialogFlags.Modal,
|
|
||||||
type: MessageType.Question,
|
|
||||||
bt: ButtonsType.OkCancel,
|
|
||||||
format: $"Are you sure you want to remove the item \"{item.name}\"?" // TODO: this looks bad being all on one line
|
|
||||||
);
|
|
||||||
md.KeepAbove = true;
|
|
||||||
|
|
||||||
ResponseType response = (ResponseType)md.Run();
|
ResponseType response = (ResponseType)md.Run();
|
||||||
md.Dispose();
|
md.Dispose();
|
||||||
|
@ -394,7 +410,7 @@ namespace Buypeeb {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ButtonSelectedRenameClicked(object sender, EventArgs a) {
|
private void ButtonSelectedRenameClicked(object sender, EventArgs a) {
|
||||||
var item = this.SelectedItem;
|
var item = this.selectedItem;
|
||||||
(bool accepted, string response) = this.EntryDialogue("Rename item", $"Enter a new name for the item \"{item.name}\".", item.name);
|
(bool accepted, string response) = this.EntryDialogue("Rename item", $"Enter a new name for the item \"{item.name}\".", item.name);
|
||||||
if (accepted) {
|
if (accepted) {
|
||||||
item.name = response;
|
item.name = response;
|
||||||
|
@ -403,32 +419,80 @@ namespace Buypeeb {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ButtonSelectedUpdateClicked(object sender, EventArgs args) {
|
private void ButtonSelectedUpdateClicked(object sender, EventArgs args) {
|
||||||
var s = (Box)this.builder.GetObject("SelectionViewBox");
|
this.selectionViewBox.Sensitive = false;
|
||||||
s.Sensitive = false;
|
this.UpdateItem(this.selectedItem.id);
|
||||||
this.UpdateItem(this.SelectedItem.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// column renderers
|
// column renderers
|
||||||
|
|
||||||
private void RenderColumnName(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter) {
|
private void RenderColumnName(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter) {
|
||||||
Listing item = (Listing)model.GetValue(iter, 0);
|
YahooAuctionsItem item = (YahooAuctionsItem)model.GetValue(iter, 0);
|
||||||
(cell as Gtk.CellRendererText).Text = item.name ?? "Loading...";
|
(cell as Gtk.CellRendererText).Text = item.name ?? "Loading...";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderColumnPriceYen(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter) {
|
private void RenderColumnPriceYen(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter) {
|
||||||
Listing item = (Listing)model.GetValue(iter, 0);
|
YahooAuctionsItem item = (YahooAuctionsItem)model.GetValue(iter, 0);
|
||||||
(cell as Gtk.CellRendererText).Text = item.ready ? item.PriceJPY() : "...";
|
(cell as Gtk.CellRendererText).Text = item.ready ? item.PriceJPY() : "...";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderColumnPriceAUD(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter) {
|
private void RenderColumnPriceAUD(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter) {
|
||||||
Listing item = (Listing)model.GetValue(iter, 0);
|
YahooAuctionsItem item = (YahooAuctionsItem)model.GetValue(iter, 0);
|
||||||
(cell as Gtk.CellRendererText).Text = item.ready ? item.PriceAUD() : "...";
|
(cell as Gtk.CellRendererText).Text = item.ready ? item.PriceAUD() : "...";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderColumnEnding(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter) {
|
private void RenderColumnEnding(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter) {
|
||||||
Listing item = (Listing)model.GetValue(iter, 0);
|
// TODO: get these columns to redraw every minute so the info doesn't become stale
|
||||||
(cell as Gtk.CellRendererText).Text = item.ready ? "whatever" : "...";
|
YahooAuctionsItem item = (YahooAuctionsItem)model.GetValue(iter, 0);
|
||||||
|
string ending = "";
|
||||||
|
if (item.ready) {
|
||||||
|
var now = DateTime.Now;
|
||||||
|
var end = item.endDate.ToLocalTime();
|
||||||
|
// TODO: should we show the year if the auction ends next year? 0uo
|
||||||
|
if (end.DayOfYear != now.DayOfYear) {
|
||||||
|
// 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 (this.settings.displaySecondsInList) {
|
||||||
|
// add the seconds on to the end
|
||||||
|
ending += end.ToString(":ss");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(cell as Gtk.CellRendererText).Text = item.ready ? ending : "...";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// timers
|
||||||
|
|
||||||
|
private bool UpdateSelectionEndTime() {
|
||||||
|
if (!this.selectionViewBox.IsSensitive) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var item = this.selectedItem;
|
||||||
|
if (!item.ready) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string ending = "";
|
||||||
|
if (item.available) {
|
||||||
|
var now = DateTime.Now;
|
||||||
|
var end = item.endDate.ToLocalTime();
|
||||||
|
var span = end.Subtract(now);
|
||||||
|
|
||||||
|
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 {
|
||||||
|
ending = "Auction has ended";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.endingLabel.Text = ending;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,15 +8,16 @@ namespace Buypeeb {
|
||||||
public int favouriteUpdateInterval { get; set; } = 5 * 60;
|
public int favouriteUpdateInterval { get; set; } = 5 * 60;
|
||||||
public int updateIntervalCritical { get; set; } = 60;
|
public int updateIntervalCritical { get; set; } = 60;
|
||||||
public int favouriteUpdateIntervalCritical { get; set; } = 30;
|
public int favouriteUpdateIntervalCritical { get; set; } = 30;
|
||||||
|
public bool displaySecondsInList { get; set; } = true;
|
||||||
|
|
||||||
public Dictionary<string, Listing> watchlist {
|
public Dictionary<string, YahooAuctionsItem> watchlist {
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Settings() {
|
public Settings() {
|
||||||
if (this.watchlist == null) {
|
if (this.watchlist == null) {
|
||||||
// either this is the first time the program has been run, or there's something wrong with userdata.json
|
// either this is the first time the program has been run, or there's something wrong with userdata.json
|
||||||
this.watchlist = new Dictionary<string, Listing>();
|
this.watchlist = new Dictionary<string, YahooAuctionsItem>();
|
||||||
// this.Watch("https://buypeeb.biz/whatever/k12345", "my thingy");
|
// this.Watch("https://buypeeb.biz/whatever/k12345", "my thingy");
|
||||||
// this.Watch("https://buypeeb.biz/whatever/z09876", "your thingy");
|
// this.Watch("https://buypeeb.biz/whatever/z09876", "your thingy");
|
||||||
// this.Watch("https://buypeeb.biz/whatever/h55555", "our thingy");
|
// this.Watch("https://buypeeb.biz/whatever/h55555", "our thingy");
|
||||||
|
@ -28,10 +29,10 @@ namespace Buypeeb {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Listing Watch(string url, string name) {
|
public YahooAuctionsItem Watch(string url, string name) {
|
||||||
string id = BuypeebApp.IDFromURL(url);
|
string id = BuypeebApp.IDFromURL(url);
|
||||||
Console.WriteLine(id);
|
Console.WriteLine(id);
|
||||||
this.watchlist[id] = new Listing(id, name);
|
this.watchlist[id] = new YahooAuctionsItem(id, name);
|
||||||
return this.watchlist[id];
|
return this.watchlist[id];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- Generated with glade 3.36.0 -->
|
<!-- Generated with glade 3.22.2 -->
|
||||||
<interface>
|
<interface>
|
||||||
<requires lib="gtk+" version="3.22"/>
|
<requires lib="gtk+" version="3.22"/>
|
||||||
<object class="GtkDialog" id="DialogueAdd">
|
<object class="GtkDialog" id="DialogueAdd">
|
||||||
|
@ -8,8 +8,12 @@
|
||||||
<property name="modal">True</property>
|
<property name="modal">True</property>
|
||||||
<property name="window_position">center-on-parent</property>
|
<property name="window_position">center-on-parent</property>
|
||||||
<property name="default_width">320</property>
|
<property name="default_width">320</property>
|
||||||
|
<property name="destroy_with_parent">True</property>
|
||||||
<property name="type_hint">dialog</property>
|
<property name="type_hint">dialog</property>
|
||||||
<property name="gravity">center</property>
|
<property name="gravity">center</property>
|
||||||
|
<child type="titlebar">
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox">
|
<object class="GtkBox">
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
@ -150,8 +154,5 @@
|
||||||
<action-widget response="-6">ButtonAddCancel</action-widget>
|
<action-widget response="-6">ButtonAddCancel</action-widget>
|
||||||
<action-widget response="-5">ButtonAddOK</action-widget>
|
<action-widget response="-5">ButtonAddOK</action-widget>
|
||||||
</action-widgets>
|
</action-widgets>
|
||||||
<child type="titlebar">
|
|
||||||
<placeholder/>
|
|
||||||
</child>
|
|
||||||
</object>
|
</object>
|
||||||
</interface>
|
</interface>
|
||||||
|
|
Loading…
Reference in a new issue