Added animated loading box.
This commit is contained in:
@@ -3,6 +3,7 @@ import praw
|
|||||||
|
|
||||||
from utils import clean, strip_subreddit_url, humanize_timestamp
|
from utils import clean, strip_subreddit_url, humanize_timestamp
|
||||||
|
|
||||||
|
# TODO: rename, ... container?
|
||||||
class BaseContent(object):
|
class BaseContent(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import curses
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from content_generators import SubmissionContent, SubredditContent
|
from content_generators import SubmissionContent, SubredditContent
|
||||||
from utils import curses_session
|
from utils import curses_session, LoadScreen
|
||||||
from viewer import BaseViewer
|
from viewer import BaseViewer
|
||||||
|
|
||||||
class SubmissionViewer(BaseViewer):
|
class SubmissionViewer(BaseViewer):
|
||||||
@@ -50,7 +50,8 @@ class SubmissionViewer(BaseViewer):
|
|||||||
def refresh_content(self):
|
def refresh_content(self):
|
||||||
|
|
||||||
self.add_loading()
|
self.add_loading()
|
||||||
self.content.reset()
|
with LoadScreen(self.stdscr):
|
||||||
|
self.content.reset()
|
||||||
self.stdscr.clear()
|
self.stdscr.clear()
|
||||||
self.draw()
|
self.draw()
|
||||||
|
|
||||||
@@ -138,17 +139,3 @@ class SubmissionViewer(BaseViewer):
|
|||||||
win.addnstr(row, 1, text, n_cols)
|
win.addnstr(row, 1, text, n_cols)
|
||||||
|
|
||||||
win.border()
|
win.border()
|
||||||
|
|
||||||
def main():
|
|
||||||
|
|
||||||
with curses_session() as stdscr:
|
|
||||||
r = praw.Reddit(user_agent='reddit terminal viewer (rtv) v0.0')
|
|
||||||
submission = SubredditContent(r).get(0)['object']
|
|
||||||
generator = SubmissionContent(submission)
|
|
||||||
|
|
||||||
viewer = SubmissionViewer(stdscr, generator)
|
|
||||||
viewer.loop()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
|
||||||
main()
|
|
||||||
@@ -6,7 +6,7 @@ import sys
|
|||||||
from content_generators import SubredditContent, SubmissionContent
|
from content_generators import SubredditContent, SubmissionContent
|
||||||
from submission_viewer import SubmissionViewer
|
from submission_viewer import SubmissionViewer
|
||||||
from viewer import BaseViewer
|
from viewer import BaseViewer
|
||||||
from utils import curses_session, text_input
|
from utils import curses_session, text_input, LoadScreen
|
||||||
|
|
||||||
class SubredditViewer(BaseViewer):
|
class SubredditViewer(BaseViewer):
|
||||||
|
|
||||||
@@ -49,10 +49,10 @@ class SubredditViewer(BaseViewer):
|
|||||||
|
|
||||||
def refresh_content(self, subreddit=None):
|
def refresh_content(self, subreddit=None):
|
||||||
|
|
||||||
self.add_loading()
|
|
||||||
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)
|
with LoadScreen(self.stdscr):
|
||||||
|
self.content.reset(subreddit=subreddit)
|
||||||
self.stdscr.clear()
|
self.stdscr.clear()
|
||||||
self.draw()
|
self.draw()
|
||||||
|
|
||||||
@@ -73,10 +73,9 @@ class SubredditViewer(BaseViewer):
|
|||||||
def open_submission(self):
|
def open_submission(self):
|
||||||
"Select the current submission to view posts"
|
"Select the current submission to view posts"
|
||||||
|
|
||||||
self.add_loading()
|
with LoadScreen(self.stdscr):
|
||||||
|
submission = self.content.get(self.nav.absolute_index)['object']
|
||||||
submission = self.content.get(self.nav.absolute_index)['object']
|
content = SubmissionContent(submission)
|
||||||
content = SubmissionContent(submission)
|
|
||||||
viewer = SubmissionViewer(self.stdscr, content)
|
viewer = SubmissionViewer(self.stdscr, content)
|
||||||
viewer.loop()
|
viewer.loop()
|
||||||
|
|
||||||
|
|||||||
67
rtv/utils.py
67
rtv/utils.py
@@ -1,13 +1,76 @@
|
|||||||
from datetime import datetime, timedelta
|
|
||||||
from contextlib import contextmanager
|
|
||||||
import os
|
import os
|
||||||
import curses
|
import curses
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
from curses import textpad
|
from curses import textpad
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from contextlib import contextmanager
|
||||||
|
|
||||||
class EscapePressed(Exception):
|
class EscapePressed(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LoadScreen(object):
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
stdscr,
|
||||||
|
message='Downloading',
|
||||||
|
trail='...',
|
||||||
|
delay=0.5,
|
||||||
|
interval=0.4):
|
||||||
|
|
||||||
|
self._stdscr = stdscr
|
||||||
|
self.message = message
|
||||||
|
self.delay = delay
|
||||||
|
self.interval=interval
|
||||||
|
self.trail = trail
|
||||||
|
|
||||||
|
message_len = len(self.message) + len(self.trail)
|
||||||
|
n_rows, n_cols = stdscr.getmaxyx()
|
||||||
|
s_row = (n_rows - 2) / 2
|
||||||
|
s_col = (n_cols - message_len - 1) / 2
|
||||||
|
self.window = stdscr.derwin(3, message_len+2, s_row, s_col)
|
||||||
|
|
||||||
|
self._animator = threading.Thread(target=self.animate)
|
||||||
|
self._animator.daemon = True
|
||||||
|
self._is_running = None
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
|
||||||
|
self._is_running = True
|
||||||
|
self._animator.start()
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
|
||||||
|
self._is_running = False
|
||||||
|
self._animator.join()
|
||||||
|
|
||||||
|
del self.window
|
||||||
|
self._stdscr.refresh()
|
||||||
|
|
||||||
|
def animate(self):
|
||||||
|
|
||||||
|
# Delay before popping up the animation to avoid flashing
|
||||||
|
# the screen if the load time is effectively zero
|
||||||
|
start = time.time()
|
||||||
|
while (time.time() - start) < self.delay:
|
||||||
|
if not self._is_running:
|
||||||
|
return
|
||||||
|
|
||||||
|
while True:
|
||||||
|
for i in xrange(len(self.trail)+1):
|
||||||
|
|
||||||
|
if not self._is_running:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.window.erase()
|
||||||
|
self.window.border()
|
||||||
|
self.window.addstr(1, 1, self.message + self.trail[:i])
|
||||||
|
self.window.refresh()
|
||||||
|
time.sleep(self.interval)
|
||||||
|
|
||||||
|
|
||||||
def clean(unicode_string):
|
def clean(unicode_string):
|
||||||
"""
|
"""
|
||||||
Convert unicode string into ascii-safe characters.
|
Convert unicode string into ascii-safe characters.
|
||||||
|
|||||||
@@ -83,7 +83,6 @@ class BaseViewer(object):
|
|||||||
self.nav = Navigator(self.content.get, **kwargs)
|
self.nav = Navigator(self.content.get, **kwargs)
|
||||||
|
|
||||||
self._subwindows = None
|
self._subwindows = None
|
||||||
self.add_loading()
|
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
@@ -107,20 +106,6 @@ class BaseViewer(object):
|
|||||||
continue
|
continue
|
||||||
self.stdscr.nodelay(0)
|
self.stdscr.nodelay(0)
|
||||||
|
|
||||||
def add_loading(self):
|
|
||||||
"Draw a `loading` popup dialog in the center of the screen"
|
|
||||||
|
|
||||||
message = 'Loading...'
|
|
||||||
|
|
||||||
n_rows, n_cols = self.stdscr.getmaxyx()
|
|
||||||
win_rows, win_cols = 3, len(message)+2
|
|
||||||
start_row = (n_rows - win_rows) / 2
|
|
||||||
start_col = (n_cols - win_cols) / 2
|
|
||||||
window = self.stdscr.derwin(win_rows, win_cols, start_row, start_col)
|
|
||||||
window.border()
|
|
||||||
window.addstr(1, 1, message)
|
|
||||||
window.refresh()
|
|
||||||
|
|
||||||
def draw_header(self):
|
def draw_header(self):
|
||||||
|
|
||||||
n_rows, n_cols = self._header_window.getmaxyx()
|
n_rows, n_cols = self._header_window.getmaxyx()
|
||||||
|
|||||||
Reference in New Issue
Block a user