Add keyboard shortcut (up key) to activate last message correction

This commit is contained in:
fiaxh 2020-04-05 16:19:56 +02:00
parent 8f75954188
commit d091a6c3cd
9 changed files with 84 additions and 21 deletions

View file

@ -91,6 +91,12 @@ public class MessageCorrection : StreamInteractionModule, MessageListener {
public override string[] after_actions { get { return after_actions_const; } } public override string[] after_actions { get { return after_actions_const; } }
public override async bool run(Entities.Message message, Xmpp.MessageStanza stanza, Conversation conversation) { public override async bool run(Entities.Message message, Xmpp.MessageStanza stanza, Conversation conversation) {
if (conversation.type_ != Conversation.Type.CHAT) {
// Don't process messages or corrections from MUC history
DateTime? mam_delay = Xep.DelayedDelivery.get_time_for_message(stanza, message.from.bare_jid);
if (mam_delay != null) return false;
}
string? replace_id = Xep.LastMessageCorrection.get_replace_id(stanza); string? replace_id = Xep.LastMessageCorrection.get_replace_id(stanza);
if (replace_id == null) { if (replace_id == null) {
if (!last_messages.has_key(conversation)) { if (!last_messages.has_key(conversation)) {
@ -126,11 +132,13 @@ public class MessageCorrection : StreamInteractionModule, MessageListener {
message.edit_to = replace_id; message.edit_to = replace_id;
on_received_correction(conversation, current_correction_message_id); on_received_correction(conversation, current_correction_message_id);
}
return true; return true;
} }
return false;
}
private void on_received_correction(Conversation conversation, int message_id) { private void on_received_correction(Conversation conversation, int message_id) {
ContentItem? content_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_item(conversation, 1, message_id); ContentItem? content_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_item(conversation, 1, message_id);
received_correction(content_item); received_correction(content_item);

View file

@ -122,7 +122,7 @@ public class MessageProcessor : StreamInteractionModule, Object {
if (id == null) return; if (id == null) return;
StanzaNode? delay_node = message.stanza.get_deep_subnode(mam_flag.ns_ver + ":result", "urn:xmpp:forward:0:forwarded", "urn:xmpp:delay:delay"); StanzaNode? delay_node = message.stanza.get_deep_subnode(mam_flag.ns_ver + ":result", "urn:xmpp:forward:0:forwarded", "urn:xmpp:delay:delay");
if (delay_node == null) return; if (delay_node == null) return;
DateTime? time = DelayedDelivery.Module.get_time_for_node(delay_node); DateTime? time = DelayedDelivery.get_time_for_node(delay_node);
if (time == null) return; if (time == null) return;
mam_times[account][id] = time; mam_times[account][id] = time;

View file

@ -51,13 +51,13 @@
<property name="visible">True</property> <property name="visible">True</property>
<child> <child>
<object class="GtkButton" id="cancel_button"> <object class="GtkButton" id="cancel_button">
<property name="label">Cancel</property> <property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property> <property name="visible">True</property>
</object> </object>
</child> </child>
<child> <child>
<object class="GtkButton" id="send_button"> <object class="GtkButton" id="send_button">
<property name="label">Update message</property> <property name="label" translatable="yes">Update message</property>
<property name="visible">True</property> <property name="visible">True</property>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>

View file

@ -8,6 +8,8 @@ namespace Dino.Ui {
public class ChatInputController : Object { public class ChatInputController : Object {
public signal void activate_last_message_correction();
public new string? conversation_display_name { get; set; } public new string? conversation_display_name { get; set; }
public string? conversation_topic { get; set; } public string? conversation_topic { get; set; }
@ -30,6 +32,7 @@ public class ChatInputController : Object {
reset_input_field_status(); reset_input_field_status();
chat_input.chat_text_view.text_view.buffer.changed.connect(on_text_input_changed); chat_input.chat_text_view.text_view.buffer.changed.connect(on_text_input_changed);
chat_input.chat_text_view.text_view.key_press_event.connect(on_text_input_key_press);
chat_text_view_controller.send_text.connect(send_text); chat_text_view_controller.send_text.connect(send_text);
chat_input.encryption_widget.encryption_changed.connect(on_encryption_changed); chat_input.encryption_widget.encryption_changed.connect(on_encryption_changed);
@ -145,6 +148,16 @@ public class ChatInputController : Object {
stream_interactor.get_module(ChatInteraction.IDENTITY).on_message_cleared(conversation); stream_interactor.get_module(ChatInteraction.IDENTITY).on_message_cleared(conversation);
} }
} }
private bool on_text_input_key_press(EventKey event) {
if (event.keyval == Gdk.Key.Up && chat_input.chat_text_view.text_view.buffer.text == "") {
activate_last_message_correction();
return true;
} else {
chat_input.chat_text_view.text_view.grab_focus();
}
return false;
}
} }
} }

View file

@ -76,6 +76,24 @@ public class ConversationView : Box, Plugins.ConversationItemCollection, Plugins
return this; return this;
} }
public void activate_last_message_correction() {
Gee.BidirIterator<Plugins.MetaConversationItem> iter = content_items.bidir_iterator();
iter.last();
for (int i = 0; i < 10 && content_items.size > i; i++) {
Plugins.MetaConversationItem item = iter.get();
MessageMetaItem message_item = item as MessageMetaItem;
if (message_item != null) {
if ((conversation.type_ == Conversation.Type.CHAT && message_item.jid.equals_bare(conversation.account.bare_jid)) ||
(conversation.type_ == Conversation.Type.GROUPCHAT &&
message_item.jid.equals(stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(conversation.counterpart, conversation.account)))) {
message_item.in_edit_mode = true;
break;
}
}
iter.previous();
}
}
private bool on_enter_notify_event(Gdk.EventCrossing event) { private bool on_enter_notify_event(Gdk.EventCrossing event) {
mouse_inside = true; mouse_inside = true;
update_highlight((int)event.x_root, (int)event.y_root); update_highlight((int)event.x_root, (int)event.y_root);

View file

@ -28,6 +28,16 @@ public class MessageMetaItem : ContentMetaItem {
stream_interactor.get_module(MessageCorrection.IDENTITY).received_correction.connect(on_received_correction); stream_interactor.get_module(MessageCorrection.IDENTITY).received_correction.connect(on_received_correction);
this.notify["in-edit-mode"].connect(() => {
if (in_edit_mode == false) return;
bool allowed = stream_interactor.get_module(MessageCorrection.IDENTITY).is_own_correction_allowed(message_item.conversation, message_item.message);
if (allowed) {
message_item_widget.set_edit_mode();
} else {
this.in_edit_mode = false;
}
});
return message_item_widget; return message_item_widget;
} }
@ -106,7 +116,11 @@ public class MessageItemWidget : SizeRequestBin {
unset_edit_mode(); unset_edit_mode();
}); });
edit_mode.send.connect(() => { edit_mode.send.connect(() => {
if (((MessageItem) content_item).message.body != edit_mode.chat_text_view.text_view.buffer.text) {
edit_sent(edit_mode.chat_text_view.text_view.buffer.text); edit_sent(edit_mode.chat_text_view.text_view.buffer.text);
} else {
edit_cancelled();
}
unset_edit_mode(); unset_edit_mode();
}); });
} }
@ -122,6 +136,9 @@ public class MessageItemWidget : SizeRequestBin {
public void unset_edit_mode() { public void unset_edit_mode() {
this.remove(edit_mode); this.remove(edit_mode);
this.add(label); this.add(label);
label.grab_focus();
label.selectable = false;
label.selectable = true;
} }
public void update_label() { public void update_label() {
@ -200,11 +217,16 @@ public class MessageItemEditMode : Box {
}); });
emoji_button.set_popover(chooser); emoji_button.set_popover(chooser);
chat_text_view.text_view.buffer.changed.connect_after(on_text_view_changed);
cancel_button.clicked.connect(() => cancelled()); cancel_button.clicked.connect(() => cancelled());
send_button.clicked.connect(() => send()); send_button.clicked.connect(() => send());
chat_text_view.cancel_input.connect(() => cancelled()); chat_text_view.cancel_input.connect(() => cancelled());
chat_text_view.send_text.connect(() => send()); chat_text_view.send_text.connect(() => send());
}
private void on_text_view_changed() {
send_button.sensitive = chat_text_view.text_view.buffer.text != "";
} }
} }

