ugly hacks, pretty results

pull/4/head
Blake DeMarcy 2017-04-09 07:45:51 -05:00
parent 1b67057527
commit 3898f19f14
2 changed files with 60 additions and 36 deletions

View File

@ -1,9 +1,9 @@
# -*- fill-column: 72 -*- # -*- fill-column: 72 -*-
from time import time, sleep, localtime
from datetime import datetime
from network import BBJ, URLError from network import BBJ, URLError
from string import punctuation from string import punctuation
from datetime import datetime
from time import time, sleep
from subprocess import run from subprocess import run
from random import choice from random import choice
import tempfile import tempfile
@ -15,6 +15,7 @@ import os
try: try:
network = BBJ(host="127.0.0.1", port=7099) network = BBJ(host="127.0.0.1", port=7099)
except URLError as e: except URLError as e:
# print the connection error in red
exit("\033[0;31m%s\033[0m" % repr(e)) exit("\033[0;31m%s\033[0m" % repr(e))
@ -52,7 +53,9 @@ default_prefs = {
"editor": "vim", "editor": "vim",
"dramatic_exit": True, "dramatic_exit": True,
"date": "%Y/%m/%d", "date": "%Y/%m/%d",
"time": "%H:%M" "time": "%H:%M",
"frame_title": "> > T I L D E T O W N < <",
"max_text_width": 80
} }
@ -88,7 +91,7 @@ class App(object):
self.walker = urwid.SimpleFocusListWalker([]) self.walker = urwid.SimpleFocusListWalker([])
self.loop = urwid.MainLoop(urwid.Frame( self.loop = urwid.MainLoop(urwid.Frame(
urwid.LineBox(ActionBox(self.walker), urwid.LineBox(ActionBox(self.walker),
title="> > T I L D E T O W N < <", title=self.prefs["frame_title"],
tlcorner="@", trcorner="@", blcorner="@", brcorner="@", tlcorner="@", trcorner="@", blcorner="@", brcorner="@",
tline="=", bline="=", lline="|", rline="|" tline="=", bline="=", lline="|", rline="|"
)), colors) )), colors)
@ -102,10 +105,13 @@ class App(object):
then concat text with format_specs applied to it. Applies then concat text with format_specs applied to it. Applies
bar formatting to it. bar formatting to it.
""" """
self.loop.widget.header = urwid.AttrMap(urwid.Text( self.loop.widget.header = \
("%s@bbj | " % (network.user_name or "anonymous")) urwid.AttrMap(
+ text.format(*format_specs) urwid.Text(
), "bar") ("{}@bbj | " + text).format(
(network.user_name or "anonymous"),
*format_specs)),
"bar")
def set_footer(self, string): def set_footer(self, string):
@ -113,8 +119,7 @@ class App(object):
Sets the footer to display `string`, applying bar formatting. Sets the footer to display `string`, applying bar formatting.
Other than setting the color, `string` is shown verbatim. Other than setting the color, `string` is shown verbatim.
""" """
self.loop.widget.footer = \ self.loop.widget.footer = urwid.AttrMap(urwid.Text(string), "bar")
urwid.AttrMap(urwid.Text(string), "bar")
def close_editor(self): def close_editor(self):
@ -142,14 +147,22 @@ class App(object):
elif self.loop.widget.focus_position == "body": elif self.loop.widget.focus_position == "body":
self.loop.widget.focus_position = "footer" self.loop.widget.focus_position = "footer"
focus = "[focused on editor]" focus = "[focused on editor]"
attr = ("bar", "dim")
else: else:
self.loop.widget.focus_position = "body" self.loop.widget.focus_position = "body"
focus = "[focused on thread]" focus = "[focused on thread]"
attr = ("dim", "bar")
control = "[save/quit to send]" if self.prefs["editor"] else "[F3]Send" control = "[save/quit to send]" if self.prefs["editor"] else "[F3]Send"
self.loop.widget.footer[0].set_text( self.loop.widget.footer[0].set_text(
"[F1]Abort [F2]Swap %s %s" % (control, focus)) "[F1]Abort [F2]Swap %s %s" % (control, focus))
# this hideous and awful sinful horrid unspeakable shithack changes
# the color of the help line and editor border to reflect which
# object is currently in focus
self.loop.widget.footer.contents[1][0].original_widget.attr_map = \
self.loop.widget.footer.contents[0][0].attr_map = {None: attr[0]}
self.loop.widget.header.attr_map = {None: attr[1]}
def readable_delta(self, modified): def readable_delta(self, modified):
@ -172,27 +185,27 @@ class App(object):
def make_message_body(self, message): def make_message_body(self, message):
name = urwid.Text("~{}".format(self.usermap[message["author"]]["user_name"]))
info = "@ " + self.timestring(message["created"]) info = "@ " + self.timestring(message["created"])
if message["edited"]: if message["edited"]:
info += " [edited]" info += " [edited]"
name = urwid.Text("~{}".format(self.usermap[message["author"]]["user_name"]))
post = str(message["post_id"]) post = str(message["post_id"])
pile = urwid.Pile([ head = urwid.Columns([
urwid.Columns([ (2 + len(post), urwid.AttrMap(cute_button(">" + post), "button")),
(2 + len(post), urwid.AttrMap(urwid.Text(">" + post), "button")),
(len(name._text) + 1, (len(name._text) + 1,
urwid.AttrMap(name, str(self.usermap[message["author"]]["color"]))), urwid.AttrMap(name, str(self.usermap[message["author"]]["color"]))),
urwid.AttrMap(urwid.Text(info), "dim") urwid.AttrMap(urwid.Text(info), "dim")
]), ])
head.message = message
return [
head,
urwid.Divider(), urwid.Divider(),
MessageBody(message["body"]), MessageBody(message["body"]),
urwid.Divider(), urwid.Divider(),
urwid.AttrMap(urwid.Divider("-"), "dim") urwid.AttrMap(urwid.Divider("-"), "dim")
]) ]
pile.message = message
return pile
def timestring(self, epoch, mode="both"): def timestring(self, epoch, mode="both"):
@ -205,7 +218,7 @@ class App(object):
elif mode == "date": elif mode == "date":
directive = self.prefs["date"] directive = self.prefs["date"]
else: else:
directive = "%s %s" % (self.prefs["date"], self.prefs["time"]) directive = "%s %s" % ( self.prefs["time"], self.prefs["date"])
return date.strftime(directive) return date.strftime(directive)
@ -252,7 +265,7 @@ class App(object):
def thread_load(self, button, thread_id): def thread_load(self, button, thread_id):
""" """
Open a thread Open a thread.
""" """
if self.mode == "index": if self.mode == "index":
self.last_pos = self.loop.widget.body.base_widget.get_focus()[1] self.last_pos = self.loop.widget.body.base_widget.get_focus()[1]
@ -261,12 +274,14 @@ class App(object):
self.usermap.update(usermap) self.usermap.update(usermap)
self.thread = thread self.thread = thread
self.walker.clear() self.walker.clear()
self.set_header("~{}: {}",
usermap[thread["author"]]["user_name"], thread["title"])
self.set_footer(self.bars["thread"]) self.set_footer(self.bars["thread"])
for message in thread["messages"]:
self.walker.append(self.make_message_body(message))
self.set_header("~{}: {}",
usermap[thread["author"]]["user_name"],
thread["title"])
for message in thread["messages"]:
self.walker += self.make_message_body(message)
def refresh(self): def refresh(self):
@ -325,8 +340,16 @@ class App(object):
self.set_header('Replying to "{}"', self.thread["title"]) self.set_header('Replying to "{}"', self.thread["title"])
self.loop.widget.footer = urwid.Pile([ self.loop.widget.footer = urwid.Pile([
urwid.AttrMap(urwid.Text(""), "bar"), urwid.AttrMap(urwid.Text(""), "bar"),
urwid.BoxAdapter(urwid.LineBox(editor("thread_reply", urwid.BoxAdapter(
thread_id=self.thread["thread_id"])), urwid.AttrMap(
urwid.LineBox(
editor(
"thread_reply",
thread_id=self.thread["thread_id"]),
tlcorner="@", trcorner="@", blcorner="@", brcorner="@",
tline="-", bline="-", lline="|", rline="|"
),
"bar"),
self.loop.screen_size[1] // 2), self.loop.screen_size[1] // 2),
]) ])
self.switch_editor() self.switch_editor()
@ -395,6 +418,7 @@ class ExternalEditor(urwid.Terminal):
self.terminate() self.terminate()
app.close_editor() app.close_editor()
app.refresh() app.refresh()
# key == "f2"
app.switch_editor() app.switch_editor()
@ -548,8 +572,8 @@ def sane_value(key, prompt, positive=True, return_empty=False):
def log_in(): def log_in():
""" """
Handles login or registration using the oldschool input() Handles login or registration using an oldschool input()
method. The user is run through this before starting the chain. The user is run through this before starting the
curses app. curses app.
""" """
name = sane_value("user_name", "Username", return_empty=True) name = sane_value("user_name", "Username", return_empty=True)
@ -641,7 +665,7 @@ def main():
sleep(0.8) # let that confirmation message shine sleep(0.8) # let that confirmation message shine
if __name__ == "__main__": if __name__ == "__main__":
global app # global app
main() main()
app = App() app = App()
app.loop.run() app.loop.run()

View File

@ -2,9 +2,9 @@ from src import schema
def ordered_keys(subscriptable_object, *keys): def ordered_keys(subscriptable_object, *keys):
""" """
returns a list with the values for KEYS in the order KEYS are provided, returns a tuple with the values for KEYS in the order KEYS are provided,
from SUBSCRIPTABLE_OBJECT. Useful for working with dictionaries when from SUBSCRIPTABLE_OBJECT. Useful for working with dictionaries when
parameter ordering is important. Used for sql transactions parameter ordering is important. Used for sql transactions.
""" """
return tuple([subscriptable_object[key] for key in keys]) return tuple([subscriptable_object[key] for key in keys])
@ -12,7 +12,7 @@ def ordered_keys(subscriptable_object, *keys):
def schema_values(scheme, obj): def schema_values(scheme, obj):
""" """
Returns the values in the database order for a given Returns the values in the database order for a given
schema. Used for sql transactions schema. Used for sql transactions.
""" """
if scheme == "user": if scheme == "user":
return ordered_keys(obj, return ordered_keys(obj,