Skip to content

Commit 16a269d

Browse files
committed
feat: add recording status filtering and improve card visual display
1 parent c9c828d commit 16a269d

File tree

6 files changed

+359
-43
lines changed

6 files changed

+359
-43
lines changed

app/ui/components/recording_card.py

Lines changed: 147 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,22 @@ def _create_card_components(self, recording: Recording):
8181
on_click=partial(self.recording_delete_button_click, recording=recording),
8282
)
8383

84-
if recording.monitor_status:
85-
display_title = recording.title
86-
else:
87-
display_title = f"[{self._['monitor_stopped']}] {recording.title}"
88-
display_title_label = ft.Text(display_title, size=14, selectable=True, max_lines=1, no_wrap=True)
84+
status_prefix = ""
85+
if not recording.monitor_status:
86+
status_prefix = f"[{self._['monitor_stopped']}] "
87+
88+
display_title = f"{status_prefix}{recording.title}"
89+
display_title_label = ft.Text(
90+
display_title,
91+
size=14,
92+
selectable=True,
93+
max_lines=1,
94+
no_wrap=True,
95+
overflow=ft.TextOverflow.ELLIPSIS,
96+
expand=True,
97+
weight=ft.FontWeight.BOLD if recording.recording or recording.is_live else None,
98+
)
99+
89100
open_folder_button = ft.IconButton(
90101
icon=ft.Icons.FOLDER,
91102
tooltip=self._["open_folder"],
@@ -98,10 +109,19 @@ def _create_card_components(self, recording: Recording):
98109
)
99110
speed_text_label = ft.Text(speed, size=12)
100111

112+
status_label = self.create_status_label(recording)
113+
114+
title_row = ft.Row(
115+
[display_title_label, status_label] if status_label else [display_title_label],
116+
alignment=ft.MainAxisAlignment.START,
117+
spacing=5,
118+
tight=True,
119+
)
120+
101121
card_container = ft.Container(
102122
content=ft.Column(
103123
[
104-
display_title_label,
124+
title_row,
105125
duration_text_label,
106126
speed_text_label,
107127
ft.Row(
@@ -114,17 +134,18 @@ def _create_card_components(self, recording: Recording):
114134
delete_button,
115135
monitor_button
116136
],
117-
spacing=5
137+
spacing=3,
138+
alignment=ft.MainAxisAlignment.START
118139
),
119140
],
120-
spacing=5,
141+
spacing=3,
121142
tight=True
122143
),
123-
padding=10,
144+
padding=8,
124145
on_click=partial(self.recording_card_on_click, recording=recording),
125-
bgcolor=None,
146+
bgcolor=self.get_card_background_color(recording),
126147
border_radius=5,
127-
148+
border=ft.border.all(2, self.get_card_border_color(recording)),
128149
)
129150
card = ft.Card(key=str(recording.rec_id), content=card_container)
130151

@@ -138,21 +159,126 @@ def _create_card_components(self, recording: Recording):
138159
"recording_info_button": recording_info_button,
139160
"edit_button": edit_button,
140161
"monitor_button": monitor_button,
162+
"status_label": status_label,
141163
}
164+
165+
def get_card_background_color(self, recording: Recording):
166+
is_dark_mode = self.app.page.theme_mode == ft.ThemeMode.DARK
167+
if recording.selected:
168+
return ft.colors.GREY_800 if is_dark_mode else ft.colors.GREY_400
169+
return None
170+
171+
@staticmethod
172+
def get_card_border_color(recording: Recording):
173+
"""Get the border color of the card."""
174+
if recording.recording:
175+
return ft.colors.GREEN
176+
elif recording.status_info == RecordingStatus.RECORDING_ERROR:
177+
return ft.colors.RED
178+
elif not recording.is_live and recording.monitor_status:
179+
return ft.colors.AMBER
180+
elif not recording.monitor_status:
181+
return ft.colors.GREY
182+
return ft.colors.TRANSPARENT
183+
184+
def create_status_label(self, recording: Recording):
185+
if recording.recording:
186+
return ft.Container(
187+
content=ft.Text(self._["recording"], color=ft.colors.WHITE, size=12, weight=ft.FontWeight.BOLD),
188+
bgcolor=ft.colors.GREEN,
189+
border_radius=5,
190+
padding=5,
191+
width=60,
192+
height=26,
193+
alignment=ft.alignment.center,
194+
)
195+
elif recording.status_info == RecordingStatus.RECORDING_ERROR:
196+
return ft.Container(
197+
content=ft.Text(self._["recording_error"], color=ft.colors.WHITE, size=12, weight=ft.FontWeight.BOLD),
198+
bgcolor=ft.colors.RED,
199+
border_radius=5,
200+
padding=5,
201+
width=60,
202+
height=26,
203+
alignment=ft.alignment.center,
204+
)
205+
elif not recording.is_live and recording.monitor_status:
206+
return ft.Container(
207+
content=ft.Text(self._["offline"], color=ft.colors.BLACK, size=12, weight=ft.FontWeight.BOLD),
208+
bgcolor=ft.colors.AMBER,
209+
border_radius=5,
210+
padding=5,
211+
width=60,
212+
height=26,
213+
alignment=ft.alignment.center,
214+
)
215+
elif not recording.monitor_status:
216+
return ft.Container(
217+
content=ft.Text(self._["no_monitor"], color=ft.colors.WHITE, size=12, weight=ft.FontWeight.BOLD),
218+
bgcolor=ft.colors.GREY,
219+
border_radius=5,
220+
padding=5,
221+
width=60,
222+
height=26,
223+
alignment=ft.alignment.center,
224+
)
225+
return None
142226

