Compare commits

..

No commits in common. "e81a47d83ff16a7799f4a12e01248d4d49e4ab87" and "b2f5288c4b8cc48057131b360f7d8b795b506645" have entirely different histories.

4 changed files with 75 additions and 94 deletions

View File

@ -1,52 +1,38 @@
namespace StudySystemClient {
public class ActivitiesView : ListView<ActivityCard> {
public class ActivitiesView : CardArea<ActivityCard>, IRefreshable {
private const uint REFRESH_PERIOD_MS = 30000;
private Client client;
private Updater updater;
private Refresher refresher;
private bool pending_sort;
public ActivitiesView(Client client) {
base();
add_css_class("card-container");
this.client = client;
updater = new Updater(this, client);
refresher = new Refresher(updater, REFRESH_PERIOD_MS);
refresher = new Refresher(this, REFRESH_PERIOD_MS);
pending_sort = false;
this.map.connect(() => {
updater.refresh.begin();
refresher.start();
refresh.begin();
});
}
internal IterableBox.Iterator<Type, ActivityCard> iterator() {
return container.iterator();
}
internal void new_card(Activity activity) {
var card = new ActivityCard(activity);
card.session_logged.connect(log_session);
card.log_closed.connect(handle_pending_sort);
container.append(card);
}
internal void remove_card(ActivityCard card) {
container.remove(card);
}
internal void sort() {
if (log_in_progress())
pending_sort = true;
else
container.sort(compare_cards);
private async void refresh() {
if (!client.connected)
return;
try {
var activities = yield client.list_activities();
update_cards(activities);
} catch (ClientError e) {
stderr.printf("Error refreshing activities: %s\n",
e.message);
}
}
private async void log_session(string subject, ActivityType type,
int minutes) {
try {
yield client.log_session(subject, type, minutes);
yield updater.refresh();
yield refresh();
} catch (ClientError e) {
stderr.printf("Error logging session: %s\n", e.message);
}
@ -59,6 +45,54 @@ namespace StudySystemClient {
}
}
private void update_cards(Array<Activity> activities) {
update_existing_cards(activities);
for (uint i = 0; i < activities.length; ++i)
create_card(activities.index(i));
if (log_in_progress())
pending_sort = true;
else
container.sort(compare_cards);
}
private void update_existing_cards(Array<Activity> activities) {
var to_remove = new List<ActivityCard>();
foreach (var card in container) {
if (!update_existing_card(card, activities))
to_remove.append(card);
}
foreach (var card in to_remove)
container.remove(card);
}
private bool update_existing_card(ActivityCard card,
Array<Activity> activities) {
var activity_index = find_activity(card, activities);
if (activity_index == null)
return false;
var priority = activities.index(activity_index).priority;
card.update_priority(priority);
activities._remove_index_fast(activity_index);
return true;
}
private uint? find_activity(ActivityCard card,
Array<Activity> activities) {
for (uint i = 0; i < activities.length; ++i) {
if (activities.index(i).subject == card.activity.subject
&& activities.index(i).type == card.activity.type)
return i;
}
return null;
}
private void create_card(Activity activity) {
var card = new ActivityCard(activity);
card.session_logged.connect(log_session);
card.log_closed.connect(handle_pending_sort);
container.append(card);
}
private bool log_in_progress() {
foreach (var card in container) {
if (card.logging)
@ -77,64 +111,4 @@ namespace StudySystemClient {
return 0;
}
}
private class Updater : IRefreshable {
private weak ActivitiesView target;
private Client client;
public Updater(ActivitiesView target, Client client) {
this.target = target;
this.client = client;
}
public async void refresh() {
if (!client.connected || target == null)
return;
try {
var activities = yield client.list_activities();
apply_update(activities);
target.sort();
} catch (ClientError e) {
stderr.printf("Error refreshing activities: %s\n",
e.message);
}
}
private void apply_update(Array<Activity> activities) {
update_existing(activities);
for (uint i = 0; i < activities.length; ++i)
target.new_card(activities.index(i));
}
private void update_existing(Array<Activity> activities) {
var to_remove = new List<ActivityCard>();
foreach (var card in target) {
if (!update_card(card, activities))
to_remove.append(card);
}
foreach (var card in to_remove)
target.remove_card(card);
}
private bool update_card(ActivityCard card,
Array<Activity> activities) {
var activity_index = find_activity(card, activities);
if (activity_index == null)
return false;
var priority = activities.index(activity_index).priority;
card.update_priority(priority);
activities._remove_index_fast(activity_index);
return true;
}
private static uint? find_activity(ActivityCard card,
Array<Activity> activities) {
for (uint i = 0; i < activities.length; ++i) {
if (activities.index(i).subject == card.activity.subject
&& activities.index(i).type == card.activity.type)
return i;
}
return null;
}
}
}

View File

@ -1,5 +1,5 @@
namespace StudySystemClient {
public class ActivityCard : Gtk.Frame {
public class ActivityCard : Card {
public signal void session_logged(string subject, ActivityType type,
int minutes);
public signal void log_closed();
@ -10,8 +10,7 @@ namespace StudySystemClient {
private Gtk.Label priority_label;
public ActivityCard(Activity activity) {
hexpand = true;
add_css_class("card");
base();
this.activity = activity;
logging = false;

View File

@ -1,8 +1,15 @@
namespace StudySystemClient {
public class ListView<T> : Gtk.Box {
public class Card : Gtk.Frame {
public Card() {
hexpand = true;
add_css_class("card");
}
}
public class CardArea<T> : Gtk.Box {
protected IterableBox<T> container;
public ListView() {
public CardArea() {
hexpand = vexpand = true;
margin_top = margin_bottom = margin_start = margin_end = 0;
@ -12,6 +19,7 @@ namespace StudySystemClient {
var scrolled_window = new Gtk.ScrolledWindow();
scrolled_window.hscrollbar_policy = Gtk.PolicyType.NEVER;
scrolled_window.hexpand = scrolled_window.vexpand = true;
scrolled_window.add_css_class("card-container");
scrolled_window.set_child(container);
append(scrolled_window);

View File

@ -13,11 +13,11 @@ lib = library(
'activities_view.vala',
'activity.vala',
'activity_card.vala',
'card.vala',
'client.vala',
'connection.vala',
'der.vala',
'iterable_box.vala',
'list_view.vala',
'main_window.vala',
'periodic.vala',
'refresher.vala',