Add navigation for chat history

This commit is contained in:
Daniel 2018-01-29 14:00:15 +01:00
parent 5ce0c65ce4
commit b0bf74337c
3 changed files with 233 additions and 12 deletions

View File

@ -732,6 +732,64 @@ class Logger:
# attributes set to None because of the MAX() function
return self.con.execute(sql, tuple(jids)).fetchone().time
def get_first_date_that_has_logs(self, account, jid):
"""
Get the timestamp of the first message we received for the jid.
:param account: The account
:param jid: The jid for which we request the first timestamp
returns a timestamp or None
"""
jids = self._get_family_jids(account, jid)
kinds = map(str, [KindConstant.STATUS,
KindConstant.GCSTATUS])
sql = '''
SELECT MIN(time) as time FROM logs
NATURAL JOIN jids WHERE jid IN ({jids})
AND kind NOT IN ({kinds})
'''.format(jids=', '.join('?' * len(jids)),
kinds=', '.join(kinds))
# fetchone() returns always at least one Row with all
# attributes set to None because of the MIN() function
return self.con.execute(sql, tuple(jids)).fetchone().time
def get_date_has_logs(self, account, jid, date):
"""
Get single timestamp of a message we received for the jid
in the time range of one day.
:param account: The account
:param jid: The jid for which we request the first timestamp
:param date: datetime.datetime instance
example: datetime.datetime(year, month, day)
returns a timestamp or None
"""
jids = self._get_family_jids(account, jid)
kinds = map(str, [KindConstant.STATUS,
KindConstant.GCSTATUS])
delta = datetime.timedelta(
hours=23, minutes=59, seconds=59, microseconds=999999)
sql = '''
SELECT time
FROM logs NATURAL JOIN jids WHERE jid IN ({jids})
AND time BETWEEN ? AND ?
'''.format(jids=', '.join('?' * len(jids)))
return self.con.execute(sql, tuple(jids) +
(date.timestamp(),
(date + delta).timestamp())).fetchone()
def get_room_last_message_time(self, account, jid):
"""
Get the timestamp of the last message we received in a room.

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<!-- Generated with glade 3.20.2 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkApplicationWindow" id="history_window">
@ -35,7 +35,7 @@
<object class="GtkEntry" id="query_entry">
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
<property name="placeholder_text">Enter name / JID of contact or groupchat</property>
<property name="placeholder_text" translatable="yes">Enter name / JID of contact or groupchat</property>
</object>
<packing>
<property name="expand">True</property>
@ -102,11 +102,13 @@
<object class="GtkPaned" id="hpaned">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_bottom">5</property>
<property name="position">165</property>
<child>
<object class="GtkBox" id="vbox2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_right">5</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
@ -123,7 +125,98 @@
</packing>
</child>
<child>
<placeholder/>
<object class="GtkButtonBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="spacing">5</property>
<property name="layout_style">expand</property>
<child>
<object class="GtkButton" id="button_first_day">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="_change_date" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">go-first-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_previous_day">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="_change_date" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">go-previous-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_next_day">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="_change_date" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">go-next-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_last_day">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="_change_date" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">go-last-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>

View File

@ -71,6 +71,10 @@ class HistoryWindow:
self.window = xml.get_object('history_window')
self.window.set_application(app.app)
self.calendar = xml.get_object('calendar')
self.button_first_day = xml.get_object('button_first_day')
self.button_previous_day = xml.get_object('button_previous_day')
self.button_next_day = xml.get_object('button_next_day')
self.button_last_day = xml.get_object('button_last_day')
scrolledwindow = xml.get_object('scrolledwindow')
self.history_textview = conversation_textview.ConversationTextview(
account, used_in_history_window = True)
@ -311,17 +315,25 @@ class HistoryWindow:
self.jids_to_search = [info_jid]
# select logs for last date we have logs with contact
# Get first/last date we have logs with contact (for log navigation)
self.first_log = app.logger.get_first_date_that_has_logs(
self.account, self.jid)
self.first_day = self._get_date_from_timestamp(self.first_log)
self.last_log = app.logger.get_last_date_that_has_logs(
self.account, self.jid)
self.last_day = self._get_date_from_timestamp(self.last_log)
# Select logs for last date we have logs with contact
self.calendar.set_sensitive(True)
last_log = \
app.logger.get_last_date_that_has_logs(self.account, self.jid)
gtk_month = gtkgui_helpers.make_python_month_gtk_month(
self.last_day.month)
self.calendar.select_month(gtk_month, self.last_day.year)
self.calendar.select_day(self.last_day.day)
date = time.localtime(last_log)
y, m, d = date[0], date[1], date[2]
gtk_month = gtkgui_helpers.make_python_month_gtk_month(m)
self.calendar.select_month(gtk_month, y)
self.calendar.select_day(d)
self.button_previous_day.set_sensitive(True)
self.button_next_day.set_sensitive(True)
self.button_first_day.set_sensitive(True)
self.button_last_day.set_sensitive(True)
self.search_entry.set_sensitive(True)
self.search_entry.grab_focus()
@ -341,6 +353,10 @@ class HistoryWindow:
self.checkbutton.set_sensitive(False)
self.calendar.set_sensitive(False)
self.calendar.clear_marks()
self.button_previous_day.set_sensitive(False)
self.button_next_day.set_sensitive(False)
self.button_first_day.set_sensitive(False)
self.button_last_day.set_sensitive(False)
self.results_window.set_property('visible', False)
@ -379,6 +395,60 @@ class HistoryWindow:
for date in log_days:
widget.mark_day(date.day)
def _get_date_from_timestamp(self, timestamp):
# Conversion from timestamp to date
log = time.localtime(timestamp)
y, m, d = log[0], log[1], log[2]
date = datetime.datetime(y, m, d)
return(date)
def _change_date(self, widget):
# Get day selected in calendar
y, m, d = self.calendar.get_date()
py_m = gtkgui_helpers.make_gtk_month_python_month(m)
_date = datetime.datetime(y, py_m, d)
if widget is self.button_first_day:
gtk_m = gtkgui_helpers.make_python_month_gtk_month(
self.first_day.month)
self.calendar.select_month(gtk_m, self.first_day.year)
self.calendar.select_day(self.first_day.day)
return
elif widget is self.button_last_day:
gtk_m = gtkgui_helpers.make_python_month_gtk_month(
self.last_day.month)
self.calendar.select_month(gtk_m, self.last_day.year)
self.calendar.select_day(self.last_day.day)
return
elif widget is self.button_previous_day:
end_date = self.first_day
timedelta = datetime.timedelta(days=-1)
if end_date >= _date:
return
elif widget is self.button_next_day:
end_date = self.last_day
timedelta = datetime.timedelta(days=1)
if end_date <= _date:
return
# Iterate through days until log entry found or
# supplied end_date (first_log / last_log) reached
logs = None
while logs is None:
_date = _date + timedelta
if _date == end_date:
break
try:
logs = app.logger.get_date_has_logs(
self.account, self.jid, _date)
except exceptions.PysqliteOperationalError as e:
dialogs.ErrorDialog(_('Disk Error'), str(e))
return
gtk_month = gtkgui_helpers.make_python_month_gtk_month(_date.month)
self.calendar.select_month(gtk_month, _date.year)
self.calendar.select_day(_date.day)
def _get_string_show_from_constant_int(self, show):
if show == ShowConstant.ONLINE:
show = 'online'