oldnews 0.3.0__tar.gz → 0.4.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.3.0 → oldnews-0.4.0}/PKG-INFO +1 -1
- {oldnews-0.3.0 → oldnews-0.4.0}/pyproject.toml +1 -1
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/commands/__init__.py +10 -2
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/commands/main.py +30 -2
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/providers/main.py +10 -2
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/screens/main.py +88 -10
- {oldnews-0.3.0/src/oldnews/sync → oldnews-0.4.0/src/oldnews}/sync.py +3 -3
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/widgets/navigation.py +14 -0
- oldnews-0.3.0/src/oldnews/sync/__init__.py +0 -11
- {oldnews-0.3.0 → oldnews-0.4.0}/README.md +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/__init__.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/__main__.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/data/__init__.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/data/auth.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/data/config.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/data/db.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/data/last_grab.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/data/local_articles.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/data/local_folders.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/data/local_subscriptions.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/data/local_unread.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/data/locations.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/data/navigation_state.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/data/reset.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/oldnews.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/providers/__init__.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/py.typed +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/screens/__init__.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/screens/login.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/widgets/__init__.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/widgets/_after_highlight.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/widgets/article_content.py +0 -0
- {oldnews-0.3.0 → oldnews-0.4.0}/src/oldnews/widgets/article_list.py +0 -0
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
##############################################################################
|
|
4
4
|
# Local imports.
|
|
5
5
|
from .main import (
|
|
6
|
+
Copy,
|
|
7
|
+
CopyArticleToClipboard,
|
|
8
|
+
CopyFeedToClipboard,
|
|
9
|
+
CopyHomePageToClipboard,
|
|
6
10
|
Escape,
|
|
7
11
|
MarkAllRead,
|
|
8
12
|
Next,
|
|
9
13
|
NextUnread,
|
|
10
14
|
OpenArticle,
|
|
11
|
-
|
|
15
|
+
OpenHomePage,
|
|
12
16
|
Previous,
|
|
13
17
|
PreviousUnread,
|
|
14
18
|
RefreshFromTheOldReader,
|
|
@@ -18,12 +22,16 @@ from .main import (
|
|
|
18
22
|
##############################################################################
|
|
19
23
|
# Exports.
|
|
20
24
|
__all__ = [
|
|
25
|
+
"Copy",
|
|
26
|
+
"CopyArticleToClipboard",
|
|
27
|
+
"CopyFeedToClipboard",
|
|
28
|
+
"CopyHomePageToClipboard",
|
|
21
29
|
"Escape",
|
|
22
30
|
"MarkAllRead",
|
|
23
31
|
"Next",
|
|
24
32
|
"NextUnread",
|
|
25
33
|
"OpenArticle",
|
|
26
|
-
"
|
|
34
|
+
"OpenHomePage",
|
|
27
35
|
"Previous",
|
|
28
36
|
"PreviousUnread",
|
|
29
37
|
"RefreshFromTheOldReader",
|
|
@@ -64,8 +64,8 @@ class OpenArticle(Command):
|
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
##############################################################################
|
|
67
|
-
class
|
|
68
|
-
"""Open the
|
|
67
|
+
class OpenHomePage(Command):
|
|
68
|
+
"""Open the home page for the current subscription in the web browser"""
|
|
69
69
|
|
|
70
70
|
BINDING_KEY = "O"
|
|
71
71
|
|
|
@@ -77,4 +77,32 @@ class MarkAllRead(Command):
|
|
|
77
77
|
BINDING_KEY = "R"
|
|
78
78
|
|
|
79
79
|
|
|
80
|
+
##############################################################################
|
|
81
|
+
class CopyHomePageToClipboard(Command):
|
|
82
|
+
"""Copy the URL of the current subscription's home page to the clipboard"""
|
|
83
|
+
|
|
84
|
+
BINDING_KEY = "f3"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
##############################################################################
|
|
88
|
+
class CopyFeedToClipboard(Command):
|
|
89
|
+
"""Copy the URL of the current subscription's feed to the clipboard"""
|
|
90
|
+
|
|
91
|
+
BINDING_KEY = "f4"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
##############################################################################
|
|
95
|
+
class CopyArticleToClipboard(Command):
|
|
96
|
+
"""Copy the URL for the current article to the clipboard"""
|
|
97
|
+
|
|
98
|
+
BINDING_KEY = "f5"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
##############################################################################
|
|
102
|
+
class Copy(Command):
|
|
103
|
+
"""Copy a URL to the clipboard depending on the context"""
|
|
104
|
+
|
|
105
|
+
BINDING_KEY = "ctrl+c"
|
|
106
|
+
|
|
107
|
+
|
|
80
108
|
### main.py ends here
|
|
@@ -13,12 +13,16 @@ from textual_enhanced.commands import (
|
|
|
13
13
|
##############################################################################
|
|
14
14
|
# Local imports.
|
|
15
15
|
from ..commands import (
|
|
16
|
+
Copy,
|
|
17
|
+
CopyArticleToClipboard,
|
|
18
|
+
CopyFeedToClipboard,
|
|
19
|
+
CopyHomePageToClipboard,
|
|
16
20
|
Escape,
|
|
17
21
|
MarkAllRead,
|
|
18
22
|
Next,
|
|
19
23
|
NextUnread,
|
|
20
24
|
OpenArticle,
|
|
21
|
-
|
|
25
|
+
OpenHomePage,
|
|
22
26
|
Previous,
|
|
23
27
|
PreviousUnread,
|
|
24
28
|
RefreshFromTheOldReader,
|
|
@@ -42,8 +46,12 @@ class MainCommands(CommandsProvider):
|
|
|
42
46
|
yield from self.maybe(Previous)
|
|
43
47
|
yield from self.maybe(PreviousUnread)
|
|
44
48
|
yield from self.maybe(OpenArticle)
|
|
45
|
-
yield from self.maybe(
|
|
49
|
+
yield from self.maybe(OpenHomePage)
|
|
46
50
|
yield from self.maybe(MarkAllRead)
|
|
51
|
+
yield from self.maybe(CopyHomePageToClipboard)
|
|
52
|
+
yield from self.maybe(CopyFeedToClipboard)
|
|
53
|
+
yield from self.maybe(CopyArticleToClipboard)
|
|
54
|
+
yield from self.maybe(Copy)
|
|
47
55
|
yield ToggleShowAll()
|
|
48
56
|
yield RefreshFromTheOldReader()
|
|
49
57
|
yield ChangeTheme()
|
|
@@ -38,12 +38,16 @@ from textual_enhanced.screen import EnhancedScreen
|
|
|
38
38
|
# Local imports.
|
|
39
39
|
from .. import __version__
|
|
40
40
|
from ..commands import (
|
|
41
|
+
Copy,
|
|
42
|
+
CopyArticleToClipboard,
|
|
43
|
+
CopyFeedToClipboard,
|
|
44
|
+
CopyHomePageToClipboard,
|
|
41
45
|
Escape,
|
|
42
46
|
MarkAllRead,
|
|
43
47
|
Next,
|
|
44
48
|
NextUnread,
|
|
45
49
|
OpenArticle,
|
|
46
|
-
|
|
50
|
+
OpenHomePage,
|
|
47
51
|
Previous,
|
|
48
52
|
PreviousUnread,
|
|
49
53
|
RefreshFromTheOldReader,
|
|
@@ -117,6 +121,13 @@ class Main(EnhancedScreen[None]):
|
|
|
117
121
|
width: 25%;
|
|
118
122
|
}
|
|
119
123
|
|
|
124
|
+
#article-view {
|
|
125
|
+
display: none;
|
|
126
|
+
&.--has-articles {
|
|
127
|
+
display: block;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
120
131
|
ArticleList {
|
|
121
132
|
height: 1fr;
|
|
122
133
|
}
|
|
@@ -142,8 +153,12 @@ class Main(EnhancedScreen[None]):
|
|
|
142
153
|
Previous,
|
|
143
154
|
PreviousUnread,
|
|
144
155
|
OpenArticle,
|
|
145
|
-
|
|
156
|
+
OpenHomePage,
|
|
146
157
|
ChangeTheme,
|
|
158
|
+
CopyHomePageToClipboard,
|
|
159
|
+
CopyFeedToClipboard,
|
|
160
|
+
CopyArticleToClipboard,
|
|
161
|
+
Copy,
|
|
147
162
|
]
|
|
148
163
|
|
|
149
164
|
BINDINGS = Command.bindings(*COMMAND_MESSAGES)
|
|
@@ -208,7 +223,7 @@ class Main(EnhancedScreen[None]):
|
|
|
208
223
|
yield Navigation(classes="panel").data_bind(
|
|
209
224
|
Main.folders, Main.subscriptions, Main.unread
|
|
210
225
|
)
|
|
211
|
-
with Vertical():
|
|
226
|
+
with Vertical(id="article-view"):
|
|
212
227
|
yield ArticleList(classes="panel").data_bind(
|
|
213
228
|
Main.articles, Main.current_category
|
|
214
229
|
)
|
|
@@ -237,8 +252,14 @@ class Main(EnhancedScreen[None]):
|
|
|
237
252
|
# but okay let's be defensive... (when I can come up with a nice
|
|
238
253
|
# little MRE I'll report it).
|
|
239
254
|
return True
|
|
240
|
-
if action in (OpenArticle.action_name(),
|
|
255
|
+
if action in (OpenArticle.action_name(), CopyArticleToClipboard.action_name()):
|
|
241
256
|
return self.article is not None
|
|
257
|
+
if action in (
|
|
258
|
+
OpenHomePage.action_name(),
|
|
259
|
+
CopyFeedToClipboard.action_name(),
|
|
260
|
+
CopyHomePageToClipboard.action_name(),
|
|
261
|
+
):
|
|
262
|
+
return self.query_one(Navigation).current_subscription is not None
|
|
242
263
|
if action in (Next.action_name(), Previous.action_name()):
|
|
243
264
|
return self.articles is not None
|
|
244
265
|
if action in (
|
|
@@ -255,6 +276,11 @@ class Main(EnhancedScreen[None]):
|
|
|
255
276
|
return self.articles is not None and any(
|
|
256
277
|
article.is_unread for article in self.articles
|
|
257
278
|
)
|
|
279
|
+
if action == Copy.action_name():
|
|
280
|
+
return (
|
|
281
|
+
(navigation := self.query_one(Navigation)).has_focus
|
|
282
|
+
and navigation.current_subscription is not None
|
|
283
|
+
) or self.query_one("#article-view").has_focus_within
|
|
258
284
|
return True
|
|
259
285
|
|
|
260
286
|
@on(SubTitle)
|
|
@@ -300,6 +326,13 @@ class Main(EnhancedScreen[None]):
|
|
|
300
326
|
"""Refresh the content of the article list."""
|
|
301
327
|
if self.current_category:
|
|
302
328
|
self.articles = get_local_articles(self.current_category, not self.show_all)
|
|
329
|
+
# If the result is there's nothing showing, tidy up the content
|
|
330
|
+
# side of the display and maybe move focus back to navigation.
|
|
331
|
+
if not self.articles:
|
|
332
|
+
self.article = None
|
|
333
|
+
if self.query_one("#article-view").has_focus_within:
|
|
334
|
+
self.query_one(Navigation).focus()
|
|
335
|
+
self.query_one("#article-view").set_class(bool(self.articles), "--has-articles")
|
|
303
336
|
|
|
304
337
|
@work(thread=True, exclusive=True)
|
|
305
338
|
def _load_locally(self) -> None:
|
|
@@ -494,17 +527,62 @@ class Main(EnhancedScreen[None]):
|
|
|
494
527
|
severity="error",
|
|
495
528
|
)
|
|
496
529
|
|
|
497
|
-
def
|
|
498
|
-
"""Open the
|
|
499
|
-
if self.
|
|
500
|
-
if
|
|
501
|
-
open_url(
|
|
530
|
+
def action_open_home_page_command(self) -> None:
|
|
531
|
+
"""Open the home page of the current subscription in the web browser."""
|
|
532
|
+
if subscription := self.query_one(Navigation).current_subscription:
|
|
533
|
+
if subscription.html_url:
|
|
534
|
+
open_url(subscription.html_url)
|
|
502
535
|
else:
|
|
503
536
|
self.notify(
|
|
504
|
-
"No URL available for the
|
|
537
|
+
"No home page URL available for the subscription",
|
|
505
538
|
severity="error",
|
|
506
539
|
title="Can't visit",
|
|
507
540
|
)
|
|
508
541
|
|
|
542
|
+
def _copy_to_clipboard(self, content: str | None, empty_error: str) -> None:
|
|
543
|
+
"""Copy some content to the clipboard.
|
|
544
|
+
|
|
545
|
+
Args:
|
|
546
|
+
content: The content to copy to the clipboard.
|
|
547
|
+
empty_error: The message to show if there's no content.
|
|
548
|
+
"""
|
|
549
|
+
if content:
|
|
550
|
+
self.app.copy_to_clipboard(content)
|
|
551
|
+
self.notify("Copied to clipboard")
|
|
552
|
+
else:
|
|
553
|
+
self.notify(empty_error, severity="error", title="Can't copy")
|
|
554
|
+
|
|
555
|
+
def action_copy_home_page_to_clipboard_command(self) -> None:
|
|
556
|
+
"""Copy the URL of the current subscription's homepage to the clipboard."""
|
|
557
|
+
if subscription := self.query_one(Navigation).current_subscription:
|
|
558
|
+
self._copy_to_clipboard(
|
|
559
|
+
subscription.html_url, "No home page URL available for the subscription"
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
def action_copy_feed_to_clipboard_command(self) -> None:
|
|
563
|
+
"""Copy the URL of the current subscription's feed to the clipboard."""
|
|
564
|
+
if subscription := self.query_one(Navigation).current_subscription:
|
|
565
|
+
self._copy_to_clipboard(
|
|
566
|
+
subscription.url, "No feed URL available for the subscription"
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
def action_copy_article_to_clipboard_command(self) -> None:
|
|
570
|
+
"""Copy the URL of the current article to the clipboard."""
|
|
571
|
+
if self.article:
|
|
572
|
+
self._copy_to_clipboard(
|
|
573
|
+
self.article.html_url, "No URL available for the article"
|
|
574
|
+
)
|
|
575
|
+
|
|
576
|
+
def action_copy_command(self) -> None:
|
|
577
|
+
"""Copy a URL to the clipboard depending on the current context."""
|
|
578
|
+
if (navigation := self.query_one(Navigation)).has_focus:
|
|
579
|
+
if navigation.current_subscription:
|
|
580
|
+
self.action_copy_home_page_to_clipboard_command()
|
|
581
|
+
elif self.query_one("#article-view").has_focus_within:
|
|
582
|
+
if self.article:
|
|
583
|
+
self.action_copy_article_to_clipboard_command()
|
|
584
|
+
else:
|
|
585
|
+
self.action_copy_home_page_to_clipboard_command()
|
|
586
|
+
|
|
509
587
|
|
|
510
588
|
### main.py ends here
|
|
@@ -11,7 +11,7 @@ from typing import Any, Callable
|
|
|
11
11
|
from oldas import ArticleIDs, Articles, Folders, Session, Subscriptions
|
|
12
12
|
|
|
13
13
|
##############################################################################
|
|
14
|
-
from
|
|
14
|
+
from .data import (
|
|
15
15
|
LocalUnread,
|
|
16
16
|
get_local_unread,
|
|
17
17
|
get_unread_article_ids,
|
|
@@ -71,10 +71,10 @@ class ToRSync:
|
|
|
71
71
|
|
|
72
72
|
async def _download_newest_articles(self) -> None:
|
|
73
73
|
"""Download the latest articles available."""
|
|
74
|
+
new_grab = datetime.now(timezone.utc)
|
|
74
75
|
last_grabbed = last_grabbed_data_at() or (
|
|
75
|
-
|
|
76
|
+
new_grab - timedelta(days=load_configuration().local_history)
|
|
76
77
|
)
|
|
77
|
-
new_grab = datetime.now(timezone.utc)
|
|
78
78
|
loaded = 0
|
|
79
79
|
async for article in Articles.stream_new_since(
|
|
80
80
|
self.session, last_grabbed, n=10
|
|
@@ -238,6 +238,20 @@ class Navigation(EnhancedOptionList):
|
|
|
238
238
|
return selected.subscription
|
|
239
239
|
raise ValueError("Unknown category")
|
|
240
240
|
|
|
241
|
+
@property
|
|
242
|
+
def current_folder(self) -> Folder | None:
|
|
243
|
+
"""The current folder, if one is highlighted, or `None`"""
|
|
244
|
+
if isinstance(current := self.current_category, Folder):
|
|
245
|
+
return current
|
|
246
|
+
return None
|
|
247
|
+
|
|
248
|
+
@property
|
|
249
|
+
def current_subscription(self) -> Subscription | None:
|
|
250
|
+
"""The current subscription, if one is highlighted, or `None`."""
|
|
251
|
+
if isinstance(current := self.current_category, Subscription):
|
|
252
|
+
return current
|
|
253
|
+
return None
|
|
254
|
+
|
|
241
255
|
def _highlight_unread(self, direction: HighlightDirection) -> bool:
|
|
242
256
|
"""Highlight the next category with unread articles, if there is one.
|
|
243
257
|
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
"""Code to sync the local data from TheOldReader."""
|
|
2
|
-
|
|
3
|
-
##############################################################################
|
|
4
|
-
# Local imports.
|
|
5
|
-
from .sync import ToRSync
|
|
6
|
-
|
|
7
|
-
##############################################################################
|
|
8
|
-
# Exports.
|
|
9
|
-
__all__ = ["ToRSync"]
|
|
10
|
-
|
|
11
|
-
### __init__.py ends here
|
|
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
|