mirror of
https://gitlab.gnome.org/GNOME/calls.git
synced 2024-12-12 15:47:35 +00:00
Implement delete call with context menu on longpress
* src/ui/call-record-row.ui: Add menu, GtkPopover. Surround existing elements with GtkEventBox to capture longpress/rightclicks * src/calls-call-record-row.c: Provide functions emiting "call-delete" signal, add widgets from ui file * src/calls-record.c: Add "call-delete" signal * src/calls-history-box.c: Add callback for "call-delete" signal * src/calls-record-store.c: Add callback for "call-delete" signal * src/util.c: Add convenience function calls_find_in_store for finding items in ListModel * src/util.h: Add declaration of calls_find_in_store
This commit is contained in:
parent
b15c2876da
commit
4bf5cd5232
7 changed files with 330 additions and 77 deletions
|
@ -44,6 +44,13 @@ struct _CallsCallRecordRow
|
||||||
GtkLabel *target;
|
GtkLabel *target;
|
||||||
GtkLabel *time;
|
GtkLabel *time;
|
||||||
GtkButton *button;
|
GtkButton *button;
|
||||||
|
GtkPopover *popover;
|
||||||
|
GtkGesture *gesture;
|
||||||
|
GtkEventBox *event_box;
|
||||||
|
|
||||||
|
GMenu *context_menu;
|
||||||
|
|
||||||
|
GActionMap *action_map;
|
||||||
|
|
||||||
CallsCallRecord *record;
|
CallsCallRecord *record;
|
||||||
gulong answered_notify_handler_id;
|
gulong answered_notify_handler_id;
|
||||||
|
@ -392,6 +399,45 @@ setup_contact (CallsCallRecordRow *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
context_menu (GtkWidget *self,
|
||||||
|
GdkEvent *event)
|
||||||
|
{
|
||||||
|
gtk_popover_popup (CALLS_CALL_RECORD_ROW (self)->popover);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
calls_call_record_row_popup_menu (GtkWidget *self)
|
||||||
|
{
|
||||||
|
context_menu (self, NULL);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
long_pressed (GtkGestureLongPress *gesture,
|
||||||
|
gdouble x,
|
||||||
|
gdouble y,
|
||||||
|
GtkWidget *self)
|
||||||
|
{
|
||||||
|
context_menu (self, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
calls_call_record_row_button_press_event (GtkWidget *self,
|
||||||
|
GdkEventButton *event)
|
||||||
|
{
|
||||||
|
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
|
||||||
|
{
|
||||||
|
context_menu (self, (GdkEvent *) event);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return GTK_WIDGET_CLASS (calls_call_record_row_parent_class)->button_press_event (self, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_property (GObject *object,
|
set_property (GObject *object,
|
||||||
guint property_id,
|
guint property_id,
|
||||||
|
@ -480,6 +526,8 @@ dispose (GObject *object)
|
||||||
|
|
||||||
g_clear_object (&self->contact);
|
g_clear_object (&self->contact);
|
||||||
g_clear_object (&self->contacts);
|
g_clear_object (&self->contacts);
|
||||||
|
g_clear_object (&self->action_map);
|
||||||
|
g_clear_object (&self->gesture);
|
||||||
|
|
||||||
calls_clear_source (&self->date_change_timeout);
|
calls_clear_source (&self->date_change_timeout);
|
||||||
calls_clear_signal (self->record, &self->answered_notify_handler_id);
|
calls_clear_signal (self->record, &self->answered_notify_handler_id);
|
||||||
|
@ -501,6 +549,9 @@ calls_call_record_row_class_init (CallsCallRecordRowClass *klass)
|
||||||
object_class->get_property = get_property;
|
object_class->get_property = get_property;
|
||||||
object_class->dispose = dispose;
|
object_class->dispose = dispose;
|
||||||
|
|
||||||
|
widget_class->popup_menu = calls_call_record_row_popup_menu;
|
||||||
|
widget_class->button_press_event = calls_call_record_row_button_press_event;
|
||||||
|
|
||||||
props[PROP_RECORD] =
|
props[PROP_RECORD] =
|
||||||
g_param_spec_object ("record",
|
g_param_spec_object ("record",
|
||||||
"Record",
|
"Record",
|
||||||
|
@ -524,18 +575,59 @@ calls_call_record_row_class_init (CallsCallRecordRowClass *klass)
|
||||||
gtk_widget_class_bind_template_child (widget_class, CallsCallRecordRow, target);
|
gtk_widget_class_bind_template_child (widget_class, CallsCallRecordRow, target);
|
||||||
gtk_widget_class_bind_template_child (widget_class, CallsCallRecordRow, time);
|
gtk_widget_class_bind_template_child (widget_class, CallsCallRecordRow, time);
|
||||||
gtk_widget_class_bind_template_child (widget_class, CallsCallRecordRow, button);
|
gtk_widget_class_bind_template_child (widget_class, CallsCallRecordRow, button);
|
||||||
|
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CallsCallRecordRow, event_box);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CallsCallRecordRow, popover);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CallsCallRecordRow, context_menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_call_activated (GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
GtkWidget *self = GTK_WIDGET (data);
|
||||||
|
g_signal_emit_by_name (CALLS_CALL_RECORD_ROW (self)->record, "call-delete");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static GActionEntry entries[] =
|
||||||
|
{
|
||||||
|
{ "delete-call", delete_call_activated, NULL, NULL, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
calls_call_record_row_init (CallsCallRecordRow *self)
|
calls_call_record_row_init (CallsCallRecordRow *self)
|
||||||
{
|
{
|
||||||
|
GAction *act;
|
||||||
gtk_widget_init_template (GTK_WIDGET (self));
|
gtk_widget_init_template (GTK_WIDGET (self));
|
||||||
|
|
||||||
g_signal_connect (self->avatar,
|
g_signal_connect (self->avatar,
|
||||||
"notify::text",
|
"notify::text",
|
||||||
G_CALLBACK (avatar_text_changed_cb),
|
G_CALLBACK (avatar_text_changed_cb),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
self->action_map = G_ACTION_MAP (g_simple_action_group_new ());
|
||||||
|
g_action_map_add_action_entries (self->action_map,
|
||||||
|
entries,
|
||||||
|
G_N_ELEMENTS (entries),
|
||||||
|
self);
|
||||||
|
gtk_widget_insert_action_group (GTK_WIDGET (self),
|
||||||
|
"row-history",
|
||||||
|
G_ACTION_GROUP (self->action_map));
|
||||||
|
|
||||||
|
act = g_action_map_lookup_action (self->action_map, "delete-call");
|
||||||
|
g_simple_action_set_enabled (G_SIMPLE_ACTION (act), TRUE);
|
||||||
|
|
||||||
|
self->gesture = gtk_gesture_long_press_new (GTK_WIDGET (self->event_box));
|
||||||
|
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (self->gesture), TRUE);
|
||||||
|
g_signal_connect (self->gesture, "pressed", G_CALLBACK (long_pressed), self);
|
||||||
|
|
||||||
|
gtk_popover_bind_model (self->popover,
|
||||||
|
G_MENU_MODEL (self->context_menu),
|
||||||
|
"row-history");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,12 @@ enum {
|
||||||
};
|
};
|
||||||
static GParamSpec *props[PROP_LAST_PROP];
|
static GParamSpec *props[PROP_LAST_PROP];
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SIGNAL_CALL_DELETE,
|
||||||
|
SIGNAL_LAST_SIGNAL,
|
||||||
|
};
|
||||||
|
static guint signals [SIGNAL_LAST_SIGNAL];
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_property (GObject *object,
|
get_property (GObject *object,
|
||||||
|
@ -167,6 +173,15 @@ calls_call_record_class_init (CallsCallRecordClass *klass)
|
||||||
object_class->get_property = get_property;
|
object_class->get_property = get_property;
|
||||||
object_class->set_property = set_property;
|
object_class->set_property = set_property;
|
||||||
|
|
||||||
|
signals[SIGNAL_CALL_DELETE] =
|
||||||
|
g_signal_new ("call-delete",
|
||||||
|
G_TYPE_FROM_CLASS (klass),
|
||||||
|
G_SIGNAL_RUN_FIRST,
|
||||||
|
0,
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
G_TYPE_NONE,
|
||||||
|
0, NULL);
|
||||||
|
|
||||||
gom_resource_class_set_table (resource_class, "calls");
|
gom_resource_class_set_table (resource_class, "calls");
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -102,13 +102,51 @@ header_cb (GtkListBoxRow *row,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_call_cb (CallsCallRecord *record,
|
||||||
|
CallsHistoryBox *self)
|
||||||
|
{
|
||||||
|
guint position;
|
||||||
|
guint id;
|
||||||
|
gboolean ok;
|
||||||
|
|
||||||
|
g_return_if_fail (CALLS_IS_CALL_RECORD (record));
|
||||||
|
|
||||||
|
ok = calls_find_in_store (self->model,
|
||||||
|
record,
|
||||||
|
&position);
|
||||||
|
|
||||||
|
g_object_get (G_OBJECT (record),
|
||||||
|
"id",
|
||||||
|
&id,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
g_warning ("Could not find record with id %u in model",
|
||||||
|
id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_store_remove ((GListStore *) self->model, position);
|
||||||
|
|
||||||
|
update(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static GtkWidget *
|
static GtkWidget *
|
||||||
create_row_cb (CallsCallRecord *record,
|
create_row_cb (CallsCallRecord *record,
|
||||||
CallsHistoryBox *self)
|
CallsHistoryBox *self)
|
||||||
{
|
{
|
||||||
return GTK_WIDGET (calls_call_record_row_new (record,
|
GtkWidget *row_widget;
|
||||||
|
row_widget = GTK_WIDGET (calls_call_record_row_new (record,
|
||||||
self->contacts));
|
self->contacts));
|
||||||
|
|
||||||
|
g_signal_connect (record,
|
||||||
|
"call-delete",
|
||||||
|
G_CALLBACK (delete_call_cb),
|
||||||
|
self);
|
||||||
|
return row_widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,56 @@ struct _CallsRecordStore
|
||||||
G_DEFINE_TYPE (CallsRecordStore, calls_record_store, G_TYPE_LIST_STORE);
|
G_DEFINE_TYPE (CallsRecordStore, calls_record_store, G_TYPE_LIST_STORE);
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_record_cb (GomResource *resource,
|
||||||
|
GAsyncResult *res,
|
||||||
|
CallsRecordStore *self)
|
||||||
|
{
|
||||||
|
g_autoptr (GError) error = NULL;
|
||||||
|
gboolean ok;
|
||||||
|
guint id;
|
||||||
|
|
||||||
|
ok = gom_resource_delete_finish (resource,
|
||||||
|
res,
|
||||||
|
&error);
|
||||||
|
|
||||||
|
g_object_get (G_OBJECT (resource),
|
||||||
|
"id",
|
||||||
|
&id,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
g_warning ("Error deleting call record with id %u from database %s",
|
||||||
|
id, error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_warning ("Unknown error deleting call record with id %u from database",
|
||||||
|
id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g_debug ("Successfully deleted call record with id %u from database",
|
||||||
|
id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_call_cb (CallsCallRecord *record,
|
||||||
|
CallsRecordStore *self)
|
||||||
|
{
|
||||||
|
gom_resource_delete_async (GOM_RESOURCE (record),
|
||||||
|
(GAsyncReadyCallback) delete_record_cb,
|
||||||
|
self);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
load_calls_fetch_cb (GomResourceGroup *group,
|
load_calls_fetch_cb (GomResourceGroup *group,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
|
@ -127,6 +177,11 @@ load_calls_fetch_cb (GomResourceGroup *group,
|
||||||
{
|
{
|
||||||
g_date_time_unref (end);
|
g_date_time_unref (end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_signal_connect (record,
|
||||||
|
"call-delete",
|
||||||
|
G_CALLBACK (delete_call_cb),
|
||||||
|
self);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_list_store_splice (G_LIST_STORE (self),
|
g_list_store_splice (G_LIST_STORE (self),
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="activatable">False</property>
|
<property name="activatable">False</property>
|
||||||
<property name="selectable">False</property>
|
<property name="selectable">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEventBox" id="event_box">
|
||||||
|
<property name="visible">True</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkBox">
|
<object class="GtkBox">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -97,5 +100,18 @@
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</template>
|
</template>
|
||||||
|
<object class="GtkPopover" id="popover">
|
||||||
|
<property name="relative-to">CallsCallRecordRow</property>
|
||||||
|
</object>
|
||||||
|
<menu id="context_menu">
|
||||||
|
<section>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">_Delete Call</attribute>
|
||||||
|
<attribute name="action">delete-call</attribute>
|
||||||
|
</item>
|
||||||
|
</section>
|
||||||
|
</menu>
|
||||||
</interface>
|
</interface>
|
||||||
|
|
33
src/util.c
33
src/util.c
|
@ -142,3 +142,36 @@ calls_date_time_is_same_year (GDateTime *a,
|
||||||
g_date_time_get_year (a) ==
|
g_date_time_get_year (a) ==
|
||||||
g_date_time_get_year (b);
|
g_date_time_get_year (b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
calls_find_in_store (GListModel *list,
|
||||||
|
gpointer item,
|
||||||
|
guint *position)
|
||||||
|
{
|
||||||
|
#if GLIB_CHECK_VERSION(2, 64, 0)
|
||||||
|
return g_list_store_find ((GListStore *) list,
|
||||||
|
item,
|
||||||
|
position);
|
||||||
|
#else
|
||||||
|
guint count;
|
||||||
|
|
||||||
|
g_return_val_if_fail (G_IS_LIST_MODEL (list), FALSE);
|
||||||
|
|
||||||
|
count = g_list_model_get_n_items (list);
|
||||||
|
|
||||||
|
for (guint i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
g_autoptr (GObject) object = NULL;
|
||||||
|
|
||||||
|
object = g_list_model_get_item (list, i);
|
||||||
|
|
||||||
|
if (object == item)
|
||||||
|
{
|
||||||
|
*position = i;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -138,6 +138,10 @@ gboolean calls_date_time_is_yesterday (GDateTime *now,
|
||||||
gboolean calls_date_time_is_same_year (GDateTime *a,
|
gboolean calls_date_time_is_same_year (GDateTime *a,
|
||||||
GDateTime *b);
|
GDateTime *b);
|
||||||
|
|
||||||
|
gboolean calls_find_in_store (GListModel *list,
|
||||||
|
gpointer item,
|
||||||
|
guint *position);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* CALLS__UTIL_H__ */
|
#endif /* CALLS__UTIL_H__ */
|
||||||
|
|
Loading…
Reference in a new issue