oldnews 0.6.0__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {oldnews-0.6.0 → oldnews-0.7.0}/PKG-INFO +2 -2
- {oldnews-0.6.0 → oldnews-0.7.0}/pyproject.toml +2 -2
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/widgets/_after_highlight.py +1 -1
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/widgets/navigation.py +91 -38
- {oldnews-0.6.0 → oldnews-0.7.0}/README.md +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/__init__.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/__main__.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/commands/__init__.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/commands/main.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/data/__init__.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/data/auth.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/data/config.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/data/db.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/data/dump.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/data/last_grab.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/data/local_articles.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/data/local_folders.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/data/local_subscriptions.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/data/local_unread.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/data/locations.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/data/log.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/data/navigation_state.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/data/reset.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/data/tools.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/oldnews.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/providers/__init__.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/providers/main.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/py.typed +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/screens/__init__.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/screens/folder_input.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/screens/information_display.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/screens/login.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/screens/main.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/screens/new_subscription.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/sync.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/widgets/__init__.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/widgets/article_content.py +0 -0
- {oldnews-0.6.0 → oldnews-0.7.0}/src/oldnews/widgets/article_list.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: oldnews
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: A terminal-based client for TheOldReader
|
|
5
5
|
Keywords: atom,client,Google Reader,RSS,TheOldReader,terminal,news-reader,news
|
|
6
6
|
Author: Dave Pearson
|
|
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.14
|
|
16
16
|
Classifier: Typing :: Typed
|
|
17
17
|
Requires-Dist: html-to-markdown>=2.15.0
|
|
18
|
-
Requires-Dist: oldas>=0.
|
|
18
|
+
Requires-Dist: oldas>=0.10.0
|
|
19
19
|
Requires-Dist: textual>=6.3.0
|
|
20
20
|
Requires-Dist: textual-autocomplete>=4.0.6
|
|
21
21
|
Requires-Dist: textual-enhanced>=1.2.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "oldnews"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.7.0"
|
|
4
4
|
description = "A terminal-based client for TheOldReader"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -20,7 +20,7 @@ keywords = [
|
|
|
20
20
|
]
|
|
21
21
|
dependencies = [
|
|
22
22
|
"html-to-markdown>=2.15.0",
|
|
23
|
-
"oldas>=0.
|
|
23
|
+
"oldas>=0.10.0",
|
|
24
24
|
"textual>=6.3.0",
|
|
25
25
|
"textual-autocomplete>=4.0.6",
|
|
26
26
|
"textual-enhanced>=1.2.0",
|
|
@@ -45,7 +45,7 @@ def options_after_highlight[T](
|
|
|
45
45
|
highlight = (len(options) - highlight - 1) if direction == "previous" else highlight
|
|
46
46
|
return (
|
|
47
47
|
option
|
|
48
|
-
for option in [*options[highlight:], *options[
|
|
48
|
+
for option in [*options[highlight:], *options[:highlight]][1:]
|
|
49
49
|
if option_filter(option)
|
|
50
50
|
)
|
|
51
51
|
|
|
@@ -7,7 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
##############################################################################
|
|
8
8
|
# Python imports.
|
|
9
9
|
from dataclasses import dataclass
|
|
10
|
-
from typing import cast
|
|
10
|
+
from typing import Callable, Iterable, Iterator, cast
|
|
11
11
|
|
|
12
12
|
##############################################################################
|
|
13
13
|
# OldAs imports.
|
|
@@ -157,41 +157,86 @@ class Navigation(EnhancedOptionList):
|
|
|
157
157
|
self._expanded = get_navigation_state()
|
|
158
158
|
"""The IDs of the folders that are expanded."""
|
|
159
159
|
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
@staticmethod
|
|
161
|
+
def _key(attr: str) -> Callable[[object], str]:
|
|
162
|
+
"""Create a key to use with `sorted`.
|
|
162
163
|
|
|
163
164
|
Args:
|
|
164
|
-
|
|
165
|
+
attr: The attribute to sort on.
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
A function to get a `casefold` version of the attribute.
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
def _casefold(value: object) -> str:
|
|
172
|
+
return cast(str, getattr(value, attr)).casefold()
|
|
173
|
+
|
|
174
|
+
return _casefold
|
|
175
|
+
|
|
176
|
+
def _viewable(
|
|
177
|
+
self, subscriptions: Iterable[Subscription]
|
|
178
|
+
) -> Iterator[SubscriptionView]:
|
|
179
|
+
"""Given a iterable of subscriptions, make them viewable.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
subscriptions: The subscriptions to make viewable.
|
|
183
|
+
|
|
184
|
+
Yields:
|
|
185
|
+
Views of the subscriptions.
|
|
165
186
|
"""
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
self.add_option(SubscriptionView(subscription, self.unread))
|
|
187
|
+
yield from (
|
|
188
|
+
SubscriptionView(subscription, self.unread)
|
|
189
|
+
for subscription in sorted(subscriptions, key=self._key("title"))
|
|
190
|
+
)
|
|
171
191
|
|
|
172
|
-
def
|
|
173
|
-
|
|
192
|
+
def _gather_subscriptions_for_folder(
|
|
193
|
+
self, parent_folder: Folder
|
|
194
|
+
) -> Iterator[SubscriptionView]:
|
|
195
|
+
"""Gather the subscriptions for a given parent folder.
|
|
174
196
|
|
|
175
197
|
Args:
|
|
176
|
-
|
|
198
|
+
parent_folder: The parent folder to add the subscriptions for.
|
|
199
|
+
|
|
200
|
+
Yields:
|
|
201
|
+
The subscriptions within that folder.
|
|
202
|
+
"""
|
|
203
|
+
yield from self._viewable(
|
|
204
|
+
subscription
|
|
205
|
+
for subscription in self.subscriptions
|
|
206
|
+
if parent_folder in subscription.categories
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
def _gather_folders(self) -> Iterator[FolderView | SubscriptionView]:
|
|
210
|
+
"""Gather up all the folders and their subscriptions.
|
|
211
|
+
|
|
212
|
+
Yields:
|
|
213
|
+
Folder and subscription options.
|
|
214
|
+
"""
|
|
215
|
+
for folder in sorted(self.folders, key=self._key("name")):
|
|
216
|
+
yield FolderView(
|
|
217
|
+
folder, expanded := folder.id in self._expanded, self.unread
|
|
218
|
+
)
|
|
219
|
+
if expanded:
|
|
220
|
+
yield from self._gather_subscriptions_for_folder(folder)
|
|
221
|
+
|
|
222
|
+
def _gather_folderless_subscrtiptions(self) -> Iterator[SubscriptionView]:
|
|
223
|
+
"""Gather up all the subscriptions that don't live in a folder.
|
|
224
|
+
|
|
225
|
+
Yields:
|
|
226
|
+
Subscription options for folderless subscriptions.
|
|
177
227
|
"""
|
|
178
|
-
self.
|
|
179
|
-
|
|
228
|
+
yield from self._viewable(
|
|
229
|
+
subscription
|
|
230
|
+
for subscription in self.subscriptions
|
|
231
|
+
if not subscription.categories
|
|
180
232
|
)
|
|
181
|
-
if expanded:
|
|
182
|
-
self._add_subscriptions(folder.id)
|
|
183
233
|
|
|
184
234
|
def _refresh_navigation(self) -> None:
|
|
185
235
|
"""Refresh the content of the navigation widget."""
|
|
186
236
|
with self.preserved_highlight:
|
|
187
|
-
self.
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
if not subscription.categories:
|
|
191
|
-
self.add_option(SubscriptionView(subscription, self.unread))
|
|
192
|
-
# Now add all the subscriptions that are within folders.
|
|
193
|
-
for folder in self.folders:
|
|
194
|
-
self._add_folder(folder)
|
|
237
|
+
self.set_options(
|
|
238
|
+
(*self._gather_folderless_subscrtiptions(), *self._gather_folders())
|
|
239
|
+
)
|
|
195
240
|
|
|
196
241
|
def _watch_folders(self) -> None:
|
|
197
242
|
"""React to the folders being updated."""
|
|
@@ -205,6 +250,25 @@ class Navigation(EnhancedOptionList):
|
|
|
205
250
|
"""React to the unread data being updated."""
|
|
206
251
|
self._refresh_navigation()
|
|
207
252
|
|
|
253
|
+
@work(thread=True)
|
|
254
|
+
def _save_state(self, state: set[str]) -> None:
|
|
255
|
+
"""Save the folder expanded/collapsed state.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
state: The state to save.
|
|
259
|
+
"""
|
|
260
|
+
save_navigation_state(state)
|
|
261
|
+
|
|
262
|
+
def _set_expansion(self, new_state: set[str]) -> None:
|
|
263
|
+
"""Set the new navigation state.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
new_state: The new state to set.
|
|
267
|
+
"""
|
|
268
|
+
self._expanded = new_state
|
|
269
|
+
self._save_state(new_state)
|
|
270
|
+
self._refresh_navigation()
|
|
271
|
+
|
|
208
272
|
def _action_toggle_folder(self) -> None:
|
|
209
273
|
"""Action that toggles the expanded state of a folder."""
|
|
210
274
|
if self.highlighted is None:
|
|
@@ -215,26 +279,15 @@ class Navigation(EnhancedOptionList):
|
|
|
215
279
|
self.notify("Only folders can be collapsed/expanded", severity="warning")
|
|
216
280
|
return
|
|
217
281
|
if option.folder.id is not None:
|
|
218
|
-
self._expanded
|
|
219
|
-
self._save_state()
|
|
220
|
-
self._refresh_navigation()
|
|
282
|
+
self._set_expansion(self._expanded ^ {option.folder.id})
|
|
221
283
|
|
|
222
284
|
def _action_expand_all(self) -> None:
|
|
223
285
|
"""Action that expands all folders."""
|
|
224
|
-
self.
|
|
225
|
-
self._save_state()
|
|
226
|
-
self._refresh_navigation()
|
|
286
|
+
self._set_expansion({folder.id for folder in self.folders})
|
|
227
287
|
|
|
228
288
|
def _action_collapse_all(self) -> None:
|
|
229
289
|
"""Action that collapses all folders."""
|
|
230
|
-
self.
|
|
231
|
-
self._save_state()
|
|
232
|
-
self._refresh_navigation()
|
|
233
|
-
|
|
234
|
-
@work(thread=True)
|
|
235
|
-
def _save_state(self) -> None:
|
|
236
|
-
"""Save the folder expanded/collapsed state."""
|
|
237
|
-
save_navigation_state(self._expanded)
|
|
290
|
+
self._set_expansion(set())
|
|
238
291
|
|
|
239
292
|
@on(EnhancedOptionList.OptionSelected)
|
|
240
293
|
def _handle_selection(self, message: EnhancedOptionList.OptionSelected) -> None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|