You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

285 lines
11 KiB

import urwid
import yaml
import asyncio
import warnings
from concurrent.futures import ThreadPoolExecutor
from API import Fetcher
from Render import Article
import Utils
warnings.filterwarnings("ignore")
class LeftPane(urwid.ListBox):
def __init__(self, categories):
super().__init__(self)
items = [urwid.AttrMap(urwid.Columns([
(16, urwid.Text(category["date"])), urwid.Text(category["name"]), (5, urwid.Text(str(category["count"])))]),
(category["id"], category["name"], category["count"]), "reveal focus") for category in categories]
walker = urwid.SimpleListWalker(items)
self.body = walker
self.categoryPosition = 0
self.isCategoryView = True
self.currentCategory = ""
focus_widget, idx = self.get_focus()
if self.isCategoryView:
self.currentCategory = focus_widget.attr_map[None][0]
def setArticlesPaneTitle(self, text):
tui.rightBox.set_title(text)
def getArticlesFromCategory(self, category, number=0):
tui.fetcher.articlesFromCategory(category, str(number))
articles = tui.fetcher.articles[category]
return articles
def getArticlesFromFeed(self, feed):
return tui.fetcher.articlesFromFeed(feed, self.currentCategory)
async def setCategoryArticles(self, attrMap):
itemId = attrMap[0]
number = attrMap[2]
name = attrMap[1]
await tui.fetcher.articlesFromCategoryAsync(itemId, str(number))
focus_widget, idx = self.get_focus()
currentCategory = focus_widget.attr_map[None][0]
if itemId == currentCategory:
tui.articles = tui.fetcher.articles[currentCategory]
tui.articleView.fill(tui.articles)
self.setArticlesPaneTitle(name)
def setFeedArticles(self, attrMap):
itemId = attrMap[0]
tui.articles = tui.fetcher.articlesFromFeed(itemId, self.currentCategory)
if tui.articles is not None:
tui.articleView.fill(tui.articles)
self.setArticlesPaneTitle(attrMap[1])
def keypress(self, size, key):
if key in ("j", "down"):
item_size = len(self.body)
focus_widget, idx = self.get_focus()
if idx < item_size - 1:
idx = idx + 1
self.set_focus(idx)
focus_widget, idx = self.get_focus()
if self.isCategoryView:
self.currentCategory = focus_widget.attr_map[None][0]
asyncio.create_task(self.setCategoryArticles(focus_widget.attr_map[None]))
else:
self.setFeedArticles(focus_widget.attr_map[None])
return
elif key in ("k", "up"):
focus_widget, idx = self.get_focus()
if idx > 0:
idx = idx - 1
self.set_focus(idx)
focus_widget, idx = self.get_focus()
if self.isCategoryView:
self.currentCategory = focus_widget.attr_map[None][0]
asyncio.create_task(self.setCategoryArticles(focus_widget.attr_map[None]))
else:
self.setFeedArticles(focus_widget.attr_map[None])
return
elif key in ("l", "right"):
if self.isCategoryView and tui.fetcher.checkCategory(self.currentCategory):
self.isCategoryView = False
focus_widget, idx = self.get_focus()
self.categoryPosition = idx
categoryId = focus_widget.attr_map[None][0]
categoryName = focus_widget.attr_map[None][1]
feeds = tui.fetcher.feedsFromCategory(categoryId)
feedItems = [urwid.AttrMap(urwid.Columns([(16, urwid.Text(tui.fetcher.unreadCounts[feed["id"]][2])),
urwid.Text(feed["title"]),
(5, urwid.Text(str(tui.fetcher.unreadCounts[feed["id"]][0])))]),
(feed["id"], feed["title"]), "reveal focus") for feed in feeds]
walker = urwid.SimpleListWalker(feedItems)
self.body = walker
focus_widget, idx = self.get_focus()
self.setFeedArticles(focus_widget.attr_map[None])
tui.leftBox.set_title(categoryName)
return
elif key in ("h", "left"):
if not self.isCategoryView:
self.isCategoryView = True
items = [
urwid.AttrMap(
urwid.Columns(
[(16, urwid.Text(category["date"])),
urwid.Text(category["name"]),
(5, urwid.Text(str(category["count"])))]),
(category["id"],
category["name"],
category["count"]),
"reveal focus") for category in tui.fetcher.categories]
walker = urwid.SimpleFocusListWalker(items)
self.body = walker
tui.leftBox.set_title("Categories")
self.set_focus(self.categoryPosition)
focus_widget, idx = self.get_focus()
tui.articles = self.getArticlesFromCategory(focus_widget.attr_map[None][0])
tui.articleView.fill(tui.articles)
self.setArticlesPaneTitle(self.currentCategory[13:])
return
return super().keypress(size, key)
class RightPane(urwid.ListBox):
def __init__(self, items):
super().__init__(self)
walker = urwid.SimpleListWalker([])
self.body = walker
self.isList = True
self.articlePosition = 0
self.article = None
self.chunkNumber = 0
def fill(self, articles):
items = [
urwid.AttrMap(
urwid.Columns(
[(2, urwid.Text("")),
(16, urwid.Text(Utils.timestampToDate(article["timestampUsec"]))),
urwid.Text(article["title"])]),
article["id"],
"reveal focus") for article in articles]
walker = urwid.SimpleListWalker(items)
self.body = walker
def getArticle(self, articleId):
article = [item for item in tui.fetcher.articles[tui.feedView.currentCategory] if item["id"] == articleId][0]
return article
def setArticleTitle(self):
tui.rightBox.set_title(self.article.title + " (" + str(self.article.currentPageNumber) + "/" +
str(self.article.numberOfPages) + ")")
def keypress(self, size, key):
if key in ("j", "down"):
if not self.isList:
walker = urwid.SimpleListWalker([urwid.Text(self.article.scrollDown())])
self.body = walker
self.setArticleTitle()
item_size = len(self.body)
focus_widget, idx = self.get_focus()
if idx < item_size - 1:
idx = idx + 1
self.set_focus(idx)
return
elif key in ("k", "up"):
if not self.isList:
walker = urwid.SimpleListWalker([urwid.Text(self.article.scrollUp())])
self.body = walker
self.setArticleTitle()
focus_widget, idx = self.get_focus()
if idx > 0:
idx = idx - 1
self.set_focus(idx)
return
elif key in ("l", "right"):
if self.isList is True:
self.isList = False
self.chunkNumber = 0
focus_widget, idx = self.get_focus()
self.articlePosition = idx
articleId = focus_widget.attr_map[None]
self.article = Article(self.getArticle(articleId))
walker = urwid.SimpleListWalker([urwid.Text(self.article.firstPage)])
self.body = walker
self.setArticleTitle()
return
elif key in ("h", "left"):
if self.isList is False:
self.isList = True
self.fill(tui.articles)
focusFeed, idx = tui.feedView.get_focus()
tui.rightBox.set_title(focusFeed.attr_map[None][1])
self.set_focus(self.articlePosition)
return
return super().keypress(size, key)
class TUI(urwid.Frame):
@classmethod
def create(cls):
tui = cls()
palette = [("linebox", "dark blue", "black"), ("text", "dark cyan", "dark cyan"),
('header', 'white', 'black'), ('reveal focus', 'black', 'dark cyan', 'standout')]
loop = urwid.MainLoop(
tui,
palette,
event_loop=urwid.AsyncioEventLoop(),
unhandled_input=tui.unhandled_input,
)
tui.loop = loop
return tui
def __init__(self):
with open('config.yml', 'r') as file:
config = yaml.safe_load(file)
URL = config["server"]["URL"]
token = config["server"]["token"]
self.fetcher = Fetcher(URL, token)
self.leftPaneItems = {}
self.activePane = False
self.executor = ThreadPoolExecutor(max_workers=1)
self.loop = None
self.feedView = LeftPane(self.fetcher.categories)
self.articleView = RightPane([])
self.leftBox = urwid.LineBox(self.feedView, title="Categories")
self.rightBox = urwid.LineBox(self.articleView, title="Articles")
self.views = urwid.Columns(
[(56, self.leftBox), self.rightBox])
self.status = urwid.Text("")
self.footer = urwid.ListBox([self.status])
self.container = urwid.Pile([self.views, (1, self.footer)])
self.body = self.container
self.articles = []
super().__init__(self.body)
def fetchAll(self):
articles = tui.fetcher.fetch()
for text in articles:
self.status.set_text(text)
tui.loop.entering_idle()
self.status.set_text("")
self.loop.event_loop.remove_alarm(self.handle)
def run(self):
focus_widget, idx = self.feedView.get_focus()
item = focus_widget.attr_map[None][0]
name = focus_widget.attr_map[None][1]
self.fetcher.articlesFromCategory(item, str(focus_widget.attr_map[None][2]))
self.articles = tui.fetcher.articles[item]
self.articleView.fill(self.articles)
self.feedView.setArticlesPaneTitle(name)
self.loop.run()
self.executor.shutdown(wait=False)
def unhandled_input(self, key):
if key == "tab":
self.activePane = not self.activePane
self.views.set_focus(int(self.activePane))
if self.activePane:
tui.articleView.isList = True
elif key == "q":
raise urwid.ExitMainLoop()
elif key == "r":
self.handle = self.loop.event_loop.alarm(0, self.fetchAll)
focus_widget, idx = self.feedView.get_focus()
itemId = focus_widget.attr_map[None][0]
self.articles = tui.fetcher.articles[itemId]
self.articleView.fill(self.articles)
tui = TUI.create()
tui.run()