diff --git a/Calendar/CalendarEvent.py b/Calendar/CalendarEvent.py index d3a058b..0f97f2f 100644 --- a/Calendar/CalendarEvent.py +++ b/Calendar/CalendarEvent.py @@ -15,6 +15,7 @@ class CalendarEvent (object): self.highlight = None self.calendar_name = None + self.calendar_url = None self.location = None self.fetch_datetime = None diff --git a/Calendar/CalendarInterface.py b/Calendar/CalendarInterface.py index 740a5cc..4efbad3 100644 --- a/Calendar/CalendarInterface.py +++ b/Calendar/CalendarInterface.py @@ -10,6 +10,7 @@ class CalendarInterface (DataSourceInterface): def __init__(self): self.events = [] + self.excluded_urls = [] def reload(self): if self.is_available() == False: @@ -17,6 +18,9 @@ class CalendarInterface (DataSourceInterface): self.events = self.__get_events__() self.events = self.__sort_events__(self.events) + def exclude_calendars(self, urls=[]): + self.excluded_urls = urls + def __sort_events__(self, events): events.sort(key=lambda x: x.begin_datetime) return events @@ -72,6 +76,10 @@ class CalendarInterface (DataSourceInterface): events_in_range = [] for event in self.events: + # Is excluded? + if event.calendar_url in self.excluded_urls: + continue + event_occurrence = self.__get_if_event_in_range__( event, start, duration) if event_occurrence: diff --git a/Calendar/DayFocusListPanel.py b/Calendar/DayFocusListPanel.py new file mode 100644 index 0000000..751e0d9 --- /dev/null +++ b/Calendar/DayFocusListPanel.py @@ -0,0 +1,151 @@ +from datetime import date, datetime, timedelta, timezone +from settings import line_thickness, general_settings +from DayHeaderDesign import DayHeaderDesign +from HourListDesign import HourListDesign +from DayRowDesign import DayRowDesign +from PanelDesign import PanelDesign +from Assets import colors +from PIL import ImageDraw + +HEADER_SIZE = (1, 0.2) +HOURLIST_HEIGHT = 0.3 +HOURLIST_SIZE = (1, HOURLIST_HEIGHT) +DAYLIST_YPOS = HEADER_SIZE[1] + HOURLIST_SIZE[1] +DAYLIST_HEIGHT = 1 - HEADER_SIZE[1] - HOURLIST_SIZE[1] +DAYLIST_SIZE = (1, DAYLIST_HEIGHT) +HOURS_COUNT = 6 +DAYROW_MIN_FORMAT = 40 / 384 +DAYROW_MAX_FORMAT = 60 / 384 +PANEL_LINE_THICKNESS = line_thickness + + +class DayFocusListPanel (PanelDesign): + """Shows Day-View for today and a short Day-List for + the upcoming days.""" + + def __init__(self, size): + super(DayFocusListPanel, self).__init__(size) + self.hours_count = HOURS_COUNT + self.__init_modules__() + + def __abs_co__(self, coordinates): + return (int(coordinates[0] * self.size[0]), int(coordinates[1] * self.size[1])) + + def __init_modules__(self): + self.__init_header__() + self.__init_hourlist__() + self.__init_daylist__() + + def __init_header__(self): + self.__header__ = DayHeaderDesign( + self.__abs_co__(HEADER_SIZE), date.today()) + self.__header__.pos = (0, 0) + + def __init_hourlist__(self): + start, end = self.__get_current_hour_range__() + size = self.__abs_co__(HOURLIST_SIZE) + + self.__hourlist__ = HourListDesign(size, start, end) + self.__hourlist__.pos = (0, self.__header__.size[1]) + + def __init_daylist__(self): + self.__daylist_rows__ = [] + self.__calc_dayrow_size__() + self.__create_day_rows__() + + def __calc_dayrow_size__(self): + max_area_height = DAYLIST_HEIGHT * self.size[1] + max_row_number = max_area_height / (DAYROW_MIN_FORMAT * self.size[0]) + min_row_number = max_area_height / (DAYROW_MAX_FORMAT * self.size[0]) + average_row_number = (max_row_number + min_row_number) / 2 + self.dayrow_count = round(average_row_number) + row_height = max_area_height / self.dayrow_count + self.dayrow_size = (1, row_height / self.size[1]) + + def __create_day_rows__(self): + following_days = self.__get_following_days__() + for i, date in enumerate(following_days): + row = DayRowDesign(self.__abs_co__(self.dayrow_size), date) + row.pos = self.__get_day_row_pos__(i) + self.__daylist_rows__.append(row) + + def __get_following_days__(self): + following_days = [] + for i in range(self.dayrow_count): + following_days.append(date.today() + timedelta(days=i + 1)) + return following_days + + def __get_day_row_pos__(self, i): + ypos = self.size[1] * DAYLIST_YPOS + down_shift = i * self.dayrow_size[1] * self.size[1] + return (0, int(ypos + down_shift)) + + def __finish_panel__(self): + self.draw_design(self.__header__) + self.draw_design(self.__hourlist__) + + for row in self.__daylist_rows__: + self.draw_design(row) + self.__draw_daylist_lines__() + + def __draw_daylist_lines__(self): + positions = [] + for i in range(len(self.__daylist_rows__)): + positions.append(self.__get_day_row_pos__(i)[1]) + for ypos in positions: + line_start = (0, ypos) + line_end = (self.size[0], ypos) + ImageDraw.Draw(self.__image__).line( + [line_start, line_end], fill=colors["fg"], width=PANEL_LINE_THICKNESS) + + def __get_current_hour_range__(self): + start_hour = datetime.now().hour + additional_hours = self.hours_count - 1 + + if start_hour + additional_hours > 23: + start_hour = 23 - additional_hours + + return start_hour, start_hour + additional_hours + + def add_weather(self, weather): + self.__header__.add_weather(weather) + + def add_calendar(self, calendar): + allday_ev, timed_ev = self.__split_events__( + calendar.get_today_events()) + self.__header__.add_events(allday_ev) + self.__hourlist__.add_events(timed_ev) + + self.__add_calendar_daylist__(calendar) + + def __split_events__(self, events): + allday_ev = [] + timed_ev = [] + + for event in events: + if event.allday: + allday_ev.append(event) + elif event.multiday: + if self.__is_today__(event.begin_datetime): + timed_ev.append(event) + elif self.__is_today__(event.end_datetime): + timed_ev.append(event) + else: + allday_ev.append(event) + else: + timed_ev.append(event) + return allday_ev, timed_ev + + def __is_today__(self, dt): + today = date.today() + return dt.day == today.day and \ + dt.month == today.month and \ + dt.year == today.year + + def __add_calendar_daylist__(self, calendar): + calendar.exclude_calendars(general_settings["extra-excluded-urls"]) + + for row in self.__daylist_rows__: + row.add_calendar(calendar) + + calendar.exclude_calendars() diff --git a/Calendar/E-Paper.py b/Calendar/E-Paper.py index 6fd51af..1360310 100644 --- a/Calendar/E-Paper.py +++ b/Calendar/E-Paper.py @@ -17,6 +17,7 @@ from settings import datetime_encoding, language, render_to_display, render_to_f from MonthOvPanel import MonthOvPanel from DayListPanel import DayListPanel from DayViewPanel import DayViewPanel +from DayFocusListPanel import DayFocusListPanel from MonthViewPanel import MonthViewPanel from AgendaListPanel import AgendaListPanel from ImageFramePanel import ImageFramePanel @@ -54,12 +55,14 @@ available_panels = { "day-list": DayListPanel, "month-overview": MonthOvPanel, "day-view": DayViewPanel, + "day-focus-list": DayFocusListPanel, "agenda-list": AgendaListPanel, "month-view": MonthViewPanel, - "image-frame": ImageFramePanel + "image-frame": ImageFramePanel, } -loop_timer = LoopTimer(update_interval, run_on_hour=run_on_hour, max_loop_count=max_loop_count) +loop_timer = LoopTimer( + update_interval, run_on_hour=run_on_hour, max_loop_count=max_loop_count) """Main loop starts from here""" @@ -117,7 +120,8 @@ def main(): loop_timer.end_loop() if loop_timer.was_last_loop(): - debug.print_line("Maximum loop count " + str(loop_timer.loop_count) + " reached, exiting.") + debug.print_line("Maximum loop count " + + str(loop_timer.loop_count) + " reached, exiting.") return sleep_time = loop_timer.time_until_next() diff --git a/Calendar/IcalEvents.py b/Calendar/IcalEvents.py index ef5068e..7ec6d22 100644 --- a/Calendar/IcalEvents.py +++ b/Calendar/IcalEvents.py @@ -51,6 +51,7 @@ class IcalEvents(CalendarInterface): ical = Calendar(decode) for event in ical.events: cal_event = CalendarEvent() + cal_event.calendar_url = calendar cal_event.fetch_datetime = datetime.now(timezone.utc) cal_event.begin_datetime = event.begin.datetime diff --git a/Calendar/ImageFramePanel.py b/Calendar/ImageFramePanel.py index 37dd2c5..3cb4e4d 100644 --- a/Calendar/ImageFramePanel.py +++ b/Calendar/ImageFramePanel.py @@ -44,18 +44,3 @@ class ImageFramePanel (PanelDesign): overlay = ImageDesign(self.size, self.overlay_path) overlay.__finish_image__() self.__image__.alpha_composite(overlay.__image__) - - def add_weather(self, weather): - pass - - def add_calendar(self, calendar): - pass - - def add_rssfeed(self, rss): - pass - - def add_crypto(self, crypto): - pass - - def add_tasks(self, tasks): - pass diff --git a/Calendar/PanelDesign.py b/Calendar/PanelDesign.py index e1fc60b..a360ef8 100644 --- a/Calendar/PanelDesign.py +++ b/Calendar/PanelDesign.py @@ -12,19 +12,19 @@ class PanelDesign (DesignEntity): self.start_timestamp = datetime.now() def add_weather(self, weather): - raise NotImplementedError("Function needs to be implemented") + pass def add_calendar(self, calendar): - raise NotImplementedError("Function needs to be implemented") + pass def add_rssfeed(self, rss): - raise NotImplementedError("Function needs to be implemented") + pass def add_tasks(self, tasks): - raise NotImplementedError("Function needs to be implemented") + pass def add_crypto(self, crypto): - raise NotImplementedError("Function needs to be implemented") + pass def __finish_panel__(self): pass diff --git a/Calendar/settings.py.sample b/Calendar/settings.py.sample index 52f6c9f..a683a38 100644 --- a/Calendar/settings.py.sample +++ b/Calendar/settings.py.sample @@ -30,13 +30,14 @@ run_on_hour = True # If True, updates calendar every full hour, ignoring differ font_size = 14 # does not affect every text font_boldness = "semibold" # extralight, light, regular, semibold, bold, extrabold line_thickness = 1 # 1-3 Thickness advised -choosen_design = "month-overview" # month-overview, day-list, day-view, agenda-list, month-view, image-frame +choosen_design = "month-overview" # month-overview, day-list, day-view, day-focus-list, agenda-list, month-view, image-frame general_settings = { # General settings that designs may use "info-area" : "rss", # empty, events, rss, crypto "highlight-event-days" : True, - "weather-info" : True, + "weather-info" : True, "image-folder" : "", - "overlay-image" : "" # Size must be 384x640px with default display + "overlay-image" : "", # Size must be 384x640px with default display + "extra-excluded-urls" : [] } diff --git a/Gallery/day-focus-list_example.png b/Gallery/day-focus-list_example.png new file mode 100644 index 0000000..9d3686a Binary files /dev/null and b/Gallery/day-focus-list_example.png differ diff --git a/README.md b/README.md index f261eb1..7ced017 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,14 @@ This software fully supports the 3-Colour **and** 2-Colour version of the 7.5" E * **Added Support for the 2-Colour E-Paper Display as well!** (Late September 2018) * **Added Support for Raspbian Stretch lite.** (Late September 2018) - + 1.: Day-List Panel  2.: Month-Overview Panel  3.: Agenda-List Panel
4.: Day-View Panel  -5.: Image-Frame Panel +5.: Day-Focus-List Panel  +6.: Image-Frame Panel ## Main features * Display a calendar with one of multiple designes @@ -98,6 +99,7 @@ Once the packages are installed, navigate to the home directory, open 'E-Paper-M | `"weather-info"` | If set to `False`, weather info areas disappear and make room for events/rss/etc. (depends on the design). | | `"image-folder"` | Set a relative or absolute path to a folder containing images that you want to see fullscreen with the `"image-frame"` design activated. | | `"overlay-image"` | Set a relative or absolute path to an image with the same size as the screen (default: 384x640px) to show some static information over every image shown in the `"image-frame"` design. If the overlay image is contained within the `"image-folder"`, it will not be included into the slideshow. | +| `"extra-excluded-urls"` | A list of calendar urls that may be excluded in some panels in certain areas. | ### Debug | Parameter | Description |