Person*
chat_view_get_person(ChatView *self)
{
    g_return_val_if_fail(IS_CHAT_VIEW(self), nullptr);
    auto priv = CHAT_VIEW_GET_PRIVATE(self);

    return priv->person;
}
Call*
chat_view_get_call(ChatView *self)
{
    g_return_val_if_fail(IS_CHAT_VIEW(self), nullptr);
    auto priv = CHAT_VIEW_GET_PRIVATE(self);

    return priv->call;
}
ContactMethod*
chat_view_get_cm(ChatView *self)
{
    g_return_val_if_fail(IS_CHAT_VIEW(self), nullptr);
    auto priv = CHAT_VIEW_GET_PRIVATE(self);

    return priv->cm;
}
Esempio n. 4
0
static void
update_contact_methods(ChatView *self)
{
    g_return_if_fail(IS_CHAT_VIEW(self));
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

    g_return_if_fail(priv->person);

    /* model for the combobox for the choice of ContactMethods */
    auto cm_model = gtk_list_store_new(
        1, G_TYPE_POINTER
    );

    auto cms = priv->person->phoneNumbers();
    for (int i = 0; i < cms.size(); ++i) {
        GtkTreeIter iter;
        gtk_list_store_append(cm_model, &iter);
        gtk_list_store_set(cm_model, &iter,
                           0, cms.at(i),
                           -1);
    }

    gtk_combo_box_set_model(GTK_COMBO_BOX(priv->combobox_cm), GTK_TREE_MODEL(cm_model));
    g_object_unref(cm_model);

    auto renderer = gtk_cell_renderer_text_new();
    g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(priv->combobox_cm), renderer, FALSE);
    gtk_cell_layout_set_cell_data_func(
        GTK_CELL_LAYOUT(priv->combobox_cm),
        renderer,
        (GtkCellLayoutDataFunc)render_contact_method,
        nullptr, nullptr);

    /* select the last used cm */
    if (!cms.isEmpty()) {
        auto last_used_cm = cms.at(0);
        int last_used_cm_idx = 0;
        for (int i = 1; i < cms.size(); ++i) {
            auto new_cm = cms.at(i);
            if (difftime(new_cm->lastUsed(), last_used_cm->lastUsed()) > 0) {
                last_used_cm = new_cm;
                last_used_cm_idx = i;
            }
        }

        gtk_combo_box_set_active(GTK_COMBO_BOX(priv->combobox_cm), last_used_cm_idx);
    }

    /* show the combo box if there is more than one cm to choose from */
    if (cms.size() > 1)
        gtk_widget_show_all(priv->combobox_cm);
    else
        gtk_widget_hide(priv->combobox_cm);
}
static void
print_text_recording(Media::TextRecording *recording, ChatView *self)
{
    g_return_if_fail(IS_CHAT_VIEW(self));
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

     /* set the photos of the chat participants */
     set_participant_images(self);

    /* only text messages are supported for now */
    auto model = recording->instantTextMessagingModel();

    /* new model, disconnect from the old model updates and clear the text buffer */
    QObject::disconnect(priv->new_message_connection);

    /* put all the messages in the im model into the text view */
    for (int row = 0; row < model->rowCount(); ++row) {
        QModelIndex idx = model->index(row, 0);
        print_message_to_buffer(self, idx);
    }
    /* mark all messages as read */
    recording->setAllRead();


    /* messages modified */
    /* connecting on instantMessagingModel and not textMessagingModel */
    priv->message_changed_connection = QObject::connect(
        model,
        &QAbstractItemModel::dataChanged,
        [self, priv] (const QModelIndex & topLeft, G_GNUC_UNUSED const QModelIndex & bottomRight)
        {
            webkit_chat_container_update_message(
                WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
                topLeft
            );
        }
    );

    /* append new messages */
    priv->new_message_connection = QObject::connect(
        model,
        &QAbstractItemModel::rowsInserted,
        [self, priv, model] (const QModelIndex &parent, int first, int last) {
            for (int row = first; row <= last; ++row) {
                QModelIndex idx = model->index(row, 0, parent);
                print_message_to_buffer(self, idx);
                /* make sure these messages are marked as read */
                model->setData(idx, true, static_cast<int>(Media::TextRecording::Role::IsRead));
                g_signal_emit(G_OBJECT(self), chat_view_signals[NEW_MESSAGES_DISPLAYED], 0);
            }
        }
    );
}
Esempio n. 6
0
static void
selected_cm_changed(GtkComboBox *box, ChatView *self)
{
    g_return_if_fail(IS_CHAT_VIEW(self));
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

    auto cms = priv->person->phoneNumbers();
    auto active = gtk_combo_box_get_active(box);
    if (active >= 0 && active < cms.size()) {
        print_text_recording(cms.at(active)->textRecording(), self);
    } else {
        g_warning("no valid ContactMethod selected to display chat conversation");
    }
}
Esempio n. 7
0
static void
update_name(ChatView *self)
{
    g_return_if_fail(IS_CHAT_VIEW(self));
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

    g_return_if_fail(priv->person || priv->cm);

    QString name;
    if (priv->person) {
        name = priv->person->roleData(static_cast<int>(Ring::Role::Name)).toString();
    } else {
        name = priv->cm->roleData(static_cast<int>(Ring::Role::Name)).toString();
    }
    gtk_label_set_text(GTK_LABEL(priv->label_peer), name.toUtf8().constData());
}
Esempio n. 8
0
static void
print_text_recording(Media::TextRecording *recording, ChatView *self)
{
    g_return_if_fail(IS_CHAT_VIEW(self));
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

    /* only text messages are supported for now */
    auto model = recording->instantTextMessagingModel();

    /* new model, disconnect from the old model updates and clear the text buffer */
    QObject::disconnect(priv->new_message_connection);

    GtkTextBuffer *new_buffer = gtk_text_buffer_new(NULL);
    gtk_text_view_set_buffer(GTK_TEXT_VIEW(priv->textview_chat), new_buffer);

    /* add tags to the buffer */
    gtk_text_buffer_create_tag(new_buffer, "bold", "weight", PANGO_WEIGHT_BOLD, NULL);

    g_object_unref(new_buffer);

    /* put all the messages in the im model into the text view */
    for (int row = 0; row < model->rowCount(); ++row) {
        QModelIndex idx = model->index(row, 0);
        print_message_to_buffer(idx, new_buffer);
    }
    /* mark all messages as read */
    recording->setAllRead();

    /* append new messages */
    priv->new_message_connection = QObject::connect(
        model,
        &QAbstractItemModel::rowsInserted,
        [self, priv, model] (const QModelIndex &parent, int first, int last) {
            for (int row = first; row <= last; ++row) {
                QModelIndex idx = model->index(row, 0, parent);
                print_message_to_buffer(idx, gtk_text_view_get_buffer(GTK_TEXT_VIEW(priv->textview_chat)));
                /* make sure these messages are marked as read */
                model->setData(idx, true, static_cast<int>(Media::TextRecording::Role::IsRead));
                g_signal_emit(G_OBJECT(self), chat_view_signals[NEW_MESSAGES_DISPLAYED], 0);
            }
        }
    );
}
static void
send_chat(G_GNUC_UNUSED GtkWidget *widget, ChatView *self)
{
    g_return_if_fail(IS_CHAT_VIEW(self));
    ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);

    /* make sure there is more than just whitespace, but if so, send the original text */
    const auto text = QString(gtk_entry_get_text(GTK_ENTRY(priv->entry_chat_input)));
    if (!text.trimmed().isEmpty()) {
        QMap<QString, QString> messages;
        messages["text/plain"] = text;

        if (priv->call) {
            // in call message
            priv->call->addOutgoingMedia<Media::Text>()->send(messages);
        } else if (priv->person) {
            // get the chosen cm
            auto active = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->combobox_cm));
            if (active >= 0) {
                auto cm = priv->person->phoneNumbers().at(active);
                if (!cm->sendOfflineTextMessage(messages))
                    g_warning("message failed to send"); // TODO: warn the user about this in the UI
            } else {
                g_warning("no ContactMethod chosen; message not sent");
            }
        } else if (priv->cm) {
            if (!priv->cm->sendOfflineTextMessage(messages))
                g_warning("message failed to send"); // TODO: warn the user about this in the UI
        } else {
            g_warning("no Call, Person, or ContactMethod set; message not sent");
        }

        /* clear the entry */
        gtk_entry_set_text(GTK_ENTRY(priv->entry_chat_input), "");
    }
}
Esempio n. 10
0
static gboolean
selected_item_changed(RingMainWindow *win)
{
    // g_debug("item changed");
    RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(win));

    /* if we're showing the settings, then nothing needs to be done as the call
       view is not shown */
    if (priv->show_settings) return G_SOURCE_REMOVE;

    auto idx_selected = RecentModel::instance().selectionModel()->currentIndex();

    /* we prioritize showing the call view; but if the call is over we go back to showing the chat view */
    if(auto call = RecentModel::instance().getActiveCall(idx_selected)) {
        /* check if we need to change the view */
        auto current_view = gtk_bin_get_child(GTK_BIN(priv->frame_call));
        auto state = call->lifeCycleState();

        /* check what the current state is vs what is displayed */
        switch(state) {
            case Call::LifeCycleState::CREATION:
            case Call::LifeCycleState::FINISHED:
            /* go back to incoming call view;
             * it will show that the call failed and offer to hang it up */
            case Call::LifeCycleState::INITIALIZATION:
                {
                    /* show the incoming call view */
                    if (!IS_INCOMING_CALL_VIEW(current_view)) {
                        auto new_view = incoming_call_view_new();
                        incoming_call_view_set_call_info(INCOMING_CALL_VIEW(new_view), CallModel::instance().getIndex(call));
                        gtk_container_remove(GTK_CONTAINER(priv->frame_call), current_view);
                        gtk_container_add(GTK_CONTAINER(priv->frame_call), new_view);
                        gtk_widget_show(new_view);
                    }
                }
                break;
            case Call::LifeCycleState::PROGRESS:
                {
                    /* show the current call view */
                    if (!IS_CURRENT_CALL_VIEW(current_view)) {
                        auto new_view = current_call_view_new();
                        g_signal_connect(new_view, "video-double-clicked", G_CALLBACK(video_double_clicked), win);
                        current_call_view_set_call_info(CURRENT_CALL_VIEW(new_view), CallModel::instance().getIndex(call));
                        gtk_container_remove(GTK_CONTAINER(priv->frame_call), current_view);
                        gtk_container_add(GTK_CONTAINER(priv->frame_call), new_view);
                        gtk_widget_show(new_view);
                    }
                }
                break;
            case Call::LifeCycleState::COUNT__:
                g_warning("LifeCycleState should never be COUNT");
                break;
        }
    } else if (idx_selected.isValid()) {
        /* otherwise, the call is over and is already removed from the RecentModel */
        auto current_view = gtk_bin_get_child(GTK_BIN(priv->frame_call));
        leave_full_screen(win);

        /* show the chat view */
        if (!IS_CHAT_VIEW(current_view)) {
            auto type = idx_selected.data(static_cast<int>(Ring::Role::ObjectType)).value<Ring::ObjectType>();
            auto object = idx_selected.data(static_cast<int>(Ring::Role::Object));
            if (type == Ring::ObjectType::Person && object.isValid()) {
                /* show chat view constructed from Person object */
                auto new_view = chat_view_new_person(object.value<Person *>());
                gtk_container_remove(GTK_CONTAINER(priv->frame_call), current_view);
                gtk_container_add(GTK_CONTAINER(priv->frame_call), new_view);
                gtk_widget_show(new_view);
            } else if (type == Ring::ObjectType::ContactMethod && object.isValid()) {
                /* show chat view constructed from CM */
                auto new_view = chat_view_new_cm(object.value<ContactMethod *>());
                gtk_container_remove(GTK_CONTAINER(priv->frame_call), current_view);
                gtk_container_add(GTK_CONTAINER(priv->frame_call), new_view);
                gtk_widget_show(new_view);
            }
        }
    }

    return G_SOURCE_REMOVE;
}