2019-08-02 01:15:12 +00:00
using Gee ;
using Gdk ;
using Gtk ;
using Dino.Entities ;
namespace Dino.Ui {
2020-04-22 18:04:03 +00:00
private const string OPEN_CONVERSATION_DETAILS_URI = " x-dino:open-conversation-details " ;
2019-08-02 01:15:12 +00:00
public class ChatInputController : Object {
2020-04-05 14:19:56 +00:00
public signal void activate_last_message_correction ( ) ;
2020-04-22 13:44:12 +00:00
public signal void file_picker_selected ( ) ;
2020-06-04 12:03:34 +00:00
public signal void clipboard_pasted ( ) ;
2020-04-05 14:19:56 +00:00
2019-08-02 01:15:12 +00:00
public new string ? conversation_display_name { get ; set ; }
public string ? conversation_topic { get ; set ; }
private Conversation ? conversation ;
private ChatInput . View chat_input ;
private Label status_description_label ;
private StreamInteractor stream_interactor ;
private Plugins . InputFieldStatus input_field_status ;
2020-04-03 20:49:59 +00:00
private ChatTextViewController chat_text_view_controller ;
2019-08-02 01:15:12 +00:00
public ChatInputController ( ChatInput . View chat_input , StreamInteractor stream_interactor ) {
this . chat_input = chat_input ;
this . status_description_label = chat_input . chat_input_status ;
this . stream_interactor = stream_interactor ;
2020-04-03 20:49:59 +00:00
this . chat_text_view_controller = new ChatTextViewController ( chat_input . chat_text_view , stream_interactor ) ;
2019-08-02 01:15:12 +00:00
2020-02-21 01:11:23 +00:00
chat_input . init ( stream_interactor ) ;
2019-08-02 01:15:12 +00:00
reset_input_field_status ( ) ;
2022-07-27 17:41:05 +00:00
var text_input_key_events = new EventControllerKey ( ) { name = " dino-text-input-controller-key-events " } ;
2022-02-14 13:55:59 +00:00
text_input_key_events . key_pressed . connect ( on_text_input_key_press ) ;
chat_input . chat_text_view . text_view . add_controller ( text_input_key_events ) ;
2020-06-04 12:03:34 +00:00
chat_input . chat_text_view . text_view . paste_clipboard . connect ( ( ) = > clipboard_pasted ( ) ) ;
2022-02-14 13:55:59 +00:00
chat_input . chat_text_view . text_view . buffer . changed . connect ( on_text_input_changed ) ;
2020-04-22 13:44:12 +00:00
2020-04-03 20:49:59 +00:00
chat_text_view_controller . send_text . connect ( send_text ) ;
2019-08-02 01:15:12 +00:00
chat_input . encryption_widget . encryption_changed . connect ( on_encryption_changed ) ;
2020-04-22 21:57:12 +00:00
2020-04-22 13:44:12 +00:00
chat_input . file_button . clicked . connect ( ( ) = > file_picker_selected ( ) ) ;
2020-04-22 18:04:03 +00:00
stream_interactor . get_module ( MucManager . IDENTITY ) . received_occupant_role . connect ( update_moderated_input_status ) ;
stream_interactor . get_module ( MucManager . IDENTITY ) . room_info_updated . connect ( update_moderated_input_status ) ;
status_description_label . activate_link . connect ( ( uri ) = > {
if ( uri = = OPEN_CONVERSATION_DETAILS_URI ) {
ContactDetails . Dialog contact_details_dialog = new ContactDetails . Dialog ( stream_interactor , conversation ) ;
2022-02-14 13:55:59 +00:00
contact_details_dialog . set_transient_for ( ( Gtk . Window ) chat_input . get_root ( ) ) ;
2020-04-22 18:04:03 +00:00
contact_details_dialog . present ( ) ;
}
return true ;
} ) ;
2019-08-02 01:15:12 +00:00
}
public void set_conversation ( Conversation conversation ) {
this . conversation = conversation ;
reset_input_field_status ( ) ;
chat_input . encryption_widget . set_conversation ( conversation ) ;
2020-04-03 20:49:59 +00:00
chat_input . initialize_for_conversation ( conversation ) ;
chat_text_view_controller . initialize_for_conversation ( conversation ) ;
2020-04-22 21:57:12 +00:00
update_moderated_input_status ( conversation . account ) ;
2019-08-02 01:15:12 +00:00
}
2020-04-22 13:44:12 +00:00
public void set_file_upload_active ( bool active ) {
chat_input . set_file_upload_active ( active ) ;
}
2022-08-20 22:10:59 +00:00
private void on_encryption_changed ( Encryption encryption ) {
2019-08-02 01:15:12 +00:00
reset_input_field_status ( ) ;
2022-08-20 22:10:59 +00:00
if ( encryption = = Encryption . NONE ) return ;
2019-08-02 01:15:12 +00:00
2022-08-20 22:10:59 +00:00
Application app = GLib . Application . get_default ( ) as Application ;
var encryption_entry = app . plugin_registry . encryption_list_entries [ encryption ] ;
2019-08-02 01:15:12 +00:00
encryption_entry . encryption_activated ( conversation , set_input_field_status ) ;
}
private void set_input_field_status ( Plugins . InputFieldStatus ? status ) {
input_field_status = status ;
chat_input . set_input_state ( status . message_type ) ;
2020-04-22 21:57:12 +00:00
status_description_label . use_markup = status . contains_markup ;
2020-04-22 18:04:03 +00:00
2019-08-02 01:15:12 +00:00
status_description_label . label = status . message ;
chat_input . file_button . sensitive = status . input_state = = Plugins . InputFieldStatus . InputState . NORMAL ;
}
private void reset_input_field_status ( ) {
set_input_field_status ( new Plugins . InputFieldStatus ( " " , Plugins . InputFieldStatus . MessageType . NONE , Plugins . InputFieldStatus . InputState . NORMAL ) ) ;
}
private void send_text ( ) {
// Don't do anything if we're in a NO_SEND state. Don't clear the chat input, don't send.
if ( input_field_status . input_state = = Plugins . InputFieldStatus . InputState . NO_SEND ) {
chat_input . highlight_state_description ( ) ;
return ;
}
2020-04-03 20:49:59 +00:00
string text = chat_input . chat_text_view . text_view . buffer . text ;
chat_input . chat_text_view . text_view . buffer . text = " " ;
2019-10-16 01:25:44 +00:00
if ( text . has_prefix ( " / " ) ) {
string [ ] token = text . split ( " " , 2 ) ;
2019-08-02 01:15:12 +00:00
switch ( token [ 0 ] ) {
case " /me " :
// Just send as is.
break ;
case " /say " :
if ( token . length = = 1 ) return ;
text = token [ 1 ] ;
break ;
case " /kick " :
stream_interactor . get_module ( MucManager . IDENTITY ) . kick ( conversation . account , conversation . counterpart , token [ 1 ] ) ;
return ;
case " /affiliate " :
if ( token . length > 1 ) {
2022-01-05 11:35:46 +00:00
string [ ] user_role = token [ 1 ] . split ( " " ) ;
if ( user_role . length > = 2 ) {
string nick = string . joinv ( " " , user_role [ 0 : user_role . length - 1 ] ) . strip ( ) ;
string role = user_role [ user_role . length - 1 ] . strip ( ) ;
stream_interactor . get_module ( MucManager . IDENTITY ) . change_affiliation ( conversation . account , conversation . counterpart , nick , role ) ;
2019-08-02 01:15:12 +00:00
}
}
return ;
case " /nick " :
2020-10-27 14:31:39 +00:00
stream_interactor . get_module ( MucManager . IDENTITY ) . change_nick . begin ( conversation , token [ 1 ] ) ;
2019-08-02 01:15:12 +00:00
return ;
case " /ping " :
Xmpp . XmppStream ? stream = stream_interactor . get_stream ( conversation . account ) ;
2019-12-22 03:10:53 +00:00
try {
2022-02-14 13:55:59 +00:00
stream . get_module ( Xmpp . Xep . Ping . Module . IDENTITY ) . send_ping . begin ( stream , conversation . counterpart . with_resource ( token [ 1 ] ) ) ;
2019-12-22 03:10:53 +00:00
} catch ( Xmpp . InvalidJidError e ) {
warning ( " Could not ping invalid Jid: %s " , e . message ) ;
}
2019-08-02 01:15:12 +00:00
return ;
case " /topic " :
stream_interactor . get_module ( MucManager . IDENTITY ) . change_subject ( conversation . account , conversation . counterpart , token [ 1 ] ) ;
return ;
default :
if ( token [ 0 ] . has_prefix ( " // " ) ) {
text = text . substring ( 1 ) ;
} else {
string cmd_name = token [ 0 ] . substring ( 1 ) ;
Dino . Application app = GLib . Application . get_default ( ) as Dino . Application ;
if ( app ! = null & & app . plugin_registry . text_commands . has_key ( cmd_name ) ) {
string ? new_text = app . plugin_registry . text_commands [ cmd_name ] . handle_command ( token [ 1 ] , conversation ) ;
if ( new_text = = null ) return ;
text = ( ! ) new_text ;
}
}
break ;
}
}
stream_interactor . get_module ( MessageProcessor . IDENTITY ) . send_text ( text , conversation ) ;
}
private void on_text_input_changed ( ) {
2020-04-03 20:49:59 +00:00
if ( chat_input . chat_text_view . text_view . buffer . text ! = " " ) {
2019-08-02 01:15:12 +00:00
stream_interactor . get_module ( ChatInteraction . IDENTITY ) . on_message_entered ( conversation ) ;
} else {
stream_interactor . get_module ( ChatInteraction . IDENTITY ) . on_message_cleared ( conversation ) ;
}
}
2020-04-22 21:57:12 +00:00
private void update_moderated_input_status ( Account account , Xmpp . Jid ? jid = null ) {
2020-05-27 22:27:06 +00:00
if ( conversation ! = null & & conversation . type_ = = Conversation . Type . GROUPCHAT ) {
2020-04-22 21:57:12 +00:00
Xmpp . Jid ? own_jid = stream_interactor . get_module ( MucManager . IDENTITY ) . get_own_jid ( conversation . counterpart , conversation . account ) ;
if ( own_jid = = null ) return ;
if ( stream_interactor . get_module ( MucManager . IDENTITY ) . is_moderated_room ( conversation . account , conversation . counterpart ) & &
stream_interactor . get_module ( MucManager . IDENTITY ) . get_role ( own_jid , conversation . account ) = = Xmpp . Xep . Muc . Role . VISITOR ) {
2020-05-17 18:07:48 +00:00
string msg_str = _ ( " This conference does not allow you to send messages. " ) + " <a href= \" " + OPEN_CONVERSATION_DETAILS_URI + " \" > " + _ ( " Request permission " ) + " </a> " ;
set_input_field_status ( new Plugins . InputFieldStatus ( msg_str , Plugins . InputFieldStatus . MessageType . ERROR , Plugins . InputFieldStatus . InputState . NO_SEND , true ) ) ;
2020-04-22 18:04:03 +00:00
} else {
reset_input_field_status ( ) ;
}
}
}
2020-04-05 14:19:56 +00:00
2022-02-14 13:55:59 +00:00
private bool on_text_input_key_press ( uint keyval , uint keycode , Gdk . ModifierType state ) {
if ( keyval = = Gdk . Key . Up & & chat_input . chat_text_view . text_view . buffer . text = = " " ) {
2020-04-05 14:19:56 +00:00
activate_last_message_correction ( ) ;
return true ;
} else {
2022-07-27 17:41:05 +00:00
chat_input . do_focus ( ) ;
2020-04-05 14:19:56 +00:00
}
return false ;
}
2019-08-02 01:15:12 +00:00
}
}