Commit 3c22bc91 authored by Bob Ham's avatar Bob Ham
Browse files

Hook up Recent Calls list to database

Closes use-cases#113
Closes use-cases#115
parent 8862b03a
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
height="16"
id="svg7384"
version="1.1"
width="16">
<metadata
id="metadata90">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Gnome Symbolic Icon Theme</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<title
id="title9167">Gnome Symbolic Icon Theme</title>
<defs
id="defs7386">
<linearGradient
id="linearGradient7212"
osb:paint="solid">
<stop
id="stop7214"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
</linearGradient>
</defs>
<path
class="error"
id="path14066"
d="M 2 4 L 2 10 L 3 10 C 3.5522848 10 4 9.5522848 4 9 L 4 7.4140625 L 9 12.414062 L 13.697266 7.7167969 A 1 1 0 0 0 14 7 L 14 6 L 13 6 A 1 1 0 0 0 12.292969 6.2929688 L 9 9.5859375 L 5.4160156 6 L 7 6 C 7.5522848 6 8 5.5522848 8 5 L 8 4 L 2 4 z "
style="opacity:1;vector-effect:none;fill:#ed333b;fill-opacity:1;stroke:none;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
height="16"
id="svg7384"
version="1.1"
width="16">
<metadata
id="metadata90">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Gnome Symbolic Icon Theme</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<title
id="title9167">Gnome Symbolic Icon Theme</title>
<defs
id="defs7386">
<linearGradient
id="linearGradient7212"
osb:paint="solid">
<stop
id="stop7214"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
</linearGradient>
</defs>
<path
id="path819"
d="M 9,13 V 12 C 9,11.44772 8.552285,11 8,11 H 6.414062 l 6.289063,-6.2910203 c 1.027617,-0.93764 -0.463493,-2.43908 -1.408203,-1.41796 L 5,9.5937497 v -1.59375 c -0.0011,-0.55152 -0.448476,-0.99805 -1,-0.99805 v -0.00195 H 3 V 13 Z"
style="opacity:1;vector-effect:none;fill:#3584e4;fill-opacity:1;stroke:none;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
height="16"
id="svg7384"
version="1.1"
width="16">
<metadata
id="metadata90">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Gnome Symbolic Icon Theme</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<title
id="title9167">Gnome Symbolic Icon Theme</title>
<defs
id="defs7386">
<linearGradient
id="linearGradient7212"
osb:paint="solid">
<stop
id="stop7214"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
</linearGradient>
</defs>
<path
class="error"
style="opacity:1;vector-effect:none;fill:#ed333b;fill-opacity:1;stroke:none;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="M 14,12 V 6 H 13 C 12.447715,6 12,6.4477152 12,7 V 8.5859375 L 7,3.585938 2.302734,8.2832031 A 1,1 0 0 0 2,9 v 1 H 3 A 1,1 0 0 0 3.707031,9.707031 L 7,6.4140625 10.583984,10 H 9 c -0.5522848,0 -1,0.447715 -1,1 v 1 z"
id="path949" />
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
height="16"
id="svg7384"
version="1.1"
width="16">
<metadata
id="metadata90">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Gnome Symbolic Icon Theme</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<title
id="title9167">Gnome Symbolic Icon Theme</title>
<defs
id="defs7386">
<linearGradient
id="linearGradient7212"
osb:paint="solid">
<stop
id="stop7214"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
</linearGradient>
</defs>
<path
style="opacity:1;vector-effect:none;fill:#2ec27e;fill-opacity:1;stroke:none;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 7.000377,3.00001 v 1 c 0,0.55228 0.447715,1 1,1 h 1.585938 l -6.289063,6.29102 c -1.027617,0.93764 0.463493,2.43908 1.408203,1.41796 l 6.294922,-6.30273 v 1.59375 c 0.0011,0.55152 0.448476,0.99805 1,0.99805 v 0.00195 h 1 v -6 z"
id="path14090" />
</svg>
/* calls-application.c
*
* Copyright (C) 2018 Purism SPC
* Copyright (C) 2018, 2019 Purism SPC
* Copyright (C) 2018 Mohammed Sadiq <sadiq@sadiqpk.org>
*
* This file is part of Calls.
......@@ -126,11 +126,16 @@ static const GActionEntry actions[] =
static void
startup (GApplication *application)
{
GtkIconTheme *icon_theme;
G_APPLICATION_CLASS (calls_application_parent_class)->startup (application);
g_set_prgname (APP_ID);
g_set_application_name (_("Calls"));
icon_theme = gtk_icon_theme_get_default ();
gtk_icon_theme_add_resource_path (icon_theme, "/sm/puri/calls/");
g_action_map_add_action_entries (G_ACTION_MAP (application),
actions,
G_N_ELEMENTS (actions),
......@@ -253,7 +258,9 @@ activate (GApplication *application)
* But we assume that the application is closed by closing the
* window. In that case, GTK+ frees the resources right.
*/
window = GTK_WINDOW (calls_main_window_new (gtk_app, self->provider));
window = GTK_WINDOW
(calls_main_window_new (gtk_app, self->provider,
G_LIST_MODEL (self->record_store)));
calls_call_window_new (gtk_app, self->provider);
}
......@@ -282,6 +289,7 @@ dispose (GObject *object)
{
CallsApplication *self = (CallsApplication *)object;
g_clear_object (&self->record_store);
g_clear_object (&self->ringer);
g_clear_object (&self->provider);
......
/*
* Copyright (C) 2018, 2019 Purism SPC
*
* This file is part of Calls.
*
* Calls is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calls is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calls. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Bob Ham <bob.ham@puri.sm>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#include "calls-call-record-row.h"
#include "util.h"
#include <glib/gi18n.h>
#include <glib-object.h>
#include <glib.h>
#include <sys/time.h>
#include <errno.h>
struct _CallsCallRecordRow
{
GtkOverlay parent_instance;
GtkImage *avatar;
GtkImage *type;
GtkLabel *target;
GtkLabel *time;
CallsCallRecord *record;
gulong answered_notify_handler_id;
gulong end_notify_handler_id;
guint date_change_timeout;
CallsNewCallBox *new_call;
};
G_DEFINE_TYPE (CallsCallRecordRow, calls_call_record_row, GTK_TYPE_BOX);
enum {
PROP_0,
PROP_RECORD,
PROP_NEW_CALL,
PROP_LAST_PROP,
};
static GParamSpec *props[PROP_LAST_PROP];
static void
redial_clicked_cb (CallsCallRecordRow *self)
{
gchar *target;
g_object_get (self->record,
"target", &target,
NULL);
g_assert (target != NULL);
calls_new_call_box_dial (self->new_call, target);
g_free (target);
}
static void
nice_time (GDateTime *t,
gchar **nice,
gboolean *final)
{
GDateTime *now = g_date_time_new_now_local ();
const gboolean today =
calls_date_time_is_same_day (now, t);
const gboolean yesterday =
(!today && calls_date_time_is_yesterday (now, t));
g_assert (nice != NULL);
g_assert (final != NULL);
if (today || yesterday)
{
gchar *n = g_date_time_format (t, "%R");
if (yesterday)
{
gchar *s;
s = g_strdup_printf (_("%s\nyesterday"), n);
g_free (n);
n = s;
}
*nice = n;
*final = FALSE;
}
else if (calls_date_time_is_same_year (now, t))
{
*nice = g_date_time_format (t, "%b %-d");
*final = FALSE;
}
else
{
*nice = g_date_time_format (t, "%Y");
*final = TRUE;
}
g_date_time_unref (now);
}
static void
update_time (CallsCallRecordRow *self,
GDateTime *end,
gboolean *final)
{
gchar *nice;
nice_time (end, &nice, final);
gtk_label_set_text (self->time, nice);
g_free (nice);
}
static gboolean date_change_cb (CallsCallRecordRow *self);
static void
setup_date_change_timeout (CallsCallRecordRow *self)
{
GDateTime *gnow, *gnextday, *gtomorrow;
struct timeval now, tomorrow, delta;
int err;
guint interval;
// Get the time now
gnow = g_date_time_new_now_local ();
// Get the next day
gnextday = g_date_time_add_days (gnow, 1);
g_date_time_unref (gnow);
// Get the start of the next day
gtomorrow =
g_date_time_new (g_date_time_get_timezone (gnextday),
g_date_time_get_year (gnextday),
g_date_time_get_month (gnextday),
g_date_time_get_day_of_month (gnextday),
0,
0,
0.0);
g_date_time_unref (gnextday);
// Convert to a timeval
tomorrow.tv_sec = g_date_time_to_unix (gtomorrow);
tomorrow.tv_usec = 0;
g_date_time_unref (gtomorrow);
// Get the precise time now
err = gettimeofday (&now, NULL);
if (err == -1)
{
g_warning ("Error getting time to set date change timeout: %s",
g_strerror (errno));
return;
}
// Find how long from now until the start of the next day
timersub (&tomorrow, &now, &delta);
// Convert to milliseconds
interval =
(delta.tv_sec * 1000)
+
(delta.tv_usec / 1000);
// Add the timeout
self->date_change_timeout =
g_timeout_add (interval,
(GSourceFunc)date_change_cb,
self);
}
static gboolean
date_change_cb (CallsCallRecordRow *self)
{
GDateTime *end;
gboolean final;
g_object_get (G_OBJECT (self->record),
"end", &end,
NULL);
g_assert (end != NULL);
update_time (self, end, &final);
g_date_time_unref (end);
if (final)
{
self->date_change_timeout = 0;
}
else
{
setup_date_change_timeout (self);
}
return FALSE;
}
static void
update (CallsCallRecordRow *self,
gboolean inbound,
GDateTime *answered,
GDateTime *end)
{
gboolean missed = FALSE;
gchar *type_icon_name;
if (end)
{
gboolean time_final;
update_time (self, end, &time_final);
if (!time_final && !self->date_change_timeout)
{
setup_date_change_timeout (self);
}
if (!answered)
{
missed = TRUE;
}
}
type_icon_name = g_strdup_printf
("call-arrow-%s%s-symbolic",
inbound ? "incoming" : "outgoing",
missed ? "-missed" : "");
gtk_image_set_from_icon_name (self->type, type_icon_name,
GTK_ICON_SIZE_MENU);
g_free (type_icon_name);
}
static void
notify_cb (CallsCallRecordRow *self,
GParamSpec *pspec,
CallsCallRecord *record)
{
gboolean inbound;
GDateTime *answered;
GDateTime *end;
g_object_get (G_OBJECT (self->record),
"inbound", &inbound,
"answered", &answered,
"end", &end,
NULL);
update (self, inbound, answered, end);
if (answered)
{
g_date_time_unref (answered);
calls_clear_signal (record, &self->answered_notify_handler_id);
}
if (end)
{
g_date_time_unref (end);
calls_clear_signal (record, &self->end_notify_handler_id);
}
}
static void
set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
CallsCallRecordRow *self = CALLS_CALL_RECORD_ROW (object);
switch (property_id) {
case PROP_RECORD:
g_set_object (&self->record,
CALLS_CALL_RECORD (g_value_get_object (value)));
break;
case PROP_NEW_CALL:
g_set_object (&self->new_call,
CALLS_NEW_CALL_BOX (g_value_get_object (value)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
constructed (GObject *object)
{
GObjectClass *obj_class = g_type_class_peek (G_TYPE_OBJECT);
CallsCallRecordRow *self = CALLS_CALL_RECORD_ROW (object);
gchar *target;
gboolean inbound;
GDateTime *answered;
GDateTime *end;
g_object_get (G_OBJECT (self->record),
"target", &target,
"inbound", &inbound,
"answered", &answered,
"end", &end,
NULL);
gtk_label_set_text (self->target, target);
g_free (target);
if (!end)
{
self->end_notify_handler_id =
g_signal_connect_swapped (self->record,
"notify::end",
G_CALLBACK (notify_cb),
self);
if (!answered)
{
self->answered_notify_handler_id =
g_signal_connect_swapped (self->record,
"notify::answered",
G_CALLBACK (notify_cb),
self);
}
}
update (self, inbound, answered, end);
calls_date_time_unref (answered);
calls_date_time_unref (end);
obj_class->constructed (object);
}
static void
get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
CallsCallRecordRow *self = CALLS_CALL_RECORD_ROW (object);
switch (property_id) {
case PROP_RECORD:
g_value_set_object (value, self->record);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
dispose (GObject *object)
{
GObjectClass *obj_class = g_type_class_peek (G_TYPE_OBJECT);
CallsCallRecordRow *self = CALLS_CALL_RECORD_ROW (object);
g_clear_object (&self->new_call);
calls_clear_source (&self->date_change_timeout);
calls_clear_signal (self->record, &self->answered_notify_handler_id);
calls_clear_signal (self->record, &self->end_notify_handler_id);
g_clear_object (&self->record);
obj_class->dispose (object);
}
static void
calls_call_record_row_class_init (CallsCallRecordRowClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);