Add navigation for chat history
This commit is contained in:
parent
5ce0c65ce4
commit
b0bf74337c
|
@ -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.
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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'
|
||||
|
|
Loading…
Reference in New Issue