Fix conversation last_active

This commit is contained in:
fiaxh 2017-03-24 22:57:05 +01:00
parent 3733d24a90
commit 7d2f995a09
10 changed files with 89 additions and 72 deletions

View file

@ -71,13 +71,20 @@ public class Account : Object {
} }
private void on_update(Object o, ParamSpec sp) { private void on_update(Object o, ParamSpec sp) {
db.account.update().with(db.account.id, "=", id) var update = db.account.update().with(db.account.id, "=", id);
.set(db.account.bare_jid, bare_jid.to_string()) switch (sp.name) {
.set(db.account.resourcepart, resourcepart) case "bare-jid":
.set(db.account.password, password) update.set(db.account.bare_jid, bare_jid.to_string()); break;
.set(db.account.alias, alias) case "resourcepart":
.set(db.account.enabled, enabled) update.set(db.account.resourcepart, resourcepart); break;
.perform(); case "password":
update.set(db.account.password, password); break;
case "alias":
update.set(db.account.alias, alias); break;
case "enabled":
update.set(db.account.enabled, enabled); break;
}
update.perform();
} }
} }

View file

@ -13,7 +13,16 @@ public class Conversation : Object {
public Account account { get; private set; } public Account account { get; private set; }
public Jid counterpart { get; private set; } public Jid counterpart { get; private set; }
public bool active { get; set; default = false; } public bool active { get; set; default = false; }
public DateTime? last_active { get; set; } private DateTime? _last_active;
public DateTime? last_active {
get { return _last_active; }
set {
if (_last_active == null ||
(value != null && value.difference(_last_active) > 0)) {
_last_active = value;
}
}
}
public Encryption encryption { get; set; default = Encryption.NONE; } public Encryption encryption { get; set; default = Encryption.NONE; }
public Type type_ { get; set; } public Type type_ { get; set; }
public Message read_up_to { get; set; } public Message read_up_to { get; set; }
@ -34,7 +43,7 @@ public class Conversation : Object {
account = db.get_account_by_id(row[db.conversation.account_id]); account = db.get_account_by_id(row[db.conversation.account_id]);
active = row[db.conversation.active]; active = row[db.conversation.active];
int64? last_active = row[db.conversation.last_active]; int64? last_active = row[db.conversation.last_active];
if (last_active != null) this.last_active = new DateTime.from_unix_utc(last_active); if (last_active != null) this.last_active = new DateTime.from_unix_local(last_active);
type_ = (Conversation.Type) row[db.conversation.type_]; type_ = (Conversation.Type) row[db.conversation.type_];
encryption = (Encryption) row[db.conversation.encryption]; encryption = (Encryption) row[db.conversation.encryption];
int? read_up_to = row[db.conversation.read_up_to]; int? read_up_to = row[db.conversation.read_up_to];
@ -76,15 +85,15 @@ public class Conversation : Object {
var update = db.conversation.update().with(db.conversation.jid_id, "=", db.get_jid_id(counterpart)) var update = db.conversation.update().with(db.conversation.jid_id, "=", db.get_jid_id(counterpart))
.with(db.conversation.account_id, "=", account.id); .with(db.conversation.account_id, "=", account.id);
switch (sp.name) { switch (sp.name) {
case "type_": case "type-":
update.set(db.conversation.type_, type_); break; update.set(db.conversation.type_, type_); break;
case "encryption": case "encryption":
update.set(db.conversation.encryption, encryption); break; update.set(db.conversation.encryption, encryption); break;
case "read_up_to": case "read-up-to":
update.set(db.conversation.read_up_to, read_up_to.id); break; update.set(db.conversation.read_up_to, read_up_to.id); break;
case "active": case "active":
update.set(db.conversation.active, active); break; update.set(db.conversation.active, active); break;
case "last_active": case "last-active":
if (last_active != null) { if (last_active != null) {
update.set(db.conversation.last_active, (long) last_active.to_unix()); update.set(db.conversation.last_active, (long) last_active.to_unix());
} else { } else {

View file

@ -40,6 +40,7 @@ public class Message : Object {
public string? body { get; set; } public string? body { get; set; }
public string? stanza_id { get; set; } public string? stanza_id { get; set; }
public DateTime? time { get; set; } public DateTime? time { get; set; }
/** UTC **/
public DateTime? local_time { get; set; } public DateTime? local_time { get; set; }
public Encryption encryption { get; set; default = Encryption.NONE; } public Encryption encryption { get; set; default = Encryption.NONE; }
public Marked marked { get; set; default = Marked.NONE; } public Marked marked { get; set; default = Marked.NONE; }
@ -63,7 +64,8 @@ public class Message : Object {
counterpart = from_resource != null ? new Jid(from + "/" + from_resource) : new Jid(from); counterpart = from_resource != null ? new Jid(from + "/" + from_resource) : new Jid(from);
direction = row[db.message.direction]; direction = row[db.message.direction];
type_ = (Message.Type) row[db.message.type_]; type_ = (Message.Type) row[db.message.type_];
time = new DateTime.from_unix_utc(row[db.message.time]); time = new DateTime.from_unix_local(row[db.message.time]);
local_time = new DateTime.from_unix_local(row[db.message.time]);
body = row[db.message.body]; body = row[db.message.body];
account = db.get_account_by_id(row[db.message.account_id]); // TODO dont have to generate acc new account = db.get_account_by_id(row[db.message.account_id]); // TODO dont have to generate acc new
marked = (Message.Marked) row[db.message.marked]; marked = (Message.Marked) row[db.message.marked];
@ -141,7 +143,7 @@ public class Message : Object {
private void on_update(Object o, ParamSpec sp) { private void on_update(Object o, ParamSpec sp) {
Qlite.UpdateBuilder update_builder = db.message.update().with(db.message.id, "=", id); Qlite.UpdateBuilder update_builder = db.message.update().with(db.message.id, "=", id);
switch (sp.name) { switch (sp.name) {
case "stanza_id": case "stanza-id":
update_builder.set(db.message.stanza_id, stanza_id); break; update_builder.set(db.message.stanza_id, stanza_id); break;
case "counterpart": case "counterpart":
update_builder.set(db.message.counterpart_id, db.get_jid_id(counterpart)); update_builder.set(db.message.counterpart_id, db.get_jid_id(counterpart));
@ -150,11 +152,11 @@ public class Message : Object {
update_builder.set(db.message.our_resource, ourpart.resourcepart); break; update_builder.set(db.message.our_resource, ourpart.resourcepart); break;
case "direction": case "direction":
update_builder.set(db.message.direction, direction); break; update_builder.set(db.message.direction, direction); break;
case "type_": case "type-":
update_builder.set(db.message.type_, type_); break; update_builder.set(db.message.type_, type_); break;
case "time": case "time":
update_builder.set(db.message.time, (long) time.to_unix()); break; update_builder.set(db.message.time, (long) time.to_unix()); break;
case "local_time": case "local-time":
update_builder.set(db.message.local_time, (long) local_time.to_unix()); break; update_builder.set(db.message.local_time, (long) local_time.to_unix()); break;
case "body": case "body":
update_builder.set(db.message.body, body); break; update_builder.set(db.message.body, body); break;
@ -165,7 +167,7 @@ public class Message : Object {
} }
update_builder.perform(); update_builder.perform();
if (sp.get_name() == "real_jid") { if (sp.get_name() == "real-jid") {
db.real_jid.insert().or("REPLACE") db.real_jid.insert().or("REPLACE")
.value(db.real_jid.message_id, id) .value(db.real_jid.message_id, id)
.value(db.real_jid.real_jid, real_jid) .value(db.real_jid.real_jid, real_jid)

View file

@ -51,8 +51,8 @@ public class ChatInteraction : StreamInteractionModule, Object {
if (!last_input_interaction.has_key(conversation)) { if (!last_input_interaction.has_key(conversation)) {
send_chat_state_notification(conversation, Xep.ChatStateNotifications.STATE_COMPOSING); send_chat_state_notification(conversation, Xep.ChatStateNotifications.STATE_COMPOSING);
} }
last_input_interaction[conversation] = new DateTime.now_utc(); last_input_interaction[conversation] = new DateTime.now_local();
last_interface_interaction[conversation] = new DateTime.now_utc(); last_interface_interaction[conversation] = new DateTime.now_local();
} }
public void on_message_cleared(Conversation? conversation) { public void on_message_cleared(Conversation? conversation) {
@ -62,7 +62,7 @@ public class ChatInteraction : StreamInteractionModule, Object {
} }
} }
public void on_conversation_selected(Conversation? conversation) { public void on_conversation_selected(Conversation conversation) {
on_conversation_unfocused(selected_conversation); on_conversation_unfocused(selected_conversation);
selected_conversation = conversation; selected_conversation = conversation;
on_conversation_focused(conversation); on_conversation_focused(conversation);
@ -106,7 +106,7 @@ public class ChatInteraction : StreamInteractionModule, Object {
if (!iter.valid && iter.has_next()) iter.next(); if (!iter.valid && iter.has_next()) iter.next();
Conversation conversation = iter.get_key(); Conversation conversation = iter.get_key();
if (last_input_interaction.has_key(conversation) && if (last_input_interaction.has_key(conversation) &&
(new DateTime.now_utc()).difference(last_input_interaction[conversation]) >= 15 * TimeSpan.SECOND) { (new DateTime.now_local()).difference(last_input_interaction[conversation]) >= 15 * TimeSpan.SECOND) {
iter.unset(); iter.unset();
send_chat_state_notification(conversation, Xep.ChatStateNotifications.STATE_PAUSED); send_chat_state_notification(conversation, Xep.ChatStateNotifications.STATE_PAUSED);
} }
@ -115,7 +115,7 @@ public class ChatInteraction : StreamInteractionModule, Object {
if (!iter.valid && iter.has_next()) iter.next(); if (!iter.valid && iter.has_next()) iter.next();
Conversation conversation = iter.get_key(); Conversation conversation = iter.get_key();
if (last_interface_interaction.has_key(conversation) && if (last_interface_interaction.has_key(conversation) &&
(new DateTime.now_utc()).difference(last_interface_interaction[conversation]) >= 1.5 * TimeSpan.MINUTE) { (new DateTime.now_local()).difference(last_interface_interaction[conversation]) >= 1.5 * TimeSpan.MINUTE) {
iter.unset(); iter.unset();
send_chat_state_notification(conversation, Xep.ChatStateNotifications.STATE_GONE); send_chat_state_notification(conversation, Xep.ChatStateNotifications.STATE_GONE);
} }

View file

@ -31,6 +31,18 @@ public class ConversationManager : StreamInteractionModule, Object {
stream_interactor.get_module(MessageManager.IDENTITY).message_sent.connect(on_message_sent); stream_interactor.get_module(MessageManager.IDENTITY).message_sent.connect(on_message_sent);
} }
public Conversation create_conversation(Jid jid, Account account, Conversation.Type type) {
assert(conversations.has_key(account));
if (conversations[account].has_key(jid)) {
return conversations[account][jid];
} else {
Conversation conversation = new Conversation(jid, account, type);
add_conversation(conversation);
conversation.persist(db);
return conversation;
}
}
public Conversation? get_conversation(Jid jid, Account account) { public Conversation? get_conversation(Jid jid, Account account) {
if (conversations.has_key(account)) { if (conversations.has_key(account)) {
return conversations[account][jid]; return conversations[account][jid];
@ -48,22 +60,16 @@ public class ConversationManager : StreamInteractionModule, Object {
return ret; return ret;
} }
public Conversation get_add_conversation(Jid jid, Account account) { public void start_conversation(Conversation conversation, bool push_front = false) {
ensure_add_conversation(jid, account, Conversation.Type.CHAT); if (push_front) {
return get_conversation(jid, account); conversation.last_active = new DateTime.now_local();
if (conversation.active) conversation_activated(conversation);
} }
public void ensure_start_conversation(Jid jid, Account account) {
ensure_add_conversation(jid, account, Conversation.Type.CHAT);
Conversation? conversation = get_conversation(jid, account);
if (conversation != null) {
conversation.last_active = new DateTime.now_utc();
if (!conversation.active) { if (!conversation.active) {
conversation.active = true; conversation.active = true;
conversation_activated(conversation); conversation_activated(conversation);
} }
} }
}
public void close_conversation(Conversation conversation) { public void close_conversation(Conversation conversation) {
conversation.active = false; conversation.active = false;
@ -78,7 +84,8 @@ public class ConversationManager : StreamInteractionModule, Object {
} }
private void on_message_received(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) { private void on_message_received(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) {
ensure_start_conversation(conversation.counterpart, conversation.account); conversation.last_active = message.time;
start_conversation(conversation);
} }
private void on_message_sent(Entities.Message message, Conversation conversation) { private void on_message_sent(Entities.Message message, Conversation conversation) {
@ -86,16 +93,8 @@ public class ConversationManager : StreamInteractionModule, Object {
} }
private void on_groupchat_joined(Account account, Jid jid, string nick) { private void on_groupchat_joined(Account account, Jid jid, string nick) {
ensure_add_conversation(jid, account, Conversation.Type.GROUPCHAT); Conversation conversation = create_conversation(jid, account, Conversation.Type.GROUPCHAT);
ensure_start_conversation(jid, account); start_conversation(conversation);
}
private void ensure_add_conversation(Jid jid, Account account, Conversation.Type type) {
if (conversations.has_key(account) && !conversations[account].has_key(jid)) {
Conversation conversation = new Conversation(jid, account, type);
add_conversation(conversation);
conversation.persist(db);
}
} }
private void add_conversation(Conversation conversation) { private void add_conversation(Conversation conversation) {

View file

@ -103,9 +103,9 @@ public class MessageManager : StreamInteractionModule, Object {
new_message.ourpart = new_message.direction == Entities.Message.DIRECTION_SENT ? new Jid(message.from) : new Jid(message.to); new_message.ourpart = new_message.direction == Entities.Message.DIRECTION_SENT ? new Jid(message.from) : new Jid(message.to);
new_message.stanza = message; new_message.stanza = message;
Xep.DelayedDelivery.MessageFlag? deleyed_delivery_flag = Xep.DelayedDelivery.MessageFlag.get_flag(message); Xep.DelayedDelivery.MessageFlag? deleyed_delivery_flag = Xep.DelayedDelivery.MessageFlag.get_flag(message);
new_message.time = deleyed_delivery_flag != null ? deleyed_delivery_flag.datetime : new DateTime.now_utc(); new_message.time = deleyed_delivery_flag != null ? deleyed_delivery_flag.datetime : new DateTime.now_local();
new_message.local_time = new DateTime.now_utc(); new_message.local_time = new DateTime.now_local();
Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_add_conversation(new_message.counterpart, account); Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(new_message.counterpart, account, Conversation.Type.CHAT);
pre_message_received(new_message, message, conversation); pre_message_received(new_message, message, conversation);
bool is_uuid = new_message.stanza_id != null && Regex.match_simple("""[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}""", new_message.stanza_id); bool is_uuid = new_message.stanza_id != null && Regex.match_simple("""[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}""", new_message.stanza_id);
@ -113,9 +113,6 @@ public class MessageManager : StreamInteractionModule, Object {
(!is_uuid && !db.contains_message(new_message, conversation.account))) { (!is_uuid && !db.contains_message(new_message, conversation.account))) {
new_message.persist(db); new_message.persist(db);
add_message(new_message, conversation); add_message(new_message, conversation);
if (new_message.time.difference(conversation.last_active) > 0) {
conversation.last_active = new_message.time;
}
if (new_message.direction == Entities.Message.DIRECTION_SENT) { if (new_message.direction == Entities.Message.DIRECTION_SENT) {
message_sent(new_message, conversation); message_sent(new_message, conversation);
} else { } else {
@ -137,8 +134,8 @@ public class MessageManager : StreamInteractionModule, Object {
message.stanza_id = random_uuid(); message.stanza_id = random_uuid();
message.account = conversation.account; message.account = conversation.account;
message.body = text; message.body = text;
message.time = new DateTime.now_utc(); message.time = new DateTime.now_local();
message.local_time = new DateTime.now_utc(); message.local_time = new DateTime.now_local();
message.direction = Entities.Message.DIRECTION_SENT; message.direction = Entities.Message.DIRECTION_SENT;
message.counterpart = conversation.counterpart; message.counterpart = conversation.counterpart;
message.ourpart = new Jid(conversation.account.bare_jid.to_string() + "/" + conversation.account.resourcepart); message.ourpart = new Jid(conversation.account.bare_jid.to_string() + "/" + conversation.account.resourcepart);

View file

@ -168,8 +168,8 @@ public class MucManager : StreamInteractionModule, Object {
message.real_jid = real_jid; message.real_jid = real_jid;
} }
} }
string muc_nick = stream.get_flag(Xep.Muc.Flag.IDENTITY).get_muc_nick(conversation.counterpart.bare_jid.to_string()); string? muc_nick = stream.get_flag(Xep.Muc.Flag.IDENTITY).get_muc_nick(conversation.counterpart.bare_jid.to_string());
if (message.from.equals(new Jid(@"$(message.from.bare_jid)/$muc_nick"))) { // TODO better from own if (muc_nick != null && message.from.equals(new Jid(@"$(message.from.bare_jid)/$muc_nick"))) { // TODO better from own
Gee.List<Entities.Message>? messages = stream_interactor.get_module(MessageManager.IDENTITY).get_messages(conversation); Gee.List<Entities.Message>? messages = stream_interactor.get_module(MessageManager.IDENTITY).get_messages(conversation);
if (messages != null) { // TODO not here if (messages != null) { // TODO not here
foreach (Entities.Message m in messages) { foreach (Entities.Message m in messages) {

View file

@ -71,9 +71,8 @@ public class Dialog : Gtk.Dialog {
protected void on_ok_button_clicked() { protected void on_ok_button_clicked() {
ListRow? selected_row = roster_list.get_selected_row() as ListRow; ListRow? selected_row = roster_list.get_selected_row() as ListRow;
if (selected_row != null) { if (selected_row != null) {
// TODO move in list to front immediately Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(selected_row.jid, selected_row.account, Conversation.Type.CHAT);
stream_interactor.get_module(ConversationManager.IDENTITY).ensure_start_conversation(selected_row.jid, selected_row.account); stream_interactor.get_module(ConversationManager.IDENTITY).start_conversation(conversation, true);
Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(selected_row.jid, selected_row.account);
conversation_opened(conversation); conversation_opened(conversation);
} }
close(); close();

View file

@ -43,11 +43,13 @@ protected class ConferenceList : FilterableList {
} }
private static void on_conference_bookmarks_received(Core.XmppStream stream, ArrayList<Xep.Bookmarks.Conference> conferences, Object? o) { private static void on_conference_bookmarks_received(Core.XmppStream stream, ArrayList<Xep.Bookmarks.Conference> conferences, Object? o) {
Idle.add(() => {
Tuple<ConferenceList, Account> tuple = o as Tuple<ConferenceList, Account>; Tuple<ConferenceList, Account> tuple = o as Tuple<ConferenceList, Account>;
ConferenceList list = tuple.a; ConferenceList list = tuple.a;
Account account = tuple.b; Account account = tuple.b;
list.lists[account] = conferences; list.lists[account] = conferences;
Idle.add(() => { list.refresh_conferences(); return false; }); list.refresh_conferences(); return false;
});
} }
private void header(ListBoxRow row, ListBoxRow? before_row) { private void header(ListBoxRow row, ListBoxRow? before_row) {

View file

@ -51,6 +51,7 @@ public class UnifiedWindow : Window {
} }
public void on_conversation_selected(Conversation conversation) { public void on_conversation_selected(Conversation conversation) {
if (this.conversation == null || !this.conversation.equals(conversation)) {
this.conversation = conversation; this.conversation = conversation;
stream_interactor.get_module(ChatInteraction.IDENTITY).on_conversation_selected(conversation); stream_interactor.get_module(ChatInteraction.IDENTITY).on_conversation_selected(conversation);
conversation.active = true; // only for conversation_selected conversation.active = true; // only for conversation_selected
@ -60,6 +61,7 @@ public class UnifiedWindow : Window {
conversation_frame.initialize_for_conversation(conversation); conversation_frame.initialize_for_conversation(conversation);
conversation_titlebar.initialize_for_conversation(conversation); conversation_titlebar.initialize_for_conversation(conversation);
} }
}
private void setup_unified() { private void setup_unified() {
chat_input = new ChatInput.View(stream_interactor) { visible=true }; chat_input = new ChatInput.View(stream_interactor) { visible=true };