diff --git a/pixmaps/pixmaps.gresource.xml b/pixmaps/pixmaps.gresource.xml index f641e566d68677e5fc135ada0125700a557b812f..bdfbbf9615fb4832435df01a8efb47caa15cdce8 100644 --- a/pixmaps/pixmaps.gresource.xml +++ b/pixmaps/pixmaps.gresource.xml @@ -23,7 +23,9 @@ <file alias="mute_video">ic_videocam_white_24px.svg</file> <file alias="pause">ic_pause_white_24px.svg</file> <file alias="stop">baseline-stop-24px.svg</file> + <file alias="stop-white">stop-white.svg</file> <file alias="send">baseline-send-24px.svg</file> + <file alias="send-white">send-white.svg</file> <file alias="play">ic_play_arrow_white_24px.svg</file> <file alias="quality">ic_high_quality_white_24px.svg</file> <file alias="contacts_list">ic_people_black_24px.svg</file> @@ -52,5 +54,6 @@ <file alias="bottom_arrow">bottom_arrow.svg</file> <file alias="up_arrow">up_arrow.svg</file> <file alias="qrcode">qrcode.svg</file> + <file alias="retry">retry.svg</file> </gresource> </gresources> diff --git a/pixmaps/retry.svg b/pixmaps/retry.svg new file mode 100644 index 0000000000000000000000000000000000000000..d6f605cd7ed5c15be646a91ea3568a6f01ee9db0 --- /dev/null +++ b/pixmaps/retry.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z" fill="#ffffff"/></svg> \ No newline at end of file diff --git a/pixmaps/send-white.svg b/pixmaps/send-white.svg new file mode 100644 index 0000000000000000000000000000000000000000..f59133421c5fea32e77dee39d3b814e324fee265 --- /dev/null +++ b/pixmaps/send-white.svg @@ -0,0 +1,4 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> + <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" fill="white"/> + <path d="M0 0h24v24H0z" fill="none"/> +</svg> diff --git a/pixmaps/stop-white.svg b/pixmaps/stop-white.svg new file mode 100644 index 0000000000000000000000000000000000000000..63d1d1c8a3e1dd10874f9bf74e611dea30389ff8 --- /dev/null +++ b/pixmaps/stop-white.svg @@ -0,0 +1,4 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"> + <path d="M0 0h24v24H0z" fill="white"/> + <path d="M6 6h12v12H6z" fill="none"/> +</svg> diff --git a/src/chatview.cpp b/src/chatview.cpp index 63842501a8d7b901b87f36f785a3eb3282b9806f..3200d62298dc7215845d6a558f7665dbb0b8f189 100644 --- a/src/chatview.cpp +++ b/src/chatview.cpp @@ -29,25 +29,36 @@ // GTK #include <glib/gi18n.h> +#include <clutter-gtk/clutter-gtk.h> // Qt #include <QSize> // LRC +#include <api/call.h> #include <api/contactmodel.h> #include <api/conversationmodel.h> #include <api/contact.h> +#include <api/lrc.h> #include <api/newcallmodel.h> -#include <api/call.h> +#include <api/avmodel.h> // Client #include "marshals.h" #include "utils/files.h" #include "native/pixbufmanipulator.h" +#include "video/video_widget.h" + /* size of avatar */ static constexpr int AVATAR_WIDTH = 150; /* px */ static constexpr int AVATAR_HEIGHT = 150; /* px */ +enum class RecordAction { + RECORD, + STOP, + SEND +}; + struct CppImpl { struct Interaction { std::string conv; @@ -55,6 +66,11 @@ struct CppImpl { lrc::api::interaction::Info info; }; std::vector<Interaction> interactionsBuffer_; + lrc::api::AVModel* avModel_; + RecordAction current_action_ {RecordAction::RECORD}; + + // store current recording location + std::string saveFileName_; }; struct _ChatView @@ -83,13 +99,25 @@ struct _ChatViewPrivate QMetaObject::Connection interaction_removed; QMetaObject::Connection update_interaction_connection; QMetaObject::Connection update_add_to_conversations; + QMetaObject::Connection local_renderer_connection; gulong webkit_ready; gulong webkit_send_text; gulong webkit_drag_drop; bool ready_ {false}; - CppImpl* cpp_; + bool readyToRecord_ {false}; + CppImpl* cpp; + + bool video_started_by_settings; + GtkWidget* video_widget; + GtkWidget* record_popover; + GtkWidget* button_retry; + GtkWidget* button_main_action; + GtkWidget* label_time; + guint timer_duration = 0; + uint32_t duration = 0; + }; G_DEFINE_TYPE_WITH_PRIVATE(ChatView, chat_view, GTK_TYPE_BOX); @@ -108,6 +136,9 @@ enum { static guint chat_view_signals[LAST_SIGNAL] = { 0 }; +static void +init_video_widget(ChatView* self); + static void chat_view_dispose(GObject *object) { @@ -121,6 +152,7 @@ chat_view_dispose(GObject *object) QObject::disconnect(priv->update_interaction_connection); QObject::disconnect(priv->interaction_removed); QObject::disconnect(priv->update_add_to_conversations); + QObject::disconnect(priv->local_renderer_connection); /* Destroying the box will also destroy its children, and we wouldn't * want that. So we remove the webkit_chat_container from the box. */ @@ -140,6 +172,14 @@ chat_view_dispose(GObject *object) priv->webkit_chat_container = nullptr; } + if (priv->video_widget) { + gtk_widget_destroy(priv->video_widget); + } + + if (priv->record_popover) { + gtk_widget_destroy(priv->record_popover); + } + G_OBJECT_CLASS(chat_view_parent_class)->dispose(object); } @@ -223,6 +263,128 @@ file_to_manipulate(GtkWindow* top_window, bool send) static void update_chatview_frame(ChatView *self); +void +on_record_closed(GtkPopover*, ChatView *self) +{ + g_return_if_fail(IS_CHAT_VIEW(self)); + auto* priv = CHAT_VIEW_GET_PRIVATE(self); + + if (!priv->cpp->saveFileName_.empty()) { + priv->cpp->avModel_->stopLocalRecorder(priv->cpp->saveFileName_); + priv->cpp->saveFileName_ = ""; + } + + priv->cpp->current_action_ = RecordAction::RECORD; + if (priv->timer_duration) g_source_remove(priv->timer_duration); + priv->cpp->avModel_->stopPreview(); + priv->duration = 0; +} + +void +chat_view_show_video_recorder(ChatView *self, int pt_x, int pt_y) +{ + g_return_if_fail(IS_CHAT_VIEW(self)); + auto* priv = CHAT_VIEW_GET_PRIVATE(self); + if (!priv->readyToRecord_) return; + + priv->cpp->avModel_->startPreview(); + + // CSS styles + auto provider = gtk_css_provider_new(); + gtk_css_provider_load_from_data(provider, + ".record-button { background: rgba(0, 0, 0, 0.2); border-radius: 50%; border: 0; transition: all 0.3s ease; } \ + .record-button:hover { background: rgba(0, 0, 0, 0.2); border-radius: 50%; border: 0; transition: all 0.3s ease; } \ + .label_time { color: white; }", + -1, nullptr + ); + gtk_style_context_add_provider_for_screen(gdk_display_get_default_screen(gdk_display_get_default()), + GTK_STYLE_PROVIDER(provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + + auto deviceName = priv->cpp->avModel_->getDefaultDeviceName(); + auto settings = priv->cpp->avModel_->getDeviceSettings(deviceName); + auto res = settings.size; + if (res.find("x") == std::string::npos) return; + auto width = static_cast<double>(std::stoi(res.substr(0, res.find("x")))); + auto height = static_cast<double>(std::stoi(res.substr(res.find("x") + 1))); + auto max = std::max(width, height); +#if GTK_CHECK_VERSION(3,22,0) + GdkRectangle workarea = {}; + gdk_monitor_get_workarea( + gdk_display_get_primary_monitor(gdk_display_get_default()), + &workarea); + auto widget_size = std::max(300, workarea.width / 6); +#else + auto widget_size = std::max(300, gdk_screen_width() / 6); +#endif + + width = width / max * widget_size; + height = height / max * widget_size; + + if (priv->record_popover) { + gtk_widget_destroy(priv->record_popover); + } + init_video_widget(self); + + priv->record_popover = gtk_popover_new(GTK_WIDGET(priv->box_webkit_chat_container)); + g_signal_connect(priv->record_popover, "closed", G_CALLBACK(on_record_closed), self); + gtk_popover_set_relative_to(GTK_POPOVER(priv->record_popover), GTK_WIDGET(priv->box_webkit_chat_container)); + gtk_container_add(GTK_CONTAINER(GTK_POPOVER(priv->record_popover)), priv->video_widget); + GdkRectangle rect; + rect.width = 1; + rect.height = 1; + rect.x = pt_x; + rect.y = pt_y; + gtk_popover_set_pointing_to(GTK_POPOVER(priv->record_popover), &rect); + gtk_widget_set_size_request(GTK_WIDGET(priv->video_widget), width, height); +#if GTK_CHECK_VERSION(3,22,0) + gtk_popover_popdown(GTK_POPOVER(priv->record_popover)); +#endif + gtk_widget_show_all(priv->record_popover); +} + +static gboolean +on_timer_duration_timeout(ChatView* view) +{ + g_return_val_if_fail(IS_CHAT_VIEW(view), G_SOURCE_REMOVE); + auto* priv = CHAT_VIEW_GET_PRIVATE(view); + priv->duration += 1; + auto m = std::to_string(priv->duration / 60); + if (m.length() == 1) { + m = "0" + m; + } + auto s = std::to_string(priv->duration % 60); + if (s.length() == 1) { + s = "0" + s; + } + auto time_txt = m + ":" + s; + gtk_label_set_text(GTK_LABEL(priv->label_time), time_txt.c_str()); + return G_SOURCE_CONTINUE; +} + +static void +reset_recorder(ChatView *self) +{ + g_return_if_fail(IS_CHAT_VIEW(self)); + auto* priv = CHAT_VIEW_GET_PRIVATE(self); + + gtk_widget_hide(GTK_WIDGET(priv->button_retry)); + auto image = gtk_image_new_from_resource ("/net/jami/JamiGnome/stop-white"); + gtk_button_set_image(GTK_BUTTON(priv->button_main_action), image); + priv->cpp->current_action_ = RecordAction::STOP; + gtk_label_set_text(GTK_LABEL(priv->label_time), "00:00"); + priv->duration = 0; + priv->timer_duration = g_timeout_add(1000, (GSourceFunc)on_timer_duration_timeout, self); + + std::string file_name = priv->cpp->avModel_->startLocalRecorder(false); + if (file_name.empty()) { + g_warning("set_state: failed to start recording"); + return; + } + + priv->cpp->saveFileName_ = file_name; +} + static void webkit_chat_container_script_dialog(GtkWidget* webview, gchar *interaction, ChatView* self) { @@ -334,6 +496,18 @@ webkit_chat_container_script_dialog(GtkWidget* webview, gchar *interaction, Chat } catch (...) { g_warning("delete interaction failed: can't find %s", order.substr(std::string("RETRY_INTERACTION:").size()).c_str()); } + } else if (order.find("VIDEO_RECORD:") == 0) { + auto pos_str {order.substr(std::string("VIDEO_RECORD:").size())}; + auto sep_idx = pos_str.find("x"); + if (sep_idx == std::string::npos) + return; + try { + int pt_x = stoi(pos_str.substr(0, sep_idx)); + int pt_y = stoi(pos_str.substr(sep_idx + 1)); + chat_view_show_video_recorder(self, pt_x, pt_y); + } catch (...) { + // ignore + } } } @@ -541,7 +715,7 @@ webkit_chat_container_ready(ChatView* self) load_participants_images(self); priv->ready_ = true; - for (const auto& interaction: priv->cpp_->interactionsBuffer_) { + for (const auto& interaction: priv->cpp->interactionsBuffer_) { if (interaction.conv == priv->conversation_->uid) { print_interaction_to_buffer(self, interaction.id, interaction.info); } @@ -642,6 +816,7 @@ update_chatview_frame(ChatView* self) } } } catch (const std::out_of_range&) {} + chat_view_set_record_visible(self, lrc::api::Lrc::activeCalls().size() == 0); } static void @@ -678,6 +853,118 @@ on_webkit_drag_drop(GtkWidget*, gchar* data, ChatView* self) } } +static void +on_main_action_clicked(ChatView *self) +{ + g_return_if_fail(IS_CHAT_VIEW(self)); + auto* priv = CHAT_VIEW_GET_PRIVATE(self); + + switch (priv->cpp->current_action_) { + case RecordAction::RECORD: { + reset_recorder(self); + break; + } + case RecordAction::STOP: { + if (!priv->cpp->saveFileName_.empty()) { + priv->cpp->avModel_->stopLocalRecorder(priv->cpp->saveFileName_); + } + gtk_widget_show(GTK_WIDGET(priv->button_retry)); + auto image = gtk_image_new_from_resource ("/net/jami/JamiGnome/send-white"); + gtk_button_set_image(GTK_BUTTON(priv->button_main_action), image); + priv->cpp->current_action_ = RecordAction::SEND; + g_source_remove(priv->timer_duration); + break; + } + case RecordAction::SEND: { + if (auto model = (*priv->accountInfo_)->conversationModel.get()) { + model->sendFile(priv->conversation_->uid, priv->cpp->saveFileName_, g_path_get_basename(priv->cpp->saveFileName_.c_str())); + priv->cpp->saveFileName_ = ""; + } + gtk_widget_destroy(priv->record_popover); + priv->cpp->current_action_ = RecordAction::RECORD; + priv->cpp->avModel_->stopPreview(); + break; + } + } +} + +static void +init_video_widget(ChatView* self) +{ + ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self); + if (priv->video_widget && GTK_IS_WIDGET(priv->video_widget)) gtk_widget_destroy(priv->video_widget); + priv->video_widget = video_widget_new(); + + try { + const lrc::api::video::Renderer* previewRenderer = + &priv->cpp->avModel_->getRenderer( + lrc::api::video::PREVIEW_RENDERER_ID); + priv->video_started_by_settings = previewRenderer->isRendering(); + if (priv->video_started_by_settings) { + video_widget_add_new_renderer(VIDEO_WIDGET(priv->video_widget), + priv->cpp->avModel_, previewRenderer, VIDEO_RENDERER_REMOTE); + } else { + priv->video_started_by_settings = true; + priv->local_renderer_connection = QObject::connect( + &*priv->cpp->avModel_, + &lrc::api::AVModel::rendererStarted, + [=](const std::string& id) { + if (id != lrc::api::video::PREVIEW_RENDERER_ID + || !priv->readyToRecord_) + return; + video_widget_add_new_renderer( + VIDEO_WIDGET(priv->video_widget), + priv->cpp->avModel_, + previewRenderer, VIDEO_RENDERER_REMOTE); + }); + } + } catch (const std::out_of_range& e) { + g_warning("Cannot start preview"); + } + + auto stage = gtk_clutter_embed_get_stage(GTK_CLUTTER_EMBED(priv->video_widget)); + + auto* hbox_record_controls = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 15); + + auto image_retry = gtk_image_new_from_resource("/net/jami/JamiGnome/retry"); + auto image_record = gtk_image_new_from_resource("/net/jami/JamiGnome/record"); + + priv->button_retry = gtk_button_new(); + gtk_button_set_relief(GTK_BUTTON(priv->button_retry), GTK_RELIEF_NONE); + gtk_widget_set_tooltip_text(priv->button_retry, _("Retry")); + gtk_button_set_image(GTK_BUTTON(priv->button_retry), image_retry); + gtk_widget_set_size_request(GTK_WIDGET(priv->button_retry), 48, 48); + GtkStyleContext* context; + context = gtk_widget_get_style_context(GTK_WIDGET(priv->button_retry)); + gtk_style_context_add_class(context, "record-button"); + g_signal_connect_swapped(priv->button_retry, "clicked", G_CALLBACK(reset_recorder), self); + + priv->button_main_action = gtk_button_new(); + gtk_button_set_relief(GTK_BUTTON(priv->button_main_action), GTK_RELIEF_NONE); + gtk_widget_set_tooltip_text(priv->button_main_action, _("Record")); + gtk_button_set_image(GTK_BUTTON(priv->button_main_action), image_record); + gtk_widget_set_size_request(GTK_WIDGET(priv->button_main_action), 48, 48); + context = gtk_widget_get_style_context(GTK_WIDGET(priv->button_main_action)); + gtk_style_context_add_class(context, "record-button"); + g_signal_connect_swapped(priv->button_main_action, "clicked", G_CALLBACK(on_main_action_clicked), self); + + priv->label_time = gtk_label_new("00:00"); + context = gtk_widget_get_style_context(GTK_WIDGET(priv->label_time)); + gtk_style_context_add_class(context, "label_time"); + + gtk_container_add(GTK_CONTAINER(hbox_record_controls), priv->button_retry); + gtk_container_add(GTK_CONTAINER(hbox_record_controls), priv->button_main_action); + gtk_container_add(GTK_CONTAINER(hbox_record_controls), priv->label_time); + + gtk_widget_show_all(hbox_record_controls); + gtk_widget_hide(priv->button_retry); + + auto actor_controls = gtk_clutter_actor_new_with_contents(hbox_record_controls); + clutter_actor_add_child(stage, actor_controls); + clutter_actor_set_x_align(actor_controls, CLUTTER_ACTOR_ALIGN_CENTER); + clutter_actor_set_y_align(actor_controls, CLUTTER_ACTOR_ALIGN_END); +} + static void build_chat_view(ChatView* self) { @@ -706,20 +993,19 @@ build_chat_view(ChatView* self) G_CALLBACK(on_webkit_drag_drop), self ); - priv->new_interaction_connection = QObject::connect( &*(*priv->accountInfo_)->conversationModel, &lrc::api::ConversationModel::newInteraction, [self, priv](const std::string& uid, uint64_t interactionId, lrc::api::interaction::Info interaction) { if (!priv->conversation_) return; - if (!priv->ready_ && priv->cpp_) { - priv->cpp_->interactionsBuffer_.emplace_back(CppImpl::Interaction { + if (!priv->ready_ && priv->cpp) { + priv->cpp->interactionsBuffer_.emplace_back(CppImpl::Interaction { uid, interactionId, interaction}); } else if (uid == priv->conversation_->uid) { print_interaction_to_buffer(self, interactionId, interaction); } }); - priv->cpp_ = new CppImpl(); + priv->cpp = new CppImpl(); if (webkit_chat_container_is_ready(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container))) webkit_chat_container_ready(self); @@ -728,7 +1014,8 @@ build_chat_view(ChatView* self) GtkWidget * chat_view_new (WebKitChatContainer* webkit_chat_container, AccountInfoPointer const & accountInfo, - lrc::api::conversation::Info* conversation) + lrc::api::conversation::Info* conversation, + lrc::api::AVModel& avModel) { ChatView *self = CHAT_VIEW(g_object_new(CHAT_VIEW_TYPE, NULL)); @@ -738,6 +1025,8 @@ chat_view_new (WebKitChatContainer* webkit_chat_container, priv->accountInfo_ = &accountInfo; build_chat_view(self); + priv->cpp->avModel_ = &avModel; + priv->readyToRecord_ = true; return (GtkWidget *)self; } @@ -762,3 +1051,10 @@ chat_view_set_header_visible(ChatView *self, gboolean visible) auto priv = CHAT_VIEW_GET_PRIVATE(self); webkit_chat_set_header_visible(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container), visible); } + +void +chat_view_set_record_visible(ChatView *self, gboolean visible) +{ + auto priv = CHAT_VIEW_GET_PRIVATE(self); + webkit_chat_set_record_visible(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container), visible); +} diff --git a/src/chatview.h b/src/chatview.h index f052f9dd13a9ac911e8de6984a2a2516a1e6155c..f0fd444b516c602bd49f9c9afebf02c450319f6b 100644 --- a/src/chatview.h +++ b/src/chatview.h @@ -34,6 +34,7 @@ namespace lrc { namespace api { +class AVModel; namespace conversation { struct Info; @@ -55,9 +56,11 @@ typedef struct _ChatViewClass ChatViewClass; GType chat_view_get_type (void) G_GNUC_CONST; GtkWidget *chat_view_new (WebKitChatContainer* view, AccountInfoPointer const & accountInfo, - lrc::api::conversation::Info* conversation); + lrc::api::conversation::Info* conversation, + lrc::api::AVModel& avModel); lrc::api::conversation::Info chat_view_get_conversation(ChatView*); void chat_view_update_temporary(ChatView*); void chat_view_set_header_visible(ChatView*, gboolean); +void chat_view_set_record_visible(ChatView*, gboolean); G_END_DECLS diff --git a/src/currentcallview.cpp b/src/currentcallview.cpp index 97cbba20e55d0f9598a630cc08e6e3a38126dad8..f8b697ac87181e71833a9dcfe30ed7c6125367ec 100644 --- a/src/currentcallview.cpp +++ b/src/currentcallview.cpp @@ -1298,10 +1298,11 @@ CppImpl::setCallInfo() // init chat view widgets->chat_view = chat_view_new(WEBKIT_CHAT_CONTAINER(widgets->webkit_chat_container), - *accountInfo, conversation); + *accountInfo, conversation, *avModel_); gtk_container_add(GTK_CONTAINER(widgets->frame_chat), widgets->chat_view); chat_view_set_header_visible(CHAT_VIEW(widgets->chat_view), FALSE); + chat_view_set_record_visible(CHAT_VIEW(widgets->chat_view), FALSE); } void diff --git a/src/incomingcallview.cpp b/src/incomingcallview.cpp index cfbeab3ae353dde88680d800b8e8ff3b23f4b000..be92d64322fdc4f3057c3789fe8d750dbf43889b 100644 --- a/src/incomingcallview.cpp +++ b/src/incomingcallview.cpp @@ -83,6 +83,8 @@ struct _IncomingCallViewPrivate QMetaObject::Connection state_change_connection; GSettings *settings; + + lrc::api::AVModel* avModel_; }; G_DEFINE_TYPE_WITH_PRIVATE(IncomingCallView, incoming_call_view, GTK_TYPE_BOX); @@ -295,9 +297,11 @@ set_call_info(IncomingCallView *view) { auto chat_view = chat_view_new(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container), *priv->accountInfo_, - priv->conversation_); + priv->conversation_, + *priv->avModel_); gtk_widget_show(chat_view); chat_view_set_header_visible(CHAT_VIEW(chat_view), FALSE); + chat_view_set_record_visible(CHAT_VIEW(chat_view), FALSE); gtk_container_add(GTK_CONTAINER(priv->frame_chat), chat_view); } @@ -313,6 +317,7 @@ incoming_call_view_new(WebKitChatContainer* view, priv->webkit_chat_container = GTK_WIDGET(view); priv->conversation_ = conversation; priv->accountInfo_ = &accountInfo; + priv->avModel_ = &avModel; priv->messaging_widget = messaging_widget_new(avModel, conversation, accountInfo); gtk_box_pack_start(GTK_BOX(priv->box_messaging_widget), priv->messaging_widget, TRUE, TRUE, 0); diff --git a/src/mediasettingsview.cpp b/src/mediasettingsview.cpp index 2bc8e2c444d9d150aa7f9c0b470bf68c7028914e..6406f2854ee1c9913b9f3b08d8aba8cd13f5bca8 100644 --- a/src/mediasettingsview.cpp +++ b/src/mediasettingsview.cpp @@ -592,5 +592,4 @@ media_settings_view_show_preview(MediaSettingsView *self, gboolean show_preview) priv->cpp->avModel_->setAudioMeterState(false); priv->cpp->avModel_->stopAudioDevice(); } - } diff --git a/src/ringmainwindow.cpp b/src/ringmainwindow.cpp index 736961369cea1861086695e2b99e0d7f8a6f9e1c..8c56d400dd92992cd6f796a4983989b4c6aba3c8 100644 --- a/src/ringmainwindow.cpp +++ b/src/ringmainwindow.cpp @@ -1489,7 +1489,7 @@ GtkWidget* CppImpl::displayChatView(lrc::api::conversation::Info conversation, bool redraw_webview) { chatViewConversation_.reset(new lrc::api::conversation::Info(conversation)); - auto* new_view = chat_view_new(webkitChatContainer(redraw_webview), accountInfo_, chatViewConversation_.get()); + auto* new_view = chat_view_new(webkitChatContainer(redraw_webview), accountInfo_, chatViewConversation_.get(), lrc_->getAVModel()); g_signal_connect_swapped(new_view, "hide-view-clicked", G_CALLBACK(on_hide_view_clicked), self); g_signal_connect(new_view, "add-conversation-clicked", G_CALLBACK(on_add_conversation_clicked), self); g_signal_connect(new_view, "place-audio-call-clicked", G_CALLBACK(on_place_audio_call_clicked), self); diff --git a/src/webkitchatcontainer.cpp b/src/webkitchatcontainer.cpp index f42d64636326da6ea9052498708185a78b01b315..5397e1a99d5c8a88d17e6cd8459418b2c0cc867d 100644 --- a/src/webkitchatcontainer.cpp +++ b/src/webkitchatcontainer.cpp @@ -761,6 +761,14 @@ webkit_chat_set_header_visible(WebKitChatContainer *view, bool isVisible) g_free(function_call); } +void +webkit_chat_set_record_visible(WebKitChatContainer *view, bool isVisible) +{ + gchar* function_call = g_strdup_printf("displayRecordControls(%s)", isVisible ? "true" : "false"); + webkit_chat_container_execute_js(view, function_call); + g_free(function_call); +} + void webkit_chat_update_chatview_frame(WebKitChatContainer *view, bool accountEnabled, bool isBanned, bool isTemporary, const gchar* alias, const gchar* bestId) { diff --git a/src/webkitchatcontainer.h b/src/webkitchatcontainer.h index 45d46a8d66a42a0def6a261042da6301cdb4953c..6d182f644c4c3d7d6c4360fb04ee80e2f2536ad1 100644 --- a/src/webkitchatcontainer.h +++ b/src/webkitchatcontainer.h @@ -55,6 +55,7 @@ gboolean webkit_chat_container_is_ready (WebKitChatContainer *view void webkit_chat_container_set_display_links (WebKitChatContainer *view, bool display); void webkit_chat_container_set_invitation (WebKitChatContainer *view, bool show, const std::string& contactUri, const std::string& contactId); void webkit_chat_set_header_visible (WebKitChatContainer *view, bool isVisible); +void webkit_chat_set_record_visible (WebKitChatContainer *view, bool isVisible); void webkit_chat_update_chatview_frame (WebKitChatContainer *view, bool accountEnabled, bool isBanned, bool isInvited, const gchar* alias, const gchar* bestId); G_END_DECLS diff --git a/ui/chatview.ui b/ui/chatview.ui index 7ec70fb59bfafd1599eab03577bbdf786da41215..eb67ffb62e0ab2aa600056bea3e79cf254b09147 100644 --- a/ui/chatview.ui +++ b/ui/chatview.ui @@ -4,101 +4,6 @@ <template class="ChatView" parent="GtkBox"> <property name="orientation">vertical</property> - <!-- chat info (only show for out of call conversations) --> - <child> - <object class="GtkBox" id="hbox_chat_info"> - <property name="visible">False</property> - <property name="no-show-all">True</property> - <property name="orientation">horizontal</property> - <property name="spacing">5</property> - <child> - <object class="GtkButton" id="button_close_chatview"> - <property name="image">image_back_arrow</property> - <property name="visible">True</property> - <property name="relief">none</property> - <property name="tooltip-text" translatable="yes">Hide chat view</property> - <child internal-child="accessible"> - <object class="AtkObject" id="button_close_chatview-atkobject"> - <property name="AtkObject::accessible-name" translatable="yes">Hide chat view</property> - </object> - </child> - </object> - </child> - <child> - <object class="GtkLabel" id="label_peer"> - <property name="visible">True</property> - <property name="selectable">True</property> - <property name="ellipsize">end</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - </packing> - </child> - <child> - <object class="GtkButton" id="button_placecall"> - <property name="visible">True</property> - <property name="image">image_place_call</property> - <property name="tooltip-text" translatable="yes">Place call</property> - <child internal-child="accessible"> - <object class="AtkObject" id="button_placecall-atkobject"> - <property name="AtkObject::accessible-name" translatable="yes">Place call</property> - </object> - </child> - </object> - <packing> - <property name="pack-type">end</property> - </packing> - </child> - <child> - <object class="GtkButton" id="button_place_audio_call"> - <property name="image">image_place_audio_only_call</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="tooltip-text" translatable="yes">Place audio-only call</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack_type">end</property> - <property name="position">2</property> - </packing> - </child> - <child> - <object class="GtkButton" id="button_add_to_conversations"> - <property name="visible">True</property> - <property name="image">image_invite</property> - <property name="tooltip-text" translatable="yes">Add to conversations</property> - </object> - <packing> - <property name="pack-type">end</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label_cm"> - <property name="visible">True</property> - <property name="selectable">True</property> - <property name="ellipsize">end</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - <packing> - <property name="pack-type">end</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - </packing> - </child> - <!-- end of chat info --> - <!-- start of chat text view --> <child> <object class="GtkScrolledWindow" id="scrolledwindow_chat">