mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 21:03:01 +00:00
Of the day format and font updates, new rotational strucutre
This commit is contained in:
@@ -332,7 +332,9 @@
|
|||||||
},
|
},
|
||||||
"of_the_day": {
|
"of_the_day": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
"display_rotate_interval": 30,
|
||||||
"update_interval": 3600,
|
"update_interval": 3600,
|
||||||
|
"subtitle_rotate_interval": 10,
|
||||||
"category_order": ["word_of_the_day", "slovenian_word_of_the_day"],
|
"category_order": ["word_of_the_day", "slovenian_word_of_the_day"],
|
||||||
"categories": {
|
"categories": {
|
||||||
"word_of_the_day": {
|
"word_of_the_day": {
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ Add the following configuration to your `config/config.json`:
|
|||||||
"of_the_day": {
|
"of_the_day": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"update_interval": 3600,
|
"update_interval": 3600,
|
||||||
|
"subtitle_rotate_interval": 10, // Seconds to rotate subtitle/description
|
||||||
|
"display_rotate_interval": 30, // Seconds to rotate between categories
|
||||||
"category_order": ["word_of_the_day", "bible_verse", "spanish_word"],
|
"category_order": ["word_of_the_day", "bible_verse", "spanish_word"],
|
||||||
"categories": {
|
"categories": {
|
||||||
"word_of_the_day": {
|
"word_of_the_day": {
|
||||||
@@ -100,10 +102,10 @@ Each category uses a JSON file with the following structure:
|
|||||||
|
|
||||||
### Step 1: Create a Data File
|
### Step 1: Create a Data File
|
||||||
|
|
||||||
Create a new JSON file in the `data/` directory:
|
Create a new JSON file in the `of_the_day/` directory:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
touch data/my_custom_category.json
|
touch of_the_day/my_custom_category.json
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 2: Add Content
|
### Step 2: Add Content
|
||||||
@@ -148,13 +150,9 @@ Add your category to the config:
|
|||||||
|
|
||||||
### Example: Word of the Day Generator
|
### Example: Word of the Day Generator
|
||||||
|
|
||||||
You can use an LLM to generate a full year of content. Here's a Python script example:
|
You can use an LLM to generate a full year of content. Here's a script example:
|
||||||
|
|
||||||
```python
|
|
||||||
import json
|
|
||||||
import openai
|
|
||||||
|
|
||||||
def generate_word_of_the_day():
|
|
||||||
"""Generate a full year of word of the day entries using AI."""
|
"""Generate a full year of word of the day entries using AI."""
|
||||||
|
|
||||||
words = {}
|
words = {}
|
||||||
@@ -174,53 +172,7 @@ def generate_word_of_the_day():
|
|||||||
"description": "Full definition"
|
"description": "Full definition"
|
||||||
}}
|
}}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Use your preferred AI service
|
|
||||||
response = openai.ChatCompletion.create(
|
|
||||||
model="gpt-3.5-turbo",
|
|
||||||
messages=[{"role": "user", "content": prompt}]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Parse the response and add to words dict
|
|
||||||
# Implementation depends on your AI service
|
|
||||||
|
|
||||||
# Save to file
|
|
||||||
with open('data/ai_generated_words.json', 'w') as f:
|
|
||||||
json.dump(words, f, indent=4)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
generate_word_of_the_day()
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example: Bible Verse Generator
|
|
||||||
|
|
||||||
```python
|
|
||||||
def generate_bible_verses():
|
|
||||||
"""Generate a full year of inspirational bible verses."""
|
|
||||||
|
|
||||||
verses = {}
|
|
||||||
|
|
||||||
for day in range(1, 367):
|
|
||||||
prompt = f"""
|
|
||||||
Generate an inspirational bible verse for day {day} of the year.
|
|
||||||
Include:
|
|
||||||
1. Bible reference (e.g., "JOHN 3:16")
|
|
||||||
2. Brief theme (e.g., "God's love")
|
|
||||||
3. The verse text
|
|
||||||
|
|
||||||
Format as JSON:
|
|
||||||
{{
|
|
||||||
"title": "BIBLE REFERENCE",
|
|
||||||
"subtitle": "Brief theme",
|
|
||||||
"description": "Full verse text"
|
|
||||||
}}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Implementation with your AI service
|
|
||||||
|
|
||||||
with open('data/ai_generated_verses.json', 'w') as f:
|
|
||||||
json.dump(verses, f, indent=4)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Category Ideas
|
## Category Ideas
|
||||||
|
|
||||||
@@ -264,6 +216,64 @@ The display uses a layout similar to the calendar manager:
|
|||||||
- **Subtitle**: Smaller gray text below the title
|
- **Subtitle**: Smaller gray text below the title
|
||||||
- **Description**: Wrapped text if subtitle is empty
|
- **Description**: Wrapped text if subtitle is empty
|
||||||
|
|
||||||
|
## Rotation Logic (Subtitle/Description and Category)
|
||||||
|
|
||||||
|
There are two types of rotation in the Of The Day display system:
|
||||||
|
|
||||||
|
### 1. Subtitle/Description Rotation
|
||||||
|
- **What:** Within a single "Of The Day" category, the display always shows the Title at the top. Below the title, it alternates between showing the Subtitle and the Description.
|
||||||
|
- **How:** The Subtitle and Description rotate every `subtitle_rotate_interval` seconds (default: 10 seconds).
|
||||||
|
- **Example:**
|
||||||
|
- 10s: Title + Subtitle
|
||||||
|
- 10s: Title + Description
|
||||||
|
- 10s: Title + Subtitle
|
||||||
|
- ...
|
||||||
|
|
||||||
|
### 2. Category Rotation
|
||||||
|
- **What:** The display can show multiple "Of The Day" categories (e.g., Word of the Day, Slovenian Word of the Day). It rotates between these categories.
|
||||||
|
- **How:** The currently displayed category switches every `display_rotate_interval` seconds (default: 30 seconds).
|
||||||
|
- **Example:**
|
||||||
|
- 30s: Word of the Day (with subtitle/description alternating every 10s)
|
||||||
|
- 30s: Slovenian Word of the Day (with subtitle/description alternating every 10s)
|
||||||
|
- ...
|
||||||
|
|
||||||
|
### Configuration Example
|
||||||
|
Add these settings to your `of_the_day` section in `config/config.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"of_the_day": {
|
||||||
|
"enabled": true,
|
||||||
|
"update_interval": 3600,
|
||||||
|
"subtitle_rotate_interval": 10, // Seconds to rotate subtitle/description
|
||||||
|
"display_rotate_interval": 30, // Seconds to rotate between categories
|
||||||
|
"category_order": ["word_of_the_day", "slovenian_word_of_the_day"],
|
||||||
|
"categories": {
|
||||||
|
"word_of_the_day": {
|
||||||
|
"enabled": true,
|
||||||
|
"data_file": "word_of_the_day.json"
|
||||||
|
},
|
||||||
|
"slovenian_word_of_the_day": {
|
||||||
|
"enabled": true,
|
||||||
|
"data_file": "slovenian_word_of_the_day.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- **subtitle_rotate_interval**: How often (in seconds) to switch between subtitle and description for the current category.
|
||||||
|
- **display_rotate_interval**: How often (in seconds) to switch to the next category in `category_order`.
|
||||||
|
|
||||||
|
#### Example Display Flow
|
||||||
|
```
|
||||||
|
[0-10s] Word of the Day: Title + Subtitle
|
||||||
|
[10-20s] Word of the Day: Title + Description
|
||||||
|
[20-30s] Word of the Day: Title + Subtitle
|
||||||
|
[30-40s] Slovenian Word of the Day: Title + Subtitle
|
||||||
|
[40-50s] Slovenian Word of the Day: Title + Description
|
||||||
|
[50-60s] Slovenian Word of the Day: Title + Subtitle
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### Common Issues
|
### Common Issues
|
||||||
|
|||||||
@@ -21,13 +21,26 @@ class OfTheDayManager:
|
|||||||
self.of_the_day_config = config.get('of_the_day', {})
|
self.of_the_day_config = config.get('of_the_day', {})
|
||||||
self.enabled = self.of_the_day_config.get('enabled', False)
|
self.enabled = self.of_the_day_config.get('enabled', False)
|
||||||
self.update_interval = self.of_the_day_config.get('update_interval', 3600) # 1 hour default
|
self.update_interval = self.of_the_day_config.get('update_interval', 3600) # 1 hour default
|
||||||
|
self.subtitle_rotate_interval = self.of_the_day_config.get('subtitle_rotate_interval', 10) # 10 seconds default
|
||||||
|
self.display_rotate_interval = self.of_the_day_config.get('display_rotate_interval', 30) # 30 seconds default
|
||||||
self.last_update = 0
|
self.last_update = 0
|
||||||
self.last_display_log = 0
|
self.last_display_log = 0
|
||||||
self.current_day = None
|
self.current_day = None
|
||||||
self.current_items = {}
|
self.current_items = {}
|
||||||
self.current_item_index = 0
|
self.current_item_index = 0
|
||||||
self.current_category_index = 0
|
self.current_category_index = 0
|
||||||
|
self.last_drawn_category_index = -1
|
||||||
|
self.last_drawn_day = None
|
||||||
|
self.force_clear = False
|
||||||
|
self.rotation_state = 0 # 0 = subtitle, 1 = description
|
||||||
|
self.last_rotation_time = time.time()
|
||||||
|
self.last_category_rotation_time = time.time()
|
||||||
|
|
||||||
|
# Load fonts
|
||||||
|
font_dir = os.path.join(os.path.dirname(__file__), '..', 'assets', 'fonts')
|
||||||
|
self.title_font = ImageFont.load(os.path.join(font_dir, 'ic8x8u.bdf'))
|
||||||
|
self.body_font = ImageFont.load(os.path.join(font_dir, 'cozette.bdf'))
|
||||||
|
|
||||||
# Load categories and their data
|
# Load categories and their data
|
||||||
self.categories = self.of_the_day_config.get('categories', {})
|
self.categories = self.of_the_day_config.get('categories', {})
|
||||||
self.category_order = self.of_the_day_config.get('category_order', [])
|
self.category_order = self.of_the_day_config.get('category_order', [])
|
||||||
@@ -152,109 +165,60 @@ class OfTheDayManager:
|
|||||||
self.last_update = current_time
|
self.last_update = current_time
|
||||||
|
|
||||||
def draw_item(self, category_name, item):
|
def draw_item(self, category_name, item):
|
||||||
"""Draw a single 'of the day' item."""
|
|
||||||
try:
|
try:
|
||||||
title = item.get('title', 'No Title')
|
title = item.get('title', 'No Title')
|
||||||
subtitle = item.get('subtitle', '')
|
subtitle = item.get('subtitle', '')
|
||||||
description = item.get('description', '')
|
description = item.get('description', '')
|
||||||
font = self.display_manager.calendar_font
|
|
||||||
draw = ImageDraw.Draw(self.display_manager.image)
|
draw = ImageDraw.Draw(self.display_manager.image)
|
||||||
line_height = 8 # For 7px font
|
matrix_width = self.display_manager.matrix.width
|
||||||
|
matrix_height = self.display_manager.matrix.height
|
||||||
|
title_font = self.title_font
|
||||||
|
body_font = self.body_font
|
||||||
|
title_height = title_font.getsize('A')[1]
|
||||||
|
body_height = body_font.getsize('A')[1]
|
||||||
|
|
||||||
# --- Title and Subtitle Drawing (Top Aligned) ---
|
# --- Draw Title (always at top, ic8x8u.bdf) ---
|
||||||
|
self.display_manager.draw_text(title, 1, 0, color=self.title_color, font=title_font)
|
||||||
# 1. Draw Title
|
title_width = self.display_manager.get_text_width(title, title_font)
|
||||||
self.display_manager.draw_text(title, 1, 0, color=self.title_color, font=font)
|
underline_y = title_height # Just below the title font
|
||||||
|
|
||||||
# 2. Underline Title Only
|
|
||||||
title_width = self.display_manager.get_text_width(title, font)
|
|
||||||
underline_y = 7 # Just below the 7px high font
|
|
||||||
draw.line([(1, underline_y), (1 + title_width, underline_y)], fill=self.title_color, width=1)
|
draw.line([(1, underline_y), (1 + title_width, underline_y)], fill=self.title_color, width=1)
|
||||||
|
|
||||||
# 3. Draw Subtitle, starting on the same line as the title
|
# --- Draw Subtitle or Description (rotating, cozette.bdf) ---
|
||||||
if subtitle:
|
available_height = matrix_height - (title_height + 2)
|
||||||
current_x = 1 + title_width
|
y_start = title_height + 2
|
||||||
separator = " - "
|
available_width = matrix_width - 2
|
||||||
|
if self.rotation_state == 0 and subtitle:
|
||||||
# Draw separator if it fits
|
# Show subtitle
|
||||||
if current_x + self.display_manager.get_text_width(separator, font) < self.display_manager.matrix.width:
|
wrapped = self._wrap_text(subtitle, available_width, body_font, max_lines=3, line_height=body_height, max_height=available_height)
|
||||||
self.display_manager.draw_text(separator, current_x, 0, color=self.subtitle_color, font=font)
|
for i, line in enumerate(wrapped):
|
||||||
current_x += self.display_manager.get_text_width(separator, font)
|
self.display_manager.draw_text(line, 1, y_start + i * body_height, color=self.subtitle_color, font=body_font)
|
||||||
|
elif self.rotation_state == 1 and description:
|
||||||
# Wrap the rest of the subtitle
|
# Show description
|
||||||
available_width_line1 = self.display_manager.matrix.width - current_x
|
wrapped = self._wrap_text(description, available_width, body_font, max_lines=3, line_height=body_height, max_height=available_height)
|
||||||
words = subtitle.split(' ')
|
for i, line in enumerate(wrapped):
|
||||||
|
self.display_manager.draw_text(line, 1, y_start + i * body_height, color=self.subtitle_color, font=body_font)
|
||||||
line1_words = []
|
# else: nothing to show
|
||||||
while words:
|
|
||||||
word = words.pop(0)
|
|
||||||
test_line = ' '.join(line1_words + [word])
|
|
||||||
if self.display_manager.get_text_width(test_line, font) <= available_width_line1:
|
|
||||||
line1_words.append(word)
|
|
||||||
else:
|
|
||||||
words.insert(0, word) # Put word back
|
|
||||||
break
|
|
||||||
|
|
||||||
if line1_words:
|
|
||||||
self.display_manager.draw_text(' '.join(line1_words), current_x, 0, color=self.subtitle_color, font=font)
|
|
||||||
|
|
||||||
# Draw remaining words on the next line
|
|
||||||
if words:
|
|
||||||
remaining_text = ' '.join(words)
|
|
||||||
wrapped_line2 = self._wrap_text(remaining_text, self.display_manager.matrix.width - 2, font, max_lines=1)
|
|
||||||
if wrapped_line2 and wrapped_line2[0]:
|
|
||||||
self.display_manager.draw_text(wrapped_line2[0], 1, line_height, color=self.subtitle_color, font=font)
|
|
||||||
else:
|
|
||||||
# If even the separator doesn't fit, wrap the whole subtitle on the next line
|
|
||||||
wrapped_subtitle = self._wrap_text(subtitle, self.display_manager.matrix.width - 2, font, max_lines=2)
|
|
||||||
for i, line in enumerate(wrapped_subtitle):
|
|
||||||
if line.strip():
|
|
||||||
self.display_manager.draw_text(line, 1, (i + 1) * line_height, color=self.subtitle_color, font=font)
|
|
||||||
|
|
||||||
# --- Description Drawing (Bottom Aligned) ---
|
|
||||||
if description:
|
|
||||||
available_width = self.display_manager.matrix.width - 2
|
|
||||||
wrapped_lines = self._wrap_text(description, available_width, font, max_lines=3)
|
|
||||||
|
|
||||||
num_lines = len([line for line in wrapped_lines if line.strip()])
|
|
||||||
total_description_height = num_lines * line_height
|
|
||||||
start_y = self.display_manager.matrix.height - total_description_height
|
|
||||||
|
|
||||||
for i, line in enumerate(wrapped_lines):
|
|
||||||
if line.strip():
|
|
||||||
self.display_manager.draw_text(line, 1, start_y + (i * line_height),
|
|
||||||
color=self.subtitle_color,
|
|
||||||
font=font)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error drawing 'of the day' item: {e}", exc_info=True)
|
logger.error(f"Error drawing 'of the day' item: {e}", exc_info=True)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _wrap_text(self, text, max_width, font, max_lines=2):
|
def _wrap_text(self, text, max_width, font, max_lines=3, line_height=8, max_height=24):
|
||||||
"""Wrap text to fit within max_width using the provided font."""
|
|
||||||
if not text:
|
if not text:
|
||||||
return [""]
|
return [""]
|
||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
current_line = []
|
current_line = []
|
||||||
words = text.split()
|
words = text.split()
|
||||||
|
|
||||||
for word in words:
|
for word in words:
|
||||||
# Try adding the word to the current line
|
|
||||||
test_line = ' '.join(current_line + [word]) if current_line else word
|
test_line = ' '.join(current_line + [word]) if current_line else word
|
||||||
text_width = self.display_manager.get_text_width(test_line, font)
|
text_width = self.display_manager.get_text_width(test_line, font)
|
||||||
|
|
||||||
if text_width <= max_width:
|
if text_width <= max_width:
|
||||||
# Word fits, add it to current line
|
|
||||||
current_line.append(word)
|
current_line.append(word)
|
||||||
else:
|
else:
|
||||||
# Word doesn't fit, start a new line
|
|
||||||
if current_line:
|
if current_line:
|
||||||
lines.append(' '.join(current_line))
|
lines.append(' '.join(current_line))
|
||||||
current_line = [word]
|
current_line = [word]
|
||||||
else:
|
else:
|
||||||
# Single word too long, truncate it
|
|
||||||
truncated = word
|
truncated = word
|
||||||
while len(truncated) > 0:
|
while len(truncated) > 0:
|
||||||
if self.display_manager.get_text_width(truncated + "...", font) <= max_width:
|
if self.display_manager.get_text_width(truncated + "...", font) <= max_width:
|
||||||
@@ -263,76 +227,60 @@ class OfTheDayManager:
|
|||||||
truncated = truncated[:-1]
|
truncated = truncated[:-1]
|
||||||
if not truncated:
|
if not truncated:
|
||||||
lines.append(word[:10] + "...")
|
lines.append(word[:10] + "...")
|
||||||
|
if len(lines) * line_height >= max_height or len(lines) >= max_lines:
|
||||||
# Check if we've filled all lines
|
|
||||||
if len(lines) >= max_lines:
|
|
||||||
break
|
break
|
||||||
|
if current_line and (len(lines) * line_height < max_height and len(lines) < max_lines):
|
||||||
# Handle any remaining text in current_line
|
lines.append(' '.join(current_line))
|
||||||
if current_line and len(lines) < max_lines:
|
|
||||||
remaining_text = ' '.join(current_line)
|
|
||||||
if len(words) > len(current_line): # More words remain
|
|
||||||
# Try to fit with ellipsis
|
|
||||||
while len(remaining_text) > 0:
|
|
||||||
if self.display_manager.get_text_width(remaining_text + "...", font) <= max_width:
|
|
||||||
lines.append(remaining_text + "...")
|
|
||||||
break
|
|
||||||
remaining_text = remaining_text[:-1]
|
|
||||||
else:
|
|
||||||
lines.append(remaining_text)
|
|
||||||
|
|
||||||
# Ensure we have exactly max_lines
|
|
||||||
while len(lines) < max_lines:
|
while len(lines) < max_lines:
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
return lines[:max_lines]
|
return lines[:max_lines]
|
||||||
|
|
||||||
def display(self, force_clear=False):
|
def display(self, force_clear=False):
|
||||||
"""Display 'of the day' items on the LED matrix, only updating when content changes."""
|
|
||||||
if not self.enabled:
|
if not self.enabled:
|
||||||
return # Manager is disabled
|
return
|
||||||
if not self.current_items:
|
if not self.current_items:
|
||||||
# Throttle warning to once every 10 seconds
|
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
if not hasattr(self, 'last_warning_time') or current_time - self.last_warning_time > 10:
|
if not hasattr(self, 'last_warning_time') or current_time - self.last_warning_time > 10:
|
||||||
logger.warning(f"OfTheDayManager has no current items.")
|
logger.warning(f"OfTheDayManager has no current items.")
|
||||||
self.last_warning_time = current_time
|
self.last_warning_time = current_time
|
||||||
return
|
return
|
||||||
|
now = time.time()
|
||||||
# Check if a redraw is necessary
|
# Handle subtitle/description rotation
|
||||||
|
if now - self.last_rotation_time > self.subtitle_rotate_interval:
|
||||||
|
self.rotation_state = (self.rotation_state + 1) % 2
|
||||||
|
self.last_rotation_time = now
|
||||||
|
# Force redraw
|
||||||
|
self.last_drawn_category_index = -1
|
||||||
|
self.last_drawn_day = None
|
||||||
|
# Handle OTD category rotation
|
||||||
|
if now - self.last_category_rotation_time > self.display_rotate_interval:
|
||||||
|
self.current_category_index = (self.current_category_index + 1) % len(self.current_items)
|
||||||
|
self.last_category_rotation_time = now
|
||||||
|
# Reset subtitle/description rotation when switching category
|
||||||
|
self.rotation_state = 0
|
||||||
|
self.last_rotation_time = now
|
||||||
|
# Force redraw
|
||||||
|
self.last_drawn_category_index = -1
|
||||||
|
self.last_drawn_day = None
|
||||||
content_has_changed = self.current_category_index != self.last_drawn_category_index or self.current_day != self.last_drawn_day
|
content_has_changed = self.current_category_index != self.last_drawn_category_index or self.current_day != self.last_drawn_day
|
||||||
if not content_has_changed and not force_clear:
|
if not content_has_changed and not force_clear:
|
||||||
return # Nothing to update, so we exit early
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Get current category and item
|
|
||||||
category_names = list(self.current_items.keys())
|
category_names = list(self.current_items.keys())
|
||||||
if not category_names or self.current_category_index >= len(category_names):
|
if not category_names or self.current_category_index >= len(category_names):
|
||||||
self.current_category_index = 0
|
self.current_category_index = 0
|
||||||
if not category_names: return
|
if not category_names: return
|
||||||
|
|
||||||
current_category = category_names[self.current_category_index]
|
current_category = category_names[self.current_category_index]
|
||||||
current_item = self.current_items[current_category]
|
current_item = self.current_items[current_category]
|
||||||
|
|
||||||
# Log the new item being displayed (throttled)
|
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
if current_time - self.last_display_log > 5:
|
if current_time - self.last_display_log > 5:
|
||||||
logger.info(f"Displaying {current_category}: {current_item.get('title', 'No Title')}")
|
logger.info(f"Displaying {current_category}: {current_item.get('title', 'No Title')}")
|
||||||
self.last_display_log = current_time
|
self.last_display_log = current_time
|
||||||
|
|
||||||
# A redraw is needed, so first clear the canvas
|
|
||||||
self.display_manager.clear()
|
self.display_manager.clear()
|
||||||
|
|
||||||
# Draw the item
|
|
||||||
self.draw_item(current_category, current_item)
|
self.draw_item(current_category, current_item)
|
||||||
|
|
||||||
# Update the physical display
|
|
||||||
self.display_manager.update_display()
|
self.display_manager.update_display()
|
||||||
|
|
||||||
# Cache the state of what was just drawn
|
|
||||||
self.last_drawn_category_index = self.current_category_index
|
self.last_drawn_category_index = self.current_category_index
|
||||||
self.last_drawn_day = self.current_day
|
self.last_drawn_day = self.current_day
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error displaying 'of the day' item: {e}", exc_info=True)
|
logger.error(f"Error displaying 'of the day' item: {e}", exc_info=True)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user