143227
async def update_card(self, recording):
144228
"""Update only the recordings cards in the scrollable content area."""
145229
if recording.rec_id in self.cards_obj:
146-
recording_card = self.cards_obj[recording.rec_id]
147-
recording_card["display_title_label"].value = recording.display_title
148-
recording_card["duration_label"].value = self.app.record_manager.get_duration(recording)
149-
recording_card["speed_label"].value = recording.speed
150-
recording_card["record_button"].icon = self.get_icon_for_recording_state(recording)
151-
recording_card["record_button"].tooltip = self.get_tip_for_recording_state(recording)
152-
recording_card["monitor_button"].icon = self.get_icon_for_monitor_state(recording)
153-
recording_card["monitor_button"].tooltip = self.get_tip_for_monitor_state(recording)
154-
recording_card["card"].content.bgcolor = await self.update_record_hover(recording)
155-
recording_card["card"].update()
230+
try:
231+
recording_card = self.cards_obj[recording.rec_id]
232+
233+
status_prefix = ""
234+
if not recording.monitor_status:
235+
status_prefix = f"[{self._['monitor_stopped']}] "
236+
237+
display_title = f"{status_prefix}{recording.title}"
238+
if recording_card.get("display_title_label"):
239+
recording_card["display_title_label"].value = display_title
240+
title_label_weight = ft.FontWeight.BOLD if recording.recording or recording.is_live else None
241+
recording_card["display_title_label"].weight = title_label_weight
242+
243+
new_status_label = self.create_status_label(recording)
244+
245+
if recording_card["card"] and recording_card["card"].content and recording_card["card"].content.content:
246+
title_row = recording_card["card"].content.content.controls[0]
247+
title_row.alignment = ft.MainAxisAlignment.START
248+
title_row.spacing = 5
249+
title_row.tight = True
250+
251+
title_row_controls = title_row.controls
252+
if len(title_row_controls) > 1:
253+
if new_status_label:
254+
title_row_controls[1] = new_status_label
255+
else:
256+
title_row_controls.pop(1)
257+
elif new_status_label:
258+
title_row_controls.append(new_status_label)
259+
260+
recording_card["status_label"] = new_status_label
261+
262+
if recording_card.get("duration_label"):
263+
recording_card["duration_label"].value = self.app.record_manager.get_duration(recording)
264+
265+
if recording_card.get("speed_label"):
266+
recording_card["speed_label"].value = recording.speed
267+
268+
if recording_card.get("record_button"):
269+
recording_card["record_button"].icon = self.get_icon_for_recording_state(recording)
270+
recording_card["record_button"].tooltip = self.get_tip_for_recording_state(recording)
271+
272+
if recording_card.get("monitor_button"):
273+
recording_card["monitor_button"].icon = self.get_icon_for_monitor_state(recording)
274+
recording_card["monitor_button"].tooltip = self.get_tip_for_monitor_state(recording)
275+
276+
if recording_card["card"] and recording_card["card"].content:
277+
recording_card["card"].content.bgcolor = self.get_card_background_color(recording)
278+
recording_card["card"].content.border = ft.border.all(2, self.get_card_border_color(recording))
279+
recording_card["card"].update()
280+
except Exception as e:
281+
print(f"Error updating card: {e}")
156282

157283
async def update_monitor_state(self, recording: Recording):
158284
"""Update the monitor button state based on the current monitoring status."""

app/ui/components/search_dialog.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,21 @@ def __init__(self, home_page, on_close=None):
77
self._ = {}
88
self.load()
99

10+
# Get the name of the current filter condition
11+
filter_name = self._["filter_all"]
12+
if self.home_page.current_filter == "recording":
13+
filter_name = self._["filter_recording"]
14+
elif self.home_page.current_filter == "error":
15+
filter_name = self._["filter_error"]
16+
elif self.home_page.current_filter == "offline":
17+
filter_name = self._["filter_offline"]
18+
elif self.home_page.current_filter == "stopped":
19+
filter_name = self._["filter_stopped"]
20+
21+
search_title = f"{self._['search']} ({filter_name})"
22+
1023
super().__init__(
11-
title=ft.Text(self._["search"], size=20, weight=ft.FontWeight.BOLD),
24+
title=ft.Text(search_title, size=20, weight=ft.FontWeight.BOLD),
1225
content_padding=ft.padding.only(left=20, top=15, right=20, bottom=20),
1326
)
1427
self.query = ft.TextField(
@@ -49,6 +62,14 @@ def load(self):
4962
language = self.home_page.app.language_manager.language
5063
for key in ("search_dialog", "home_page", "base"):
5164
self._.update(language.get(key, {}))
65+
66+
# Ensure the language items related to filtering exist
67+
if "filter_all" not in self._:
68+
self._["filter_all"] = self._["all"]
69+
self._["filter_recording"] = self._["recording"]
70+
self._["filter_offline"] = self._["not_live"]
71+
self._["filter_error"] = self._["recording_error"]
72+
self._["filter_stopped"] = self._["stopped"]
5273

5374
async def close_dlg(self, _e):
5475
self.open = False

0 commit comments

Comments
 (0)