InkyCal module updated with Black and Pylint changes
This commit is contained in:
		| @@ -4,11 +4,13 @@ | ||||
| Inkycal Calendar Module | ||||
| Copyright by aceisace | ||||
| """ | ||||
| from inkycal.modules.template import inkycal_module | ||||
| from inkycal.custom import * | ||||
|  | ||||
| # pylint: disable=logging-fstring-interpolation | ||||
|  | ||||
| import calendar as cal | ||||
| import arrow | ||||
| from inkycal.modules.template import inkycal_module | ||||
| from inkycal.custom import * | ||||
|  | ||||
| logger = logging.getLogger(__name__) | ||||
|  | ||||
| @@ -21,39 +23,32 @@ class Calendar(inkycal_module): | ||||
|     name = "Calendar - Show monthly calendar with events from iCalendars" | ||||
|  | ||||
|     optional = { | ||||
|  | ||||
|         "week_starts_on": { | ||||
|             "label": "When does your week start? (default=Monday)", | ||||
|             "options": ["Monday", "Sunday"], | ||||
|             "default": "Monday" | ||||
|             "default": "Monday", | ||||
|         }, | ||||
|  | ||||
|         "show_events": { | ||||
|             "label": "Show parsed events? (default = True)", | ||||
|             "options": [True, False], | ||||
|             "default": True | ||||
|             "default": True, | ||||
|         }, | ||||
|  | ||||
|         "ical_urls": { | ||||
|             "label": "iCalendar URL/s, separate multiple ones with a comma", | ||||
|         }, | ||||
|  | ||||
|         "ical_files": { | ||||
|             "label": "iCalendar filepaths, separated with a comma", | ||||
|         }, | ||||
|  | ||||
|         "date_format": { | ||||
|             "label": "Use an arrow-supported token for custom date formatting " + | ||||
|                      "see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. D MMM", | ||||
|             "label": "Use an arrow-supported token for custom date formatting " | ||||
|             + "see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. D MMM", | ||||
|             "default": "D MMM", | ||||
|         }, | ||||
|  | ||||
|         "time_format": { | ||||
|             "label": "Use an arrow-supported token for custom time formatting " + | ||||
|                      "see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. HH:mm", | ||||
|             "default": "HH:mm" | ||||
|             "label": "Use an arrow-supported token for custom time formatting " | ||||
|             + "see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. HH:mm", | ||||
|             "default": "HH:mm", | ||||
|         }, | ||||
|  | ||||
|     } | ||||
|  | ||||
|     def __init__(self, config): | ||||
| @@ -62,6 +57,11 @@ class Calendar(inkycal_module): | ||||
|         super().__init__(config) | ||||
|         config = config['config'] | ||||
|  | ||||
|         self.ical = None | ||||
|         self.month_events = None | ||||
|         self._upcoming_events = None | ||||
|         self._days_with_events = None | ||||
|  | ||||
|         # optional parameters | ||||
|         self.weekstart = config['week_starts_on'] | ||||
|         self.show_events = config['show_events'] | ||||
| @@ -82,11 +82,17 @@ class Calendar(inkycal_module): | ||||
|         # additional configuration | ||||
|         self.timezone = get_system_tz() | ||||
|         self.num_font = ImageFont.truetype( | ||||
|             fonts['NotoSans-SemiCondensed'], size=self.fontsize) | ||||
|             fonts['NotoSans-SemiCondensed'], size=self.fontsize | ||||
|         ) | ||||
|  | ||||
|         # give an OK message | ||||
|         print(f'{__name__} loaded') | ||||
|  | ||||
|     @staticmethod | ||||
|     def flatten(values): | ||||
|         """Flatten the values.""" | ||||
|         return [x for y in values for x in y] | ||||
|  | ||||
|     def generate_image(self): | ||||
|         """Generate image for this module""" | ||||
|  | ||||
| @@ -94,6 +100,7 @@ class Calendar(inkycal_module): | ||||
|         im_width = int(self.width - (2 * self.padding_left)) | ||||
|         im_height = int(self.height - (2 * self.padding_top)) | ||||
|         im_size = im_width, im_height | ||||
|         events_height = 0 | ||||
|  | ||||
|         logger.info(f'Image size: {im_size}') | ||||
|  | ||||
| @@ -110,7 +117,9 @@ class Calendar(inkycal_module): | ||||
|         if self.show_events: | ||||
|             logger.debug("Allocating space for events") | ||||
|             calendar_height = int(im_height * 0.6) | ||||
|             events_height = im_height - month_name_height - weekdays_height - calendar_height | ||||
|             events_height = ( | ||||
|                 im_height - month_name_height - weekdays_height - calendar_height | ||||
|             ) | ||||
|             logger.debug(f'calendar-section size: {im_width} x {calendar_height} px') | ||||
|             logger.debug(f'events-section size: {im_width} x {events_height} px') | ||||
|         else: | ||||
| @@ -132,14 +141,19 @@ class Calendar(inkycal_module): | ||||
|         logger.debug(f"y_spacing_calendar :{y_spacing_calendar}") | ||||
|  | ||||
|         # Calculate positions for days of month | ||||
|         grid_start_y = (month_name_height + weekdays_height + y_spacing_calendar) | ||||
|         grid_start_y = month_name_height + weekdays_height + y_spacing_calendar | ||||
|         grid_start_x = x_spacing_calendar | ||||
|  | ||||
|         grid_coordinates = [(grid_start_x + icon_width * x, grid_start_y + icon_height * y) | ||||
|                             for y in range(calendar_rows) for x in range(calendar_cols)] | ||||
|         grid_coordinates = [ | ||||
|             (grid_start_x + icon_width * x, grid_start_y + icon_height * y) | ||||
|             for y in range(calendar_rows) | ||||
|             for x in range(calendar_cols) | ||||
|         ] | ||||
|  | ||||
|         weekday_pos = [(grid_start_x + icon_width * _, month_name_height) for _ in | ||||
|                        range(calendar_cols)] | ||||
|         weekday_pos = [ | ||||
|             (grid_start_x + icon_width * _, month_name_height) | ||||
|             for _ in range(calendar_cols) | ||||
|         ] | ||||
|  | ||||
|         now = arrow.now(tz=self.timezone) | ||||
|  | ||||
| @@ -152,29 +166,35 @@ class Calendar(inkycal_module): | ||||
|             weekstart = now.shift(days=-now.isoweekday()) | ||||
|  | ||||
|         # Write the name of current month | ||||
|         write(im_black, (0, 0), (im_width, month_name_height), | ||||
|               str(now.format('MMMM', locale=self.language)), font=self.font, | ||||
|               autofit=True) | ||||
|  | ||||
|         # Set up weeknames in local language and add to main section | ||||
|         weekday_names = [weekstart.shift(days=+_).format('ddd', locale=self.language) | ||||
|                          for _ in range(7)] | ||||
|         logger.debug(f'weekday names: {weekday_names}') | ||||
|  | ||||
|         for _ in range(len(weekday_pos)): | ||||
|         write( | ||||
|             im_black, | ||||
|                 weekday_pos[_], | ||||
|                 (icon_width, weekdays_height), | ||||
|                 weekday_names[_], | ||||
|             (0, 0), | ||||
|             (im_width, month_name_height), | ||||
|             str(now.format('MMMM', locale=self.language)), | ||||
|             font=self.font, | ||||
|             autofit=True, | ||||
|                 fill_height=1.0 | ||||
|         ) | ||||
|  | ||||
|         # Set up weeknames in local language and add to main section | ||||
|         weekday_names = [ | ||||
|             weekstart.shift(days=+_).format('ddd', locale=self.language) | ||||
|             for _ in range(7) | ||||
|         ] | ||||
|         logger.debug(f'weekday names: {weekday_names}') | ||||
|  | ||||
|         for idx, weekday in enumerate(weekday_pos): | ||||
|             write( | ||||
|                 im_black, | ||||
|                 weekday, | ||||
|                 (icon_width, weekdays_height), | ||||
|                 weekday_names[idx], | ||||
|                 font=self.font, | ||||
|                 autofit=True, | ||||
|                 fill_height=1.0, | ||||
|             ) | ||||
|  | ||||
|         # Create a calendar template and flatten (remove nestings) | ||||
|         flatten = lambda z: [x for y in z for x in y] | ||||
|         calendar_flat = flatten(cal.monthcalendar(now.year, now.month)) | ||||
|         calendar_flat = self.flatten(cal.monthcalendar(now.year, now.month)) | ||||
|         # logger.debug(f" calendar_flat: {calendar_flat}") | ||||
|  | ||||
|         # Map days of month to co-ordinates of grid -> 3: (row2_x,col3_y) | ||||
| @@ -190,8 +210,15 @@ class Calendar(inkycal_module): | ||||
|         # Add the numbers on the correct positions | ||||
|         for number in calendar_flat: | ||||
|             if number != int(now.day): | ||||
|                 write(im_black, grid[number], (icon_width, icon_height), | ||||
|                       str(number), font=self.num_font, fill_height=0.5, fill_width=0.5) | ||||
|                 write( | ||||
|                     im_black, | ||||
|                     grid[number], | ||||
|                     (icon_width, icon_height), | ||||
|                     str(number), | ||||
|                     font=self.num_font, | ||||
|                     fill_height=0.5, | ||||
|                     fill_width=0.5, | ||||
|                 ) | ||||
|  | ||||
|         # Draw a red/black circle with the current day of month in white | ||||
|         icon = Image.new('RGBA', (icon_width, icon_height)) | ||||
| @@ -199,10 +226,24 @@ class Calendar(inkycal_module): | ||||
|         x_circle, y_circle = int(icon_width / 2), int(icon_height / 2) | ||||
|         radius = int(icon_width * 0.2) | ||||
|         ImageDraw.Draw(icon).ellipse( | ||||
|             (x_circle - radius, y_circle - radius, x_circle + radius, y_circle + radius), | ||||
|             fill='black', outline=None) | ||||
|         write(icon, (0, 0), (icon_width, icon_height), str(now.day), | ||||
|               font=self.num_font, fill_height=0.5, colour='white') | ||||
|             ( | ||||
|                 x_circle - radius, | ||||
|                 y_circle - radius, | ||||
|                 x_circle + radius, | ||||
|                 y_circle + radius, | ||||
|             ), | ||||
|             fill='black', | ||||
|             outline=None, | ||||
|         ) | ||||
|         write( | ||||
|             icon, | ||||
|             (0, 0), | ||||
|             (icon_width, icon_height), | ||||
|             str(now.day), | ||||
|             font=self.num_font, | ||||
|             fill_height=0.5, | ||||
|             colour='white', | ||||
|         ) | ||||
|         im_colour.paste(icon, current_day_pos, icon) | ||||
|  | ||||
|         # If events should be loaded and shown... | ||||
| @@ -217,17 +258,21 @@ class Calendar(inkycal_module): | ||||
|                 events_height += icon_height * 2 | ||||
|  | ||||
|             # import the ical-parser | ||||
|             # pylint: disable=import-outside-toplevel | ||||
|             from inkycal.modules.ical_parser import iCalendar | ||||
|  | ||||
|             # find out how many lines can fit at max in the event section | ||||
|             line_spacing = 0 | ||||
|             max_event_lines = events_height // (self.font.getsize('hg')[1] + | ||||
|                                                 line_spacing) | ||||
|             max_event_lines = events_height // ( | ||||
|                 self.font.getsize('hg')[1] + line_spacing | ||||
|             ) | ||||
|  | ||||
|             # generate list of coordinates for each line | ||||
|             events_offset = im_height - events_height | ||||
|             event_lines = [(0, events_offset + int(events_height / max_event_lines * _)) | ||||
|                            for _ in range(max_event_lines)] | ||||
|             event_lines = [ | ||||
|                 (0, events_offset + int(events_height / max_event_lines * _)) | ||||
|                 for _ in range(max_event_lines) | ||||
|             ] | ||||
|  | ||||
|             # logger.debug(f"event_lines {event_lines}") | ||||
|  | ||||
| @@ -250,8 +295,9 @@ class Calendar(inkycal_module): | ||||
|             self.month_events = month_events | ||||
|  | ||||
|             # find out on which days of this month events are taking place | ||||
|             days_with_events = [int(events['begin'].format('D')) for events in | ||||
|                                 month_events] | ||||
|             days_with_events = [ | ||||
|                 int(events['begin'].format('D')) for events in month_events | ||||
|             ] | ||||
|  | ||||
|             # remove duplicates (more than one event in a single day) | ||||
|             list(set(days_with_events)).sort() | ||||
| @@ -266,13 +312,12 @@ class Calendar(inkycal_module): | ||||
|                         (icon_width, icon_height), | ||||
|                         radius=6, | ||||
|                         thickness=1, | ||||
|                         shrinkage=(0.4, 0.2) | ||||
|                         shrinkage=(0.4, 0.2), | ||||
|                     ) | ||||
|  | ||||
|             # Filter upcoming events until 4 weeks in the future | ||||
|             parser.clear_events() | ||||
|             upcoming_events = parser.get_events(now, now.shift(weeks=4), | ||||
|                                                 self.timezone) | ||||
|             upcoming_events = parser.get_events(now, now.shift(weeks=4), self.timezone) | ||||
|             self._upcoming_events = upcoming_events | ||||
|  | ||||
|             # delete events which won't be able to fit (more events than lines) | ||||
| @@ -284,56 +329,97 @@ class Calendar(inkycal_module): | ||||
|                 # Find out how much space (width) the date format requires | ||||
|                 lang = self.language | ||||
|  | ||||
|                 date_width = int(max([self.font.getsize( | ||||
|                     events['begin'].format(self.date_format, locale=lang))[0] | ||||
|                                       for events in upcoming_events]) * 1.1) | ||||
|                 date_width = int( | ||||
|                     max( | ||||
|                         ( | ||||
|                             self.font.getsize( | ||||
|                                 events['begin'].format(self.date_format, locale=lang) | ||||
|                             )[0] | ||||
|                             for events in upcoming_events | ||||
|                         ) | ||||
|                     ) | ||||
|                     * 1.1 | ||||
|                 ) | ||||
|  | ||||
|                 time_width = int(max([self.font.getsize( | ||||
|                     events['begin'].format(self.time_format, locale=lang))[0] | ||||
|                                       for events in upcoming_events]) * 1.1) | ||||
|                 time_width = int( | ||||
|                     max( | ||||
|                         ( | ||||
|                             self.font.getsize( | ||||
|                                 events['begin'].format(self.time_format, locale=lang) | ||||
|                             )[0] | ||||
|                             for events in upcoming_events | ||||
|                         ) | ||||
|                     ) | ||||
|                     * 1.1 | ||||
|                 ) | ||||
|  | ||||
|                 line_height = self.font.getsize('hg')[1] + line_spacing | ||||
|  | ||||
|                 event_width_s = im_width - date_width - time_width | ||||
|                 event_width_l = im_width - date_width | ||||
|  | ||||
|                 # Display upcoming events below calendar | ||||
|                 tomorrow = now.shift(days=1).floor('day') | ||||
|                 in_two_days = now.shift(days=2).floor('day') | ||||
|                 # Display upcoming events below calendar TODO: not used? | ||||
|                 # tomorrow = now.shift(days=1).floor('day') | ||||
|                 # in_two_days = now.shift(days=2).floor('day') | ||||
|  | ||||
|                 cursor = 0 | ||||
|                 for event in upcoming_events: | ||||
|                     if cursor < len(event_lines): | ||||
|                         name = event['title'] | ||||
|                         date = event['begin'].format(self.date_format, locale=lang) | ||||
|                         time = event['begin'].format(self.time_format, locale=lang) | ||||
|                         # logger.debug(f"name:{name}   date:{date} time:{time}") | ||||
|                         the_name = event['title'] | ||||
|                         the_date = event['begin'].format(self.date_format, locale=lang) | ||||
|                         the_time = event['begin'].format(self.time_format, locale=lang) | ||||
|                         # logger.debug(f"name:{the_name}   date:{the_date} time:{the_time}") | ||||
|  | ||||
|                         if now < event['end']: | ||||
|                             write(im_colour, event_lines[cursor], (date_width, line_height), | ||||
|                                   date, font=self.font, alignment='left') | ||||
|                             write( | ||||
|                                 im_colour, | ||||
|                                 event_lines[cursor], | ||||
|                                 (date_width, line_height), | ||||
|                                 the_date, | ||||
|                                 font=self.font, | ||||
|                                 alignment='left', | ||||
|                             ) | ||||
|  | ||||
|                             # Check if event is all day | ||||
|                             if parser.all_day(event): | ||||
|                                 write(im_black, (date_width, event_lines[cursor][1]), | ||||
|                                       (event_width_l, line_height), name, font=self.font, | ||||
|                                       alignment='left') | ||||
|                                 write( | ||||
|                                     im_black, | ||||
|                                     (date_width, event_lines[cursor][1]), | ||||
|                                     (event_width_l, line_height), | ||||
|                                     the_name, | ||||
|                                     font=self.font, | ||||
|                                     alignment='left', | ||||
|                                 ) | ||||
|                             else: | ||||
|                                 write(im_black, (date_width, event_lines[cursor][1]), | ||||
|                                       (time_width, line_height), time, font=self.font, | ||||
|                                       alignment='left') | ||||
|                                 write( | ||||
|                                     im_black, | ||||
|                                     (date_width, event_lines[cursor][1]), | ||||
|                                     (time_width, line_height), | ||||
|                                     the_time, | ||||
|                                     font=self.font, | ||||
|                                     alignment='left', | ||||
|                                 ) | ||||
|  | ||||
|                                 write(im_black, (date_width + time_width, event_lines[cursor][1]), | ||||
|                                       (event_width_s, line_height), name, font=self.font, | ||||
|                                       alignment='left') | ||||
|                                 write( | ||||
|                                     im_black, | ||||
|                                     (date_width + time_width, event_lines[cursor][1]), | ||||
|                                     (event_width_s, line_height), | ||||
|                                     the_name, | ||||
|                                     font=self.font, | ||||
|                                     alignment='left', | ||||
|                                 ) | ||||
|                             cursor += 1 | ||||
|             else: | ||||
|                 symbol = '- ' | ||||
|                 while self.font.getsize(symbol)[0] < im_width * 0.9: | ||||
|                     symbol += ' -' | ||||
|                 write(im_black, event_lines[0], | ||||
|                       (im_width, self.font.getsize(symbol)[1]), symbol, | ||||
|                       font=self.font) | ||||
|                 write( | ||||
|                     im_black, | ||||
|                     event_lines[0], | ||||
|                     (im_width, self.font.getsize(symbol)[1]), | ||||
|                     symbol, | ||||
|                     font=self.font, | ||||
|                 ) | ||||
|  | ||||
|         # return the images ready for the display | ||||
|         return im_black, im_colour | ||||
|   | ||||
		Reference in New Issue
	
	Block a user