12
12
from textual .widgets import Header , Footer , ListItem , ListView , Rule , Select , Tree , Markdown , Static , Button , \
13
13
Label , Input , Pretty , Switch
14
14
from textual .reactive import reactive
15
+ from rich .emoji import Emoji
15
16
16
17
17
18
CONFIG_DIR = Path .joinpath (Path .home (), ".config/lugus" )
@@ -77,6 +78,20 @@ def update(self, table, id_record, values):
77
78
)
78
79
self .connection .commit ()
79
80
81
+ def update_where (self , table , where , values ):
82
+ cursor = self .connection .cursor ()
83
+ cursor .execute (
84
+ "UPDATE %s SET %s WHERE %s" % (
85
+ table ,
86
+ ", " .join ([
87
+ f"{ v [0 ]} = { self ._convert_value (v [1 ])} "
88
+ for v in values
89
+ ]),
90
+ where ,
91
+ )
92
+ )
93
+ self .connection .commit ()
94
+
80
95
def read (self , table , id_record ):
81
96
if isinstance (id_record , str ):
82
97
id_record = int (id_record .lower ().replace ("id-" , "" ))
@@ -245,15 +260,20 @@ def compose(self) -> ComposeResult:
245
260
},
246
261
)
247
262
yield tree
248
- yield Button (
249
- "Sync" ,
250
- variant = "primary" ,
251
- id = "sync" ,
252
- )
253
- yield Button (
254
- "Add New Feed" ,
255
- variant = "primary" ,
256
- id = "add_new" ,
263
+ yield Horizontal (
264
+ Button (
265
+ Emoji .replace (":counterclockwise_arrows_button:" ),
266
+ variant = "primary" ,
267
+ id = "sync" ,
268
+ tooltip = "Get new articles from feeds" ,
269
+ ),
270
+ Button (
271
+ Emoji .replace (":heavy_plus_sign:" ),
272
+ variant = "primary" ,
273
+ id = "add_new" ,
274
+ tooltip = "Add a new feed" ,
275
+ ),
276
+ id = "feed_buttons" ,
257
277
)
258
278
259
279
@@ -263,18 +283,41 @@ class Articles(Vertical):
263
283
recomposes = reactive (0 , recompose = True )
264
284
feed = reactive (False , recompose = True )
265
285
filter_articles_type = reactive ("" , recompose = True )
286
+ filter_articles = reactive ("" , recompose = True )
266
287
267
288
def compose (self ) -> ComposeResult :
268
289
articles = []
269
290
if self .feed and self .feed .data :
270
291
data = self .feed .data
292
+ # Filter by Read/Unread
271
293
if self .filter_articles_type == "unread" :
272
294
read = " AND read = 0"
273
295
elif self .filter_articles_type == "read" :
274
296
read = " AND read = 1"
275
297
else :
276
298
read = ""
277
- articles = self .orm .search ("article" , ["id" , "date" , "title" ], where = f"feed_id = { data ["id" ]} { read } " )
299
+ # Filter by Title/Content
300
+ if self .filter_articles :
301
+ filters = self .filter_articles .split ("," )
302
+ filter_text = ""
303
+ for filter in filters :
304
+ filter = filter .strip ().replace ("\" " , "" )
305
+ if filter :
306
+ if filter .lower ().startswith ("title:" ):
307
+ filter = filter .replace ("title:" , "" )
308
+ filter_text = f"{ filter_text } AND title LIKE \" %{ filter } %\" "
309
+ elif filter .lower ().startswith ("content:" ):
310
+ filter = filter .replace ("content:" , "" )
311
+ filter_text = f"{ filter_text } AND content LIKE \" %{ filter } %\" "
312
+ else :
313
+ filter_text = f"{ filter_text } AND (title LIKE \" %{ filter } %\" OR content LIKE \" %{ filter } %\" )"
314
+ else :
315
+ filter_text = ""
316
+ articles = self .orm .search (
317
+ "article" ,
318
+ ["id" , "date" , "title" ],
319
+ where = f"feed_id = { data ["id" ]} { read } { filter_text } " ,
320
+ )
278
321
yield ListView (
279
322
* [
280
323
ListItem (
@@ -292,15 +335,24 @@ def compose(self) -> ComposeResult:
292
335
293
336
class ArticlesArea (Vertical ):
294
337
338
+ orm = ORM ()
339
+
295
340
def compose (self ) -> ComposeResult :
296
- yield Select (
297
- (
298
- ("Unread" , "unread" ),
299
- ("Read" , "read" ),
300
- ("All" , "all" ),
341
+ yield Horizontal (
342
+ Select (
343
+ (
344
+ ("Unread" , "unread" ),
345
+ ("Read" , "read" ),
346
+ ("All" , "all" ),
347
+ ),
348
+ value = "unread" ,
349
+ id = "filter_articles_type" ,
350
+ ),
351
+ Input (
352
+ placeholder = "Search " + Emoji .replace (":magnifying_glass_tilted_left:" ),
353
+ id = "search_articles" ,
301
354
),
302
- value = "unread" ,
303
- id = "filter_articles_type" ,
355
+ classes = "w100 hauto mb1" ,
304
356
)
305
357
yield Articles (
306
358
id = "articles"
@@ -311,6 +363,11 @@ def select_changed(self, event: Select.Changed) -> None:
311
363
if event .select .id == "filter_articles_type" :
312
364
self .query_one ("#articles" ).filter_articles_type = event .value
313
365
366
+ @on (Input .Changed )
367
+ def filter_articles (self , event : Input .Changed ) -> None :
368
+ if event .input .id == "search_articles" :
369
+ self .query_one ("#articles" ).filter_articles = event .value
370
+
314
371
315
372
class Reader (Vertical ):
316
373
@@ -351,6 +408,7 @@ class LugusApp(App):
351
408
("c" , "open_configuration" , "Configs" ),
352
409
("question_mark" , "article_data" , "Article Raw Data" ),
353
410
("r" , "article_read" , "Set Article as Read" ),
411
+ ("a" , "all_articles_read" , "Set all Feed Articles as Read" ),
354
412
("o" , "read_online" , "Read Online" ),
355
413
]
356
414
@@ -423,7 +481,7 @@ def _synchronize_feeds(self, update_interface_element=None):
423
481
)
424
482
if update_interface_element :
425
483
update_interface_element .disabled = False
426
- update_interface_element .label = "Sync"
484
+ update_interface_element .label = Emoji . replace ( ":counterclockwise_arrows_button:" )
427
485
self .notify ("Feeds synchronized!" )
428
486
return
429
487
@@ -486,6 +544,19 @@ def action_article_read(self) -> None:
486
544
def action_open_configuration (self ) -> None :
487
545
self .status = "configuration"
488
546
547
+ def action_all_articles_read (self ) -> None :
548
+ feed = self .query_one ("#articles" ).feed
549
+ if not feed :
550
+ self .notify ("Select a feed" , severity = "warning" )
551
+ else :
552
+ self .orm .update_where (
553
+ "article" ,
554
+ f"feed_id = { feed .data ["id" ]} AND read = 0" ,
555
+ [("read" , 1 )],
556
+ )
557
+ self .query_one ("#sidebar" ).recomposes += 1
558
+ self .query_one ("#articles" ).recomposes += 1
559
+
489
560
def action_read_online (self ) -> None :
490
561
reader = self .query_one ("#reader" )
491
562
if not reader .id_article :
0 commit comments