aboutsummaryrefslogtreecommitdiffstats
path: root/clients/urwid/main.py
diff options
context:
space:
mode:
authorBlake DeMarcy <ofunknowndescent@gmail.com>2017-04-08 05:09:50 -0500
committerBlake DeMarcy <ofunknowndescent@gmail.com>2017-04-08 05:09:50 -0500
commit1b670575275a2111272599d4687aff8e944f875e (patch)
tree73f84222ec4e15a491ac1621fc62ff79755c2018 /clients/urwid/main.py
parent5358639307915d53e62c0512de59655d8562bcc6 (diff)
downloadbbj-1b670575275a2111272599d4687aff8e944f875e.tar.gz
new time and bar display methods
Diffstat (limited to 'clients/urwid/main.py')
-rw-r--r--clients/urwid/main.py145
1 files changed, 90 insertions, 55 deletions
diff --git a/clients/urwid/main.py b/clients/urwid/main.py
index 98d2f89..ad2fb52 100644
--- a/clients/urwid/main.py
+++ b/clients/urwid/main.py
@@ -1,6 +1,7 @@
# -*- fill-column: 72 -*-
from time import time, sleep, localtime
+from datetime import datetime
from network import BBJ, URLError
from string import punctuation
from subprocess import run
@@ -49,17 +50,19 @@ editors = ["nano", "emacs", "vim", "micro", "ed", "joe"]
default_prefs = {
# well, it WILL default to the internal editor when I write it =)
"editor": "vim",
- "dramatic_exit": True
+ "dramatic_exit": True,
+ "date": "%Y/%m/%d",
+ "time": "%H:%M"
}
class App(object):
def __init__(self):
- self.mode = None
- self.thread = None
- self.usermap = {}
- self.prefs = bbjrc("load")
- self.window_split = False
+ self.bars = {
+ "index": "[C]ompose [R]efresh [/]Search [O]ptions [?]Help/More [Q]uit",
+ "thread": "[C]ompose [Q]Back [R]efresh [E]dit [/]Search [B/T]End [?]Help/More"
+ }
+
colors = [
("bar", "light magenta", "default"),
("button", "light red", "default"),
@@ -74,16 +77,22 @@ class App(object):
("5", "light cyan", "default"),
("6", "light magenta", "default")
]
- self.loop = urwid.MainLoop(urwid.Frame(
- urwid.LineBox(ActionBox(urwid.SimpleFocusListWalker([])),
- title="> > T I L D E T O W N < <",
- tlcorner="@", tline="=", lline="|", rline="|",
- bline="=", trcorner="@", brcorner="@", blcorner="@"
- )), colors)
- self.walker = self.loop.widget.body.base_widget.body
+ self.mode = None
+ self.thread = None
+ self.usermap = {}
+ self.prefs = bbjrc("load")
+ self.window_split = False
self.last_pos = 0
- self.date_format = "{1}/{2}/{0}"
+
+ self.walker = urwid.SimpleFocusListWalker([])
+ self.loop = urwid.MainLoop(urwid.Frame(
+ urwid.LineBox(ActionBox(self.walker),
+ title="> > T I L D E T O W N < <",
+ tlcorner="@", trcorner="@", blcorner="@", brcorner="@",
+ tline="=", bline="=", lline="|", rline="|"
+ )), colors)
+
self.index()
@@ -99,42 +108,48 @@ class App(object):
), "bar")
- def set_footer(self, *controls, static_string=""):
+ def set_footer(self, string):
"""
- Sets the footer, emphasizing the first character of each string
- argument passed to it. Used to show controls to the user. Applies
- bar formatting.
+ Sets the footer to display `string`, applying bar formatting.
+ Other than setting the color, `string` is shown verbatim.
"""
- text = str()
- for control in controls:
- text += "[{}]{} ".format(control[0], control[1:])
- text += static_string
- self.loop.widget.footer = urwid.AttrMap(urwid.Text(text), "bar")
+ self.loop.widget.footer = \
+ urwid.AttrMap(urwid.Text(string), "bar")
def close_editor(self):
+ """
+ Close whatever editing widget is open and restore proper
+ state back the walker.
+ """
if self.window_split:
self.window_split = False
self.loop.widget.focus_position = "body"
- self.set_footer("lmao")
+ self.set_footer(self.bars["thread"])
+ name = self.usermap[self.thread["author"]]["user_name"]
+ self.set_header("~{}: {}", name, self.thread["title"])
else:
self.loop.widget = self.loop.widget[0]
def switch_editor(self):
+ """
+ Switch focus between the thread viewer and the open editor
+ """
if not self.window_split:
return
+
elif self.loop.widget.focus_position == "body":
self.loop.widget.focus_position = "footer"
focus = "[focused on editor]"
+
else:
self.loop.widget.focus_position = "body"
focus = "[focused on thread]"
- if self.window_split:
- control = ("" if self.prefs["editor"] else " [F3]Send")
- self.loop.widget.footer[0].set_text(
- "[F1]Abort [F2]Swap%s %s" % (control, focus)
- )
+
+ control = "[save/quit to send]" if self.prefs["editor"] else "[F3]Send"
+ self.loop.widget.footer[0].set_text(
+ "[F1]Abort [F2]Swap %s %s" % (control, focus))
def readable_delta(self, modified):
@@ -145,7 +160,7 @@ class App(object):
delta = time() - modified
hours, remainder = divmod(delta, 3600)
if hours > 48:
- return self.date_format.format(*localtime(modified))
+ return self.timestring(modified)
elif hours > 1:
return "%d hours ago" % hours
elif hours == 1:
@@ -158,7 +173,7 @@ class App(object):
def make_message_body(self, message):
name = urwid.Text("~{}".format(self.usermap[message["author"]]["user_name"]))
- info = "@ " + self.date_format.format(*localtime(message["created"]))
+ info = "@ " + self.timestring(message["created"])
if message["edited"]:
info += " [edited]"
@@ -180,17 +195,34 @@ class App(object):
return pile
+ def timestring(self, epoch, mode="both"):
+ if mode == "delta":
+ return self.readable_delta(epoch)
+
+ date = datetime.fromtimestamp(epoch)
+ if mode == "time":
+ directive = self.prefs["time"]
+ elif mode == "date":
+ directive = self.prefs["date"]
+ else:
+ directive = "%s %s" % (self.prefs["date"], self.prefs["time"])
+ return date.strftime(directive)
+
+
def make_thread_body(self, thread):
button = cute_button(">>", self.thread_load, thread["thread_id"])
title = urwid.Text(thread["title"])
- infoline = "by ~{} @ {} | last active {}".format(
+ dateline = "by ~{} @ {}".format(
self.usermap[thread["author"]]["user_name"],
- self.date_format.format(*localtime(thread["created"])),
- self.readable_delta(thread["last_mod"])
+ self.timestring(thread["created"])
)
+ infoline = "%d replies; active %s" % (
+ thread["reply_count"], self.timestring(thread["last_mod"], "delta"))
+
pile = urwid.Pile([
urwid.Columns([(3, urwid.AttrMap(button, "button")), title]),
+ urwid.AttrMap(urwid.Text(dateline), "dim"),
urwid.AttrMap(urwid.Text(infoline), "dim"),
urwid.AttrMap(urwid.Divider("-"), "dim")
])
@@ -209,11 +241,13 @@ class App(object):
threads, usermap = network.thread_index()
self.usermap.update(usermap)
self.set_header("{} threads", len(threads))
- self.set_footer("Refresh", "Compose", "Quit", "/Search", "?Help")
+ self.set_footer(self.bars["index"])
self.walker.clear()
for thread in threads:
self.walker.append(self.make_thread_body(thread))
- self.loop.widget.body.base_widget.set_focus(self.last_pos)
+ try: self.loop.widget.body.base_widget.set_focus(self.last_pos)
+ except IndexError:
+ pass
def thread_load(self, button, thread_id):
@@ -229,11 +263,7 @@ class App(object):
self.walker.clear()
self.set_header("~{}: {}",
usermap[thread["author"]]["user_name"], thread["title"])
- self.set_footer(
- "Compose", "Refresh",
- "\"Quote", "/Search",
- "Top", "Bottom", "QBack"
- )
+ self.set_footer(self.bars["thread"])
for message in thread["messages"]:
self.walker.append(self.make_message_body(message))
@@ -241,7 +271,9 @@ class App(object):
def refresh(self):
if self.mode == "index":
- self.index()
+ return self.index()
+ self.thread_load(None, self.thread["thread_id"])
+ self.loop.widget.body.base_widget.set_focus(len(self.walker) - 1)
def back(self):
@@ -278,8 +310,7 @@ class App(object):
"Title", self.compose, extra_text=e.description)
self.set_header('Composing "{}"', title)
- self.set_footer(static_string=
- "[F1]Abort [Save and quit to submit your thread]")
+ self.set_footer("[F1]Abort [Save and quit to submit your thread]")
self.loop.widget = urwid.Overlay(
urwid.LineBox(
@@ -294,14 +325,14 @@ class App(object):
self.set_header('Replying to "{}"', self.thread["title"])
self.loop.widget.footer = urwid.Pile([
urwid.AttrMap(urwid.Text(""), "bar"),
- urwid.BoxAdapter(urwid.LineBox(editor("thread_reply", thread_id=self.thread["thread_id"])), 15),
+ urwid.BoxAdapter(urwid.LineBox(editor("thread_reply",
+ thread_id=self.thread["thread_id"])),
+ self.loop.screen_size[1] // 2),
])
self.switch_editor()
-
-
class MessageBody(urwid.Text):
pass
@@ -317,7 +348,7 @@ class FootPrompt(urwid.Edit):
if key != "enter":
return super(FootPrompt, self).keypress(size, key)
app.loop.widget.focus_position = "body"
- app.set_footer()
+ app.set_footer(app.bars[app.mode])
self.callback(self.get_edit_text(), *self.args)
@@ -580,20 +611,24 @@ def bbjrc(mode, **params):
values depending on `mode`.
"""
path = os.path.join(os.getenv("HOME"), ".bbjrc")
-
try:
+ # load it up
with open(path, "r") as _in:
values = json.load(_in)
+ # update it with new keys if necessary
+ for key, default_value in default_prefs.items():
+ if key not in values:
+ values[key] = default_value
+ # else make one
except FileNotFoundError:
values = default_prefs
- with open(path, "w") as _out:
- json.dump(values, _out)
- if mode == "load":
- return values
- values.update(params)
+ if mode == "update":
+ values.update(params)
+
with open(path, "w") as _out:
json.dump(values, _out)
+
return values
@@ -603,7 +638,7 @@ def main():
motherfucking_rainbows(obnoxious_logo)
print(welcome)
log_in()
- sleep(0.6) # let that confirmation message shine
+ sleep(0.8) # let that confirmation message shine
if __name__ == "__main__":
global app
Un proyecto texto-plano.xyz