Refactored page initialization, content initialization, and loading.

This commit is contained in:
Michael Lazar
2015-02-01 02:02:22 -08:00
parent 66dd4c5bd4
commit b8794e3599
6 changed files with 91 additions and 80 deletions

View File

@@ -135,7 +135,7 @@ class SubmissionContent(BaseContent):
def __init__( def __init__(
self, self,
submission, submission,
loader=default_loader(), loader=default_loader,
indent_size=2, indent_size=2,
max_indent_level=4): max_indent_level=4):
@@ -143,26 +143,35 @@ class SubmissionContent(BaseContent):
self.max_indent_level = max_indent_level self.max_indent_level = max_indent_level
self._loader = loader self._loader = loader
self._submissin = submission
self._submission_data = self.strip_praw_submission(submission) self._submission_data = self.strip_praw_submission(submission)
self.name = self._submission_data['permalink'] self.name = self._submission_data['permalink']
with loader: with self._loader():
comments = self.flatten_comments(submission.comments) comments = self.flatten_comments(submission.comments)
self._comment_data = [self.strip_praw_comment(c) for c in comments] self._comment_data = [self.strip_praw_comment(c) for c in comments]
@classmethod @classmethod
def from_url( def from_url(
cls, cls,
r, reddit,
url, url,
loader=default_loader(), loader=default_loader,
indent_size=2, indent_size=2,
max_indent_level=4): max_indent_level=4):
with loader: with loader():
submission = r.get_submission(url) submission = reddit.get_submission(url)
return cls(submission, loader, indent_size, max_indent_level) return cls(submission, loader, indent_size, max_indent_level)
def reset(self):
self._submissin.refresh()
self._submission_data = self.strip_praw_submission(submission)
self.name = self._submission_data['permalink']
comments = self.flatten_comments(submission.comments)
self._comment_data = [self.strip_praw_comment(c) for c in comments]
def get(self, index, n_cols=70): def get(self, index, n_cols=70):
""" """
Grab the `i`th submission, with the title field formatted to fit inside Grab the `i`th submission, with the title field formatted to fit inside
@@ -227,7 +236,7 @@ class SubmissionContent(BaseContent):
elif data['type'] == 'MoreComments': elif data['type'] == 'MoreComments':
with self._loader: with self._loader():
comments = data['object'].comments() comments = data['object'].comments()
comments = self.flatten_comments(comments, root_level=data['level']) comments = self.flatten_comments(comments, root_level=data['level'])
comment_data = [self.strip_praw_comment(c) for c in comments] comment_data = [self.strip_praw_comment(c) for c in comments]
@@ -249,23 +258,24 @@ class SubredditContent(BaseContent):
list for repeat access. list for repeat access.
""" """
def __init__(self, name, submission_generator, loader=default_loader()): def __init__(self, name, submissions, loader=default_loader):
self.name = name self.name = name
self._loader = loader self._loader = loader
self._submissions = submission_generator self._submissions = submissions
self._submission_data = [] self._submission_data = []
@classmethod @classmethod
def from_name(cls, r, name, loader=default_loader()): def from_name(cls, reddit, name, loader=default_loader):
if name == 'front': if name == 'front':
return cls('Front Page', r.get_front_page(limit=None), loader) return cls('Front Page', reddit.get_front_page(limit=None), loader)
if name == 'all': if name == 'all':
sub = r.get_subreddit(name) sub = reddit.get_subreddit(name)
else: else:
sub = r.get_subreddit(name, fetch=True) with loader():
sub = reddit.get_subreddit(name, fetch=True)
return cls('/r/'+sub.display_name, sub.get_hot(limit=None), loader) return cls('/r/'+sub.display_name, sub.get_hot(limit=None), loader)
@@ -281,7 +291,7 @@ class SubredditContent(BaseContent):
while index >= len(self._submission_data): while index >= len(self._submission_data):
try: try:
with self._loader: with self._loader():
submission = self._submissions.next() submission = self._submissions.next()
except StopIteration: except StopIteration:
raise IndexError raise IndexError

View File

