diff --git a/libdino/src/entity/account.vala b/libdino/src/entity/account.vala index 3f1bfdb2..59a76c7d 100644 --- a/libdino/src/entity/account.vala +++ b/libdino/src/entity/account.vala @@ -71,13 +71,20 @@ public class Account : Object { } private void on_update(Object o, ParamSpec sp) { - db.account.update().with(db.account.id, "=", id) - .set(db.account.bare_jid, bare_jid.to_string()) - .set(db.account.resourcepart, resourcepart) - .set(db.account.password, password) - .set(db.account.alias, alias) - .set(db.account.enabled, enabled) - .perform(); + var update = db.account.update().with(db.account.id, "=", id); + switch (sp.name) { + case "bare-jid": + update.set(db.account.bare_jid, bare_jid.to_string()); break; + case "resourcepart": + update.set(db.account.resourcepart, resourcepart); break; + 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(); } } diff --git a/libdino/src/entity/conversation.vala b/libdino/src/entity/conversation.vala index 376d1cef..55413785 100644 --- a/libdino/src/entity/conversation.vala +++ b/libdino/src/entity/conversation.vala @@ -13,7 +13,16 @@ public class Conversation : Object { public Account account { get; private set; } public Jid counterpart { get; private set; } 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 Type type_ { 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]); active = row[db.conversation.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_]; encryption = (Encryption) row[db.conversation.encryption]; 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)) .with(db.conversation.account_id, "=", account.id); switch (sp.name) { - case "type_": + case "type-": update.set(db.conversation.type_, type_); break; case "encryption": 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; case "active": update.set(db.conversation.active, active); break; - case "last_active": + case "last-active": if (last_active != null) { update.set(db.conversation.last_active, (long) last_active.to_unix()); } else { diff --git a/libdino/src/entity/message.vala b/libdino/src/entity/message.vala index e50a1fc2..b5686159 100644 --- a/libdino/src/entity/message.vala +++ b/libdino/src/entity/message.vala @@ -40,6 +40,7 @@ public class Message : Object { public string? body { get; set; } public string? stanza_id { get; set; } public DateTime? time { get; set; } + /** UTC **/ public DateTime? local_time { get; set; } public Encryption encryption { get; set; default = Encryption.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); direction = row[db.message.direction]; 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]; 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]; @@ -141,7 +143,7 @@ public class Message : Object { private void on_update(Object o, ParamSpec sp) { Qlite.UpdateBuilder update_builder = db.message.update().with(db.message.id, "=", id); switch (sp.name) { - case "stanza_id": + case "stanza-id": update_builder.set(db.message.stanza_id, stanza_id); break; case "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; case "direction": update_builder.set(db.message.direction, direction); break; - case "type_": + case "type-": update_builder.set(db.message.type_, type_); break; case "time": 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; case "body": update_builder.set(db.message.body, body); break; @@ -165,7 +167,7 @@ public class Message : Object { } update_builder.perform(); - if (sp.get_name() == "real_jid") { + if (sp.get_name() == "real-jid") { db.real_jid.insert().or("REPLACE") .value(db.real_jid.message_id, id) .value(db.real_jid.real_jid, real_jid) diff --git a/libdino/src/service/chat_interaction.vala b/libdino/src/service/chat_interaction.vala index f6da1ee6..9943c3c3 100644 --- a/libdino/src/service/chat_interaction.vala +++ b/libdino/src/service/chat_interaction.vala @@ -51,8 +51,8 @@ public class ChatInteraction : StreamInteractionModule, Object { if (!last_input_interaction.has_key(conversation)) { send_chat_state_notification(conversation, Xep.ChatStateNotifications.STATE_COMPOSING); } - last_input_interaction[conversation] = new DateTime.now_utc(); - last_interface_interaction[conversation] = new DateTime.now_utc(); + last_input_interaction[conversation] = new DateTime.now_local(); + last_interface_interaction[conversation] = new DateTime.now_local(); } 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); selected_conversation = conversation; on_conversation_focused(conversation); @@ -106,7 +106,7 @@ public class ChatInteraction : StreamInteractionModule, Object { if (!iter.valid && iter.has_next()) iter.next(); Conversation conversation = iter.get_key(); 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(); 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(); Conversation conversation = iter.get_key(); 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(); send_chat_state_notification(conversation, Xep.ChatStateNotifications.STATE_GONE); } diff --git a/libdino/src/service/conversation_manager.vala b/libdino/src/service/conversation_manager.vala index 2d046e83..25d355c4 100644 --- a/libdino/src/service/conversation_manager.vala +++ b/libdino/src/service/conversation_manager.vala @@ -31,6 +31,18 @@ public class ConversationManager : StreamInteractionModule, Object { 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) { if (conversations.has_key(account)) { return conversations[account][jid]; @@ -48,20 +60,14 @@ public class ConversationManager : StreamInteractionModule, Object { return ret; } - public Conversation get_add_conversation(Jid jid, Account account) { - ensure_add_conversation(jid, account, Conversation.Type.CHAT); - return get_conversation(jid, account); - } - - 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) { - conversation.active = true; - conversation_activated(conversation); - } + public void start_conversation(Conversation conversation, bool push_front = false) { + if (push_front) { + conversation.last_active = new DateTime.now_local(); + if (conversation.active) conversation_activated(conversation); + } + if (!conversation.active) { + conversation.active = true; + conversation_activated(conversation); } } @@ -78,7 +84,8 @@ public class ConversationManager : StreamInteractionModule, Object { } 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) { @@ -86,16 +93,8 @@ public class ConversationManager : StreamInteractionModule, Object { } private void on_groupchat_joined(Account account, Jid jid, string nick) { - ensure_add_conversation(jid, account, Conversation.Type.GROUPCHAT); - ensure_start_conversation(jid, account); - } - - 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); - } + Conversation conversation = create_conversation(jid, account, Conversation.Type.GROUPCHAT); + start_conversation(conversation); } private void add_conversation(Conversation conversation) { diff --git a/libdino/src/service/message_manager.vala b/libdino/src/service/message_manager.vala index 1f0d528b..314a466b 100644 --- a/libdino/src/service/message_manager.vala +++ b/libdino/src/service/message_manager.vala @@ -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.stanza = 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.local_time = new DateTime.now_utc(); - Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_add_conversation(new_message.counterpart, account); + new_message.time = deleyed_delivery_flag != null ? deleyed_delivery_flag.datetime : new DateTime.now_local(); + new_message.local_time = new DateTime.now_local(); + Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(new_message.counterpart, account, Conversation.Type.CHAT); 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); @@ -113,9 +113,6 @@ public class MessageManager : StreamInteractionModule, Object { (!is_uuid && !db.contains_message(new_message, conversation.account))) { new_message.persist(db); 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) { message_sent(new_message, conversation); } else { @@ -137,8 +134,8 @@ public class MessageManager : StreamInteractionModule, Object { message.stanza_id = random_uuid(); message.account = conversation.account; message.body = text; - message.time = new DateTime.now_utc(); - message.local_time = new DateTime.now_utc(); + message.time = new DateTime.now_local(); + message.local_time = new DateTime.now_local(); message.direction = Entities.Message.DIRECTION_SENT; message.counterpart = conversation.counterpart; message.ourpart = new Jid(conversation.account.bare_jid.to_string() + "/" + conversation.account.resourcepart); diff --git a/libdino/src/service/muc_manager.vala b/libdino/src/service/muc_manager.vala index 82d200b0..c5bfb8ba 100644 --- a/libdino/src/service/muc_manager.vala +++ b/libdino/src/service/muc_manager.vala @@ -168,8 +168,8 @@ public class MucManager : StreamInteractionModule, Object { message.real_jid = real_jid; } } - 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 + string? muc_nick = stream.get_flag(Xep.Muc.Flag.IDENTITY).get_muc_nick(conversation.counterpart.bare_jid.to_string()); + if (muc_nick != null && message.from.equals(new Jid(@"$(message.from.bare_jid)/$muc_nick"))) { // TODO better from own Gee.List? messages = stream_interactor.get_module(MessageManager.IDENTITY).get_messages(conversation); if (messages != null) { // TODO not here foreach (Entities.Message m in messages) { diff --git a/main/src/ui/add_conversation/chat/dialog.vala b/main/src/ui/add_conversation/chat/dialog.vala index 15624731..910e7264 100644 --- a/main/src/ui/add_conversation/chat/dialog.vala +++ b/main/src/ui/add_conversation/chat/dialog.vala @@ -71,9 +71,8 @@ public class Dialog : Gtk.Dialog { protected void on_ok_button_clicked() { ListRow? selected_row = roster_list.get_selected_row() as ListRow; if (selected_row != null) { - // TODO move in list to front immediately - stream_interactor.get_module(ConversationManager.IDENTITY).ensure_start_conversation(selected_row.jid, selected_row.account); - Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(selected_row.jid, selected_row.account); + 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).start_conversation(conversation, true); conversation_opened(conversation); } close(); diff --git a/main/src/ui/add_conversation/conference/conference_list.vala b/main/src/ui/add_conversation/conference/conference_list.vala index c44f989a..d11271d8 100644 --- a/main/src/ui/add_conversation/conference/conference_list.vala +++ b/main/src/ui/add_conversation/conference/conference_list.vala @@ -43,11 +43,13 @@ protected class ConferenceList : FilterableList { } private static void on_conference_bookmarks_received(Core.XmppStream stream, ArrayList conferences, Object? o) { - Tuple tuple = o as Tuple; - ConferenceList list = tuple.a; - Account account = tuple.b; - list.lists[account] = conferences; - Idle.add(() => { list.refresh_conferences(); return false; }); + Idle.add(() => { + Tuple tuple = o as Tuple; + ConferenceList list = tuple.a; + Account account = tuple.b; + list.lists[account] = conferences; + list.refresh_conferences(); return false; + }); } private void header(ListBoxRow row, ListBoxRow? before_row) { diff --git a/main/src/ui/unified_window.vala b/main/src/ui/unified_window.vala index 66a4a087..35f97d6e 100644 --- a/main/src/ui/unified_window.vala +++ b/main/src/ui/unified_window.vala @@ -51,14 +51,16 @@ public class UnifiedWindow : Window { } public void on_conversation_selected(Conversation conversation) { - this.conversation = conversation; - stream_interactor.get_module(ChatInteraction.IDENTITY).on_conversation_selected(conversation); - conversation.active = true; // only for conversation_selected - filterable_conversation_list.conversation_list.on_conversation_selected(conversation); // only for conversation_opened + if (this.conversation == null || !this.conversation.equals(conversation)) { + this.conversation = conversation; + stream_interactor.get_module(ChatInteraction.IDENTITY).on_conversation_selected(conversation); + conversation.active = true; // only for conversation_selected + filterable_conversation_list.conversation_list.on_conversation_selected(conversation); // only for conversation_opened - chat_input.initialize_for_conversation(conversation); - conversation_frame.initialize_for_conversation(conversation); - conversation_titlebar.initialize_for_conversation(conversation); + chat_input.initialize_for_conversation(conversation); + conversation_frame.initialize_for_conversation(conversation); + conversation_titlebar.initialize_for_conversation(conversation); + } } private void setup_unified() {