View file

@ -44,6 +44,7 @@ public class ConversationViewController : Object {
view.drag_data_received.connect(this.on_drag_data_received); view.drag_data_received.connect(this.on_drag_data_received);
// forward key presses // forward key presses
chat_input_controller.activate_last_message_correction.connect(() => view.conversation_frame.activate_last_message_correction());
view.chat_input.key_press_event.connect(forward_key_press_to_chat_input); view.chat_input.key_press_event.connect(forward_key_press_to_chat_input);
view.conversation_frame.key_press_event.connect(forward_key_press_to_chat_input); view.conversation_frame.key_press_event.connect(forward_key_press_to_chat_input);
titlebar.key_press_event.connect(forward_key_press_to_chat_input); titlebar.key_press_event.connect(forward_key_press_to_chat_input);
@ -160,7 +161,6 @@ public class ConversationViewController : Object {
return false; return false;
} }
if (view.chat_input.chat_text_view.text_view.key_press_event(event)) { if (view.chat_input.chat_text_view.text_view.key_press_event(event)) {
view.chat_input.chat_text_view.text_view.grab_focus();
return true; return true;
} }
return false; return false;

View file

@ -2,6 +2,21 @@ namespace Xmpp.Xep.DelayedDelivery {
private const string NS_URI = "urn:xmpp:delay"; private const string NS_URI = "urn:xmpp:delay";
public static DateTime? get_time_for_node(StanzaNode node) {
string? time = node.get_attribute("stamp");
if (time != null) return DateTimeProfiles.parse_string(time);
return null;
}
public static DateTime? get_time_for_message(MessageStanza message, Jid? jid = null) {
foreach (StanzaNode delay_node in message.stanza.get_subnodes("delay", NS_URI)) {
if (jid == null || delay_node.get_attribute("from") == jid.to_string()) {
return get_time_for_node(delay_node);
}
}
return null;
}
public class Module : XmppStreamModule { public class Module : XmppStreamModule {
public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0203_delayed_delivery"); public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0203_delayed_delivery");
@ -13,19 +28,6 @@ public class Module : XmppStreamModule {
message.stanza.put_node(delay_node); message.stanza.put_node(delay_node);
} }
public static DateTime? get_time_for_message(MessageStanza message) {
StanzaNode? delay_node = message.stanza.get_subnode("delay", NS_URI);
if (delay_node != null) {
return get_time_for_node(delay_node);
}
return null;
}
public static DateTime? get_time_for_node(StanzaNode node) {
string? time = node.get_attribute("stamp");
if (time != null) return DateTimeProfiles.parse_string(time);
return null;
}
public override void attach(XmppStream stream) { public override void attach(XmppStream stream) {
stream.get_module(MessageModule.IDENTITY).received_pipeline.connect(received_pipeline_listener); stream.get_module(MessageModule.IDENTITY).received_pipeline.connect(received_pipeline_listener);
@ -52,7 +54,7 @@ public class ReceivedPipelineListener : StanzaListener<MessageStanza> {
public override string[] after_actions { get { return after_actions_const; } } public override string[] after_actions { get { return after_actions_const; } }
public override async bool run(XmppStream stream, MessageStanza message) { public override async bool run(XmppStream stream, MessageStanza message) {
DateTime? datetime = Module.get_time_for_message(message); DateTime? datetime = get_time_for_message(message);
if (datetime != null) message.add_flag(new MessageFlag(datetime)); if (datetime != null) message.add_flag(new MessageFlag(datetime));
return false; return false;
} }

View file

@ -141,7 +141,7 @@ public class ReceivedPipelineListener : StanzaListener<MessageStanza> {
} }
StanzaNode? forward_node = message.stanza.get_deep_subnode(NS_VER(stream) + ":result", "urn:xmpp:forward:0:forwarded", DelayedDelivery.NS_URI + ":delay"); StanzaNode? forward_node = message.stanza.get_deep_subnode(NS_VER(stream) + ":result", "urn:xmpp:forward:0:forwarded", DelayedDelivery.NS_URI + ":delay");
DateTime? datetime = DelayedDelivery.Module.get_time_for_node(forward_node); DateTime? datetime = DelayedDelivery.get_time_for_node(forward_node);
string? mam_id = message.stanza.get_deep_attribute(NS_VER(stream) + ":result", NS_VER(stream) + ":id"); string? mam_id = message.stanza.get_deep_attribute(NS_VER(stream) + ":result", NS_VER(stream) + ":id");
string? query_id = message.stanza.get_deep_attribute(NS_VER(stream) + ":result", NS_VER(stream) + ":queryid"); string? query_id = message.stanza.get_deep_attribute(NS_VER(stream) + ":result", NS_VER(stream) + ":queryid");
message.add_flag(new MessageFlag(datetime, mam_id, query_id)); message.add_flag(new MessageFlag(datetime, mam_id, query_id));