additional time columns for EPG tab (#150)

This commit is contained in:
DYefremov
2023-01-25 17:54:09 +03:00
parent 25661816e7
commit f309005c52
5 changed files with 113 additions and 30 deletions

View File

@@ -54,8 +54,8 @@ except ModuleNotFoundError:
else: else:
DETECT_ENCODING = True DETECT_ENCODING = True
EpgEvent = namedtuple("EpgEvent", ["service_name", "title", "time", "desc", "event_data"]) EpgEvent = namedtuple("EpgEvent", ["service_name", "title", "start", "end", "length", "desc", "event_data"])
EpgEvent.__new__.__defaults__ = ("N/A", "N/A", "N/A", "N/A", None) # For Python3 < 3.7 EpgEvent.__new__.__defaults__ = ("N/A", "N/A", 0, 0, 0, "N/A", None) # For Python3 < 3.7
class Reader(metaclass=abc.ABCMeta): class Reader(metaclass=abc.ABCMeta):

View File

@@ -203,6 +203,7 @@ class EpgTool(Gtk.Box):
self._app = app self._app = app
self._app.connect("fav-changed", self.on_service_changed) self._app.connect("fav-changed", self.on_service_changed)
self._app.connect("bouquet-changed", self.on_bouquet_changed) self._app.connect("bouquet-changed", self.on_bouquet_changed)
self._app.connect("filter-toggled", self.on_filter_toggled)
handlers = {"on_epg_press": self.on_epg_press, handlers = {"on_epg_press": self.on_epg_press,
"on_timer_add": self.on_timer_add, "on_timer_add": self.on_timer_add,
@@ -217,12 +218,24 @@ class EpgTool(Gtk.Box):
self._model = builder.get_object("epg_model") self._model = builder.get_object("epg_model")
self._filter_model = builder.get_object("epg_filter_model") self._filter_model = builder.get_object("epg_filter_model")
self._filter_model.set_visible_func(self.epg_filter_function) self._filter_model.set_visible_func(self.epg_filter_function)
self._filter_button = builder.get_object("epg_filter_button")
self._filter_entry = builder.get_object("epg_filter_entry") self._filter_entry = builder.get_object("epg_filter_entry")
self._multi_epg_button = builder.get_object("multi_epg_button") self._multi_epg_button = builder.get_object("multi_epg_button")
self._event_count_label = builder.get_object("event_count_label") self._event_count_label = builder.get_object("event_count_label")
self.pack_start(builder.get_object("epg_frame"), True, True, 0) self.pack_start(builder.get_object("epg_frame"), True, True, 0)
# Custom sort function. # Custom data functions.
self._view.get_model().set_sort_func(2, self.time_sort_func, 2) renderer = builder.get_object("epg_start_renderer")
column = builder.get_object("epg_start_column")
column.set_cell_data_func(renderer, self.start_data_func)
renderer = builder.get_object("epg_end_renderer")
column = builder.get_object("epg_end_column")
column.set_cell_data_func(renderer, self.end_data_func)
renderer = builder.get_object("epg_length_renderer")
column = builder.get_object("epg_length_column")
column.set_cell_data_func(renderer, self.duration_data_func)
# Time formats.
self._time_fmt = "%a %x - %H:%M"
self._duration_fmt = f"%-Hh %Mm"
self.show() self.show()
@@ -290,18 +303,25 @@ class EpgTool(Gtk.Box):
@staticmethod @staticmethod
def get_event(event, show_day=True): def get_event(event, show_day=True):
t_str = f"{'%a, ' if show_day else ''}%x, %H:%M"
s_name = event.get("e2eventservicename", "") s_name = event.get("e2eventservicename", "")
title = event.get("e2eventtitle", "") or "" title = event.get("e2eventtitle", "") or ""
desc = event.get("e2eventdescription", "") or "" desc = event.get("e2eventdescription", "") or ""
desc = desc.strip() desc = desc.strip()
start, duration = int(event.get("e2eventstart", "0")), int(event.get("e2eventduration", "0"))
start = int(event.get("e2eventstart", "0")) return EpgEvent(s_name, title, start, start + duration, duration, desc, event)
start_time = datetime.fromtimestamp(start)
end_time = datetime.fromtimestamp(start + int(event.get("e2eventduration", "0")))
ev_time = f"{start_time.strftime(t_str)} - {end_time.strftime('%H:%M')}"
return EpgEvent(s_name, title, ev_time, desc, event) def start_data_func(self, column, renderer, model, itr, data):
value = datetime.fromtimestamp(model.get_value(itr, Column.EPG_START))
renderer.set_property("text", value.strftime(self._time_fmt))
def end_data_func(self, column, renderer, model, itr, data):
value = datetime.fromtimestamp(model.get_value(itr, Column.EPG_END))
renderer.set_property("text", value.strftime(self._time_fmt))
def duration_data_func(self, column, renderer, model, itr, data):
value = datetime.utcfromtimestamp(model.get_value(itr, Column.EPG_LENGTH))
renderer.set_property("text", value.strftime(self._duration_fmt))
def on_epg_filter_changed(self, entry): def on_epg_filter_changed(self, entry):
self._filter_model.refilter() self._filter_model.refilter()
@@ -312,14 +332,17 @@ class EpgTool(Gtk.Box):
def epg_filter_function(self, model, itr, data): def epg_filter_function(self, model, itr, data):
txt = self._filter_entry.get_text().upper() txt = self._filter_entry.get_text().upper()
return next((s for s in model.get(itr, 0, 1, 2, 3) if txt in s.upper()), False) return next((s for s in model.get(itr,
Column.EPG_SERVICE,
Column.EPG_TITLE,
Column.EPG_DESC) if txt in s.upper()), False)
def time_sort_func(self, model, iter1, iter2, column): def on_filter_toggled(self, app, value):
""" Custom sort function for time column. """ if self._app.page is Page.EPG:
event1 = model.get_value(iter1, 4) active = not self._filter_button.get_active()
event2 = model.get_value(iter2, 4) self._filter_button.set_active(active)
if active:
return int(event1.get("e2eventstart", "0")) - int(event2.get("e2eventstart", "0")) self._filter_entry.grab_focus()
def on_view_query_tooltip(self, view, x, y, keyboard_mode, tooltip): def on_view_query_tooltip(self, view, x, y, keyboard_mode, tooltip):
dst = view.get_dest_row_at_pos(x, y) dst = view.get_dest_row_at_pos(x, y)

View File

@@ -40,8 +40,12 @@ Author: Dmitriy Yefremov
<column type="gchararray"/> <column type="gchararray"/>
<!-- column-name title --> <!-- column-name title -->
<column type="gchararray"/> <column type="gchararray"/>
<!-- column-name time --> <!-- column-name start -->
<column type="gchararray"/> <column type="gint"/>
<!-- column-name end -->
<column type="gint"/>
<!-- column-name length -->
<column type="gint"/>
<!-- column-name description --> <!-- column-name description -->
<column type="gchararray"/> <column type="gchararray"/>
<!-- column-name data --> <!-- column-name data -->
@@ -277,7 +281,7 @@ Author: Dmitriy Yefremov
<property name="fixed-height-mode">True</property> <property name="fixed-height-mode">True</property>
<property name="rubber-banding">True</property> <property name="rubber-banding">True</property>
<property name="enable-grid-lines">both</property> <property name="enable-grid-lines">both</property>
<property name="tooltip-column">3</property> <property name="tooltip-column">6</property>
<signal name="button-press-event" handler="on_epg_press" swapped="no"/> <signal name="button-press-event" handler="on_epg_press" swapped="no"/>
<signal name="query-tooltip" handler="on_view_query_tooltip" swapped="no"/> <signal name="query-tooltip" handler="on_view_query_tooltip" swapped="no"/>
<child internal-child="selection"> <child internal-child="selection">
@@ -325,21 +329,61 @@ Author: Dmitriy Yefremov
</object> </object>
</child> </child>
<child> <child>
<object class="GtkTreeViewColumn" id="epg_time_column"> <object class="GtkTreeViewColumn" id="epg_start_column">
<property name="resizable">True</property> <property name="resizable">True</property>
<property name="sizing">fixed</property> <property name="sizing">fixed</property>
<property name="fixed-width">210</property> <property name="fixed-width">150</property>
<property name="min-width">50</property> <property name="min-width">50</property>
<property name="title" translatable="yes">Time</property> <property name="title" translatable="yes">Start time</property>
<property name="alignment">0.49000000953674316</property> <property name="alignment">0.49</property>
<property name="sort-column-id">2</property> <property name="sort-column-id">2</property>
<child> <child>
<object class="GtkCellRendererText" id="epg_time_renderer"> <object class="GtkCellRendererText" id="epg_start_renderer">
<property name="xpad">5</property>
<property name="xalign">0.49</property>
</object>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="epg_end_column">
<property name="resizable">True</property>
<property name="sizing">fixed</property>
<property name="fixed-width">150</property>
<property name="min-width">50</property>
<property name="title" translatable="yes">End time</property>
<property name="alignment">0.49</property>
<property name="sort-column-id">3</property>
<child>
<object class="GtkCellRendererText" id="epg_end_renderer">
<property name="xpad">5</property> <property name="xpad">5</property>
<property name="xalign">0.49000000953674316</property> <property name="xalign">0.49000000953674316</property>
</object> </object>
<attributes> <attributes>
<attribute name="text">2</attribute> <attribute name="text">3</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="epg_length_column">
<property name="resizable">True</property>
<property name="sizing">fixed</property>
<property name="fixed-width">100</property>
<property name="min-width">50</property>
<property name="title" translatable="yes">Length</property>
<property name="alignment">0.49</property>
<property name="sort-column-id">4</property>
<child>
<object class="GtkCellRendererText" id="epg_length_renderer">
<property name="xpad">5</property>
<property name="xalign">0.49000000953674316</property>
</object>
<attributes>
<attribute name="text">4</attribute>
</attributes> </attributes>
</child> </child>
</object> </object>
@@ -352,13 +396,13 @@ Author: Dmitriy Yefremov
<property name="title" translatable="yes">Description</property> <property name="title" translatable="yes">Description</property>
<property name="expand">True</property> <property name="expand">True</property>
<property name="alignment">0.49000000953674316</property> <property name="alignment">0.49000000953674316</property>
<property name="sort-column-id">3</property> <property name="sort-column-id">5</property>
<child> <child>
<object class="GtkCellRendererText" id="epg_desc_renderer"> <object class="GtkCellRendererText" id="epg_desc_renderer">
<property name="ellipsize">end</property> <property name="ellipsize">end</property>
</object> </object>
<attributes> <attributes>
<attribute name="text">3</attribute> <attribute name="text">5</attribute>
</attributes> </attributes>
</child> </child>
</object> </object>

View File

@@ -570,6 +570,8 @@ class Application(Gtk.Application):
self._epg_menu_button = builder.get_object("epg_menu_button") self._epg_menu_button = builder.get_object("epg_menu_button")
self._epg_menu_button.connect("realize", lambda b: b.set_popover(EpgSettingsPopover(self))) self._epg_menu_button.connect("realize", lambda b: b.set_popover(EpgSettingsPopover(self)))
self.bind_property("is_enigma", self._epg_menu_button, "sensitive") self.bind_property("is_enigma", self._epg_menu_button, "sensitive")
self._epg_start_time_fmt = "%a, %H:%M"
self._epg_end_time_fmt = "%H:%M"
# Hiding for Neutrino. # Hiding for Neutrino.
self.bind_property("is_enigma", builder.get_object("services_button_box"), "visible") self.bind_property("is_enigma", builder.get_object("services_button_box"), "visible")
# Setting the last size of the window if it was saved. # Setting the last size of the window if it was saved.
@@ -1147,10 +1149,16 @@ class Application(Gtk.Application):
event = self._epg_cache.get_current_event(srv_name) event = self._epg_cache.get_current_event(srv_name)
if event: if event:
if event.start:
start = datetime.fromtimestamp(event.start).strftime(self._epg_start_time_fmt)
end = datetime.fromtimestamp(event.end).strftime(self._epg_end_time_fmt)
sep = "-"
else:
start, end, sep = "", "", ""
# https://docs.gtk.org/Pango/pango_markup.html # https://docs.gtk.org/Pango/pango_markup.html
renderer.set_property("markup", (f'{escape(srv_name)}\n\n' renderer.set_property("markup", (f'{escape(srv_name)}\n\n'
f'<span size="small" weight="bold">{escape(event.title)}</span>\n' f'<span size="small" weight="bold">{escape(event.title)}</span>\n'
f'<span size="small" style="italic">{event.time}</span>')) f'<span size="small" style="italic">{start} {sep} {end}</span>'))
return False return False
return True return True

View File

@@ -269,6 +269,14 @@ class Column(IntEnum):
IPTV_FAV_ID = 5 IPTV_FAV_ID = 5
IPTV_PICON_ID = 6 IPTV_PICON_ID = 6
IPTV_TOOLTIP = 7 IPTV_TOOLTIP = 7
# EPG view
EPG_SERVICE = 0
EPG_TITLE = 1
EPG_START = 2
EPG_END = 3
EPG_LENGTH = 4
EPG_DESC = 5
EPG_DATA = 6
def __index__(self): def __index__(self):
""" Overridden to get the index in slices directly """ """ Overridden to get the index in slices directly """