@@ -1,7 +1,7 @@
import argparse import argparse
import praw import praw
from utils import curses_session, LoadScreen
from content import SubredditContent from utils import curses_session
from subreddit import SubredditPage from subreddit import SubredditPage
parser = argparse.ArgumentParser(description='Reddit Terminal Viewer') parser = argparse.ArgumentParser(description='Reddit Terminal Viewer')
@@ -13,17 +13,15 @@ group.add_argument('-p', dest='password', help='reddit password')
def main(args): def main(args):
r = praw.Reddit(user_agent='reddit terminal viewer v0.0') reddit = praw.Reddit(user_agent='reddit terminal viewer v0.0')
r.config.decode_html_entities = True reddit.config.decode_html_entities = True
if args.username and args.password: if args.username and args.password:
r.login(args.username, args.password) reddit.login(args.username, args.password)
with curses_session() as stdscr: with curses_session() as stdscr:
loader = LoadScreen(stdscr) page = SubredditPage(stdscr, reddit, args.subreddit)
content = SubredditContent(r, subreddit=args.subreddit, loader=loader)
page = SubredditPage(stdscr, content)
page.loop() page.loop()
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -79,14 +79,12 @@ class BasePage(object):
self.stdscr = stdscr self.stdscr = stdscr
self.content = content self.content = content
self.nav = Navigator(self.content.get, **kwargs) self.nav = Navigator(self.content.get, **kwargs)
self._header_window = None
self._content_window = None
self._subwindows = None self._subwindows = None
def draw(self):
raise NotImplementedError
def move_cursor_up(self): def move_cursor_up(self):
self._move_cursor(-1) self._move_cursor(-1)
@@ -106,12 +104,22 @@ class BasePage(object):
continue continue
self.stdscr.nodelay(0) self.stdscr.nodelay(0)
def draw(self):
n_rows, n_cols = self.stdscr.getmaxyx()
self._header_window = self.stdscr.derwin(1, n_cols, 0, 0)
self._content_window = self.stdscr.derwin(1, 0)
self.draw_header()
self.draw_content()
self.add_cursor()
def draw_header(self): def draw_header(self):
n_rows, n_cols = self._header_window.getmaxyx() n_rows, n_cols = self._header_window.getmaxyx()
self._header_window.erase() self._header_window.erase()
self._header_window.addnstr(0, 0, self.content.display_name, n_cols-1) self._header_window.addnstr(0, 0, self.content.name, n_cols-1)
def draw_content(self): def draw_content(self):
""" """

View File

@@ -1,18 +1,25 @@
import praw
import curses import curses
import sys import sys
from content import SubmissionContent
from page import BasePage from page import BasePage
from utils import curses_session from utils import LoadScreen
class SubmissionPage(BasePage): class SubmissionPage(BasePage):
def __init__(self, stdscr, content): def __init__(self, stdscr, reddit, url=None, submission=None):
self.loader = LoadScreen(stdscr)
if url is not None:
content = SubmissionContent.from_url(reddit, url, self.loader)
elif submission is not None:
content = SubmissionContent(submission, self.loader)
else:
raise ValueError('Must specify url or submission')
page_index, cursor_index = -1, 1
super(SubmissionPage, self).__init__( super(SubmissionPage, self).__init__(
stdscr, content, stdscr, content, page_index=-1, cursor_index=1)
page_index=page_index, cursor_index=cursor_index)
def loop(self): def loop(self):
@@ -61,16 +68,6 @@ class SubmissionPage(BasePage):
self.stdscr.clear() self.stdscr.clear()
self.draw() self.draw()
def draw(self):
n_rows, n_cols = self.stdscr.getmaxyx()
self._header_window = self.stdscr.derwin(1, n_cols, 0, 0)
self._content_window = self.stdscr.derwin(1, 0)
self.draw_header()
self.draw_content()
self.add_cursor()
def draw_item(self, win, data, inverted=False): def draw_item(self, win, data, inverted=False):
if data['type'] == 'MoreComments': if data['type'] == 'MoreComments':

View File

