-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontentswitcher_list_views.py
145 lines (107 loc) · 3.74 KB
/
contentswitcher_list_views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
"""Fake RSS reader app using a ContentSwitcher."""
from faker import Faker
from textual import on
from textual.app import App, ComposeResult
from textual.containers import Horizontal, Vertical
from textual.message import Message
from textual.widgets import (
ContentSwitcher,
Footer,
Header,
Label,
ListItem,
ListView,
Markdown,
Placeholder,
)
def get_feed_list() -> list[str]:
Faker.seed(1)
fake = Faker()
return [f"{fake.word()} Feed" for _ in range(4)]
def get_article_list(feed: str) -> list[str]:
fake = Faker()
fake.seed_instance(feed)
return [fake.sentence() for _ in range(7)]
def get_article(feed: str, article: str) -> str:
fake = Faker()
fake.seed_instance(feed + article)
return "\n\n".join(fake.paragraphs(5))
class ArticleView(Markdown):
BINDINGS = [("escape", "go_back", "Return to article list")]
can_focus = True
class GoBack(Message): ...
def action_go_back(self) -> None:
self.post_message(self.GoBack())
class ArticleItem(ListItem):
def __init__(self, article: str, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.article = article
def compose(self) -> ComposeResult:
yield Label(self.article)
class ArticleList(ListView):
BINDINGS = [("escape", "go_back", "Return to feed list")]
class GoBack(Message): ...
feed: str
def update_articles(self, feed: str, articles: list[str]) -> None:
self.clear()
self.feed = feed
for article in articles:
self.append(ArticleItem(article))
def action_go_back(self) -> None:
self.post_message(self.GoBack())
class FeedItem(ListItem):
def __init__(self, feed: str, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.feed = feed
def compose(self) -> ComposeResult:
yield Label(self.feed)
class FeedList(ListView):
def update_feeds(self, feeds: list[str]) -> None:
self.clear()
for feed in feeds:
self.append(FeedItem(feed))
class FeedReaderApp(App[None]):
CSS = """
Vertical > Placeholder {
height: 10%;
}
Horizontal > Placeholder {
width: 10%;
}
ListItem > Label {
padding: 1 2;
}
"""
def compose(self) -> ComposeResult:
yield Header()
yield Footer()
with Vertical():
yield Placeholder()
with Horizontal():
yield Placeholder()
with ContentSwitcher(initial="feed_list"):
yield FeedList(id="feed_list")
yield ArticleList(id="article_list")
yield ArticleView(id="article_view")
yield Placeholder()
yield Placeholder()
def on_mount(self) -> None:
self.query_one(FeedList).update_feeds(get_feed_list())
@on(ListView.Selected, "#feed_list")
def select_feed(self, event: ListView.Selected) -> None:
feed = event.item.feed
self.query_one(ArticleList).update_articles(feed, get_article_list(feed))
self.query_one(ContentSwitcher).current = "article_list"
@on(ListView.Selected, "#article_list")
def select_article(self, event: ListView.Selected) -> None:
self.query_one("#article_view", Markdown).update(
get_article(event.list_view.feed, event.item.article)
)
self.query_one(ContentSwitcher).current = "article_view"
@on(ArticleList.GoBack)
def return_to_feed_list(self) -> None:
self.query_one(ContentSwitcher).current = "feed_list"
@on(ArticleView.GoBack)
def return_to_article_list(self) -> None:
self.query_one(ContentSwitcher).current = "article_list"
FeedReaderApp().run()