@@ -1,15 +1,22 @@
import praw
import textwrap
import curses import curses
import sys import sys
from page import BasePage from page import BasePage
from submission import SubmissionPage from submission import SubmissionPage
from content import SubmissionContent from content import SubredditContent
from utils import curses_session, text_input from utils import LoadScreen, text_input
class SubredditPage(BasePage): class SubredditPage(BasePage):
def __init__(self, stdscr, reddit, name):
self.reddit = reddit
self.name = name
self.loader = LoadScreen(stdscr)
content = SubredditContent.from_name(reddit, name, self.loader)
super(SubredditPage, self).__init__(stdscr, content)
def loop(self): def loop(self):
self.draw() self.draw()
@@ -47,11 +54,12 @@ class SubredditPage(BasePage):
else: else:
curses.beep() curses.beep()
def refresh_content(self, subreddit=None): def refresh_content(self, name=None):
self.nav.page_index, self.nav.cursor_index = 0, 0 self.nav.page_index, self.nav.cursor_index = 0, 0
self.nav.inverted = False self.nav.inverted = False
self.content.reset(subreddit=subreddit) self.name = name if name else self.name
self.content = SubredditContent.from_name(self.reddit, self.name, self.loader)
self.stdscr.clear() self.stdscr.clear()
self.draw() self.draw()
@@ -67,26 +75,15 @@ class SubredditPage(BasePage):
if out is None: if out is None:
self.draw() self.draw()
else: else:
self.refresh_content(subreddit=out) self.refresh_content(name=out)
def open_submission(self): def open_submission(self):
"Select the current submission to view posts" "Select the current submission to view posts"
submission = self.content.get(self.nav.absolute_index)['object'] submission = self.content.get(self.nav.absolute_index)['object']
content = SubmissionContent(submission, loader=self.content.loader) page = SubmissionPage(self.stdscr, self.reddit, submission=submission)
page = SubmissionPage(self.stdscr, content)
page.loop() page.loop()
def draw(self):
n_rows, n_cols = self.stdscr.getmaxyx()
self._header_window = self.stdscr.derwin(1, n_cols, 0, 0)
self._content_window = self.stdscr.derwin(1, 0)
self.draw_header()
self.draw_content()
self.add_cursor()
@staticmethod @staticmethod
def draw_item(win, data, inverted=False): def draw_item(win, data, inverted=False):

View File

@@ -42,26 +42,27 @@ def text_input(window):
class LoadScreen(object): class LoadScreen(object):
def __init__( def __init__(self, stdscr):
self,
stdscr,
message='Downloading',
trail='...',
delay=0.5,
interval=0.4):
self._stdscr = stdscr self._stdscr = stdscr
self.message = message
self.delay = delay
self.interval=interval
self.trail = trail
self._args = None
self._animator = None self._animator = None
self._is_running = None self._is_running = None
def __call__(
self,
delay=0.5,
interval=0.4,
message='Downloading',
trail='...'):
self._args = (delay, interval, message, trail)
return self
def __enter__(self): def __enter__(self):
self._animator = threading.Thread(target=self.animate) self._animator = threading.Thread(target=self.animate, args=self._args)
self._animator.daemon = True self._animator.daemon = True
self._is_running = True self._is_running = True
@@ -72,23 +73,23 @@ class LoadScreen(object):
self._is_running = False self._is_running = False
self._animator.join() self._animator.join()
def animate(self): def animate(self, delay, interval, message, trail):
# Delay before starting animation to avoid wasting resources if the # Delay before starting animation to avoid wasting resources if the
# wait time is very short # wait time is very short
start = time.time() start = time.time()
while (time.time() - start) < self.delay: while (time.time() - start) < delay:
if not self._is_running: if not self._is_running:
return return
message_len = len(self.message) + len(self.trail) message_len = len(message) + len(trail)
n_rows, n_cols = self._stdscr.getmaxyx() n_rows, n_cols = self._stdscr.getmaxyx()
s_row = (n_rows - 2) / 2 s_row = (n_rows - 2) / 2
s_col = (n_cols - message_len - 1) / 2 s_col = (n_cols - message_len - 1) / 2
window = self._stdscr.derwin(3, message_len+2, s_row, s_col) window = self._stdscr.derwin(3, message_len+2, s_row, s_col)
while True: while True:
for i in xrange(len(self.trail)+1): for i in xrange(len(trail)+1):
if not self._is_running: if not self._is_running:
# TODO: figure out why this isn't removing the screen # TODO: figure out why this isn't removing the screen
@@ -98,9 +99,9 @@ class LoadScreen(object):
window.erase() window.erase()
window.border() window.border()
window.addstr(1, 1, self.message + self.trail[:i]) window.addstr(1, 1, message + trail[:i])
window.refresh() window.refresh()
time.sleep(self.interval) time.sleep(interval)
@contextmanager @contextmanager