Navigation works!
This commit is contained in:
15
ui/auth.py
15
ui/auth.py
@@ -1,9 +1,12 @@
|
||||
import urwid
|
||||
|
||||
"""
|
||||
Input box that accepts OAuth tokens
|
||||
"""
|
||||
class TokenEdit(urwid.Edit):
|
||||
def __init__(self):
|
||||
urwid.register_signal(TokenEdit, 'TokenEdit-changed')
|
||||
prompt = ('seondary', u'Auth Token: ')
|
||||
prompt = ('seondary', u' Authorization Token: ')
|
||||
super(TokenEdit, self).__init__(prompt, '')
|
||||
|
||||
def keypress(self, size, key):
|
||||
@@ -18,12 +21,16 @@ class AuthPrompt(object):
|
||||
token_input = TokenEdit()
|
||||
urwid.connect_signal(token_input, 'TokenEdit-changed', self.callback)
|
||||
|
||||
self.frame = urwid.Filler(
|
||||
self.frame = urwid.Filler(urwid.Padding(
|
||||
urwid.Pile([
|
||||
urwid.Text('Visit %s and paste the token below.\n' % auth_url),
|
||||
token_input,
|
||||
])
|
||||
)
|
||||
]),
|
||||
align='center',
|
||||
width='pack',
|
||||
left=2,
|
||||
right=2
|
||||
))
|
||||
|
||||
def callback(self, token):
|
||||
self.callback(token)
|
||||
|
||||
@@ -2,10 +2,15 @@ palette = [
|
||||
('selected', 'standout', ''),
|
||||
('selected workspace', 'standout,bold', ''),
|
||||
('header', 'bold,light green', ''),
|
||||
('secondary', 'light gray', ''),
|
||||
('secondary', 'light green', ''),
|
||||
('task', 'light green', ''),
|
||||
('project', 'yellow', ''),
|
||||
('section', 'white', 'dark green'),
|
||||
('section', 'dark green,bold', ''),
|
||||
('atm_section', 'white,bold', 'dark blue'),
|
||||
('workspace', 'white', 'dark blue'),
|
||||
('pager', 'standout', ''),
|
||||
]
|
||||
|
||||
keys = {
|
||||
'select': ['enter', 'space']
|
||||
}
|
||||
62
ui/task_details.py
Normal file
62
ui/task_details.py
Normal file
@@ -0,0 +1,62 @@
|
||||
import urwid
|
||||
|
||||
class TaskDetails(object):
|
||||
def __init__(self, task, stories, on_subtask_click, on_project_click,
|
||||
on_comment):
|
||||
self.task = task
|
||||
self.on_subtask_click = on_subtask_click,
|
||||
self.on_project_click = on_project_click,
|
||||
self.on_comment = on_comment
|
||||
|
||||
self.details = urwid.Pile([
|
||||
('pack', urwid.Text(('task', task.name()))),
|
||||
('pack', urwid.Divider('-')),
|
||||
('weight', 1, Memberships(task, on_subtask_click, on_project_click) \
|
||||
.component()),
|
||||
('pack', urwid.Divider('-')),
|
||||
('pack', CustomFields(task).component()),
|
||||
('pack', urwid.Divider('-')),
|
||||
('weight', 20, urwid.Filler(urwid.Text(task.description()))),
|
||||
('weight', 5, urwid.Filler(Stories(stories).component()))
|
||||
])
|
||||
|
||||
def component(self):
|
||||
return self.details
|
||||
|
||||
class Memberships(object):
|
||||
def __init__(self, task, on_subtask_click, on_project_click):
|
||||
components = [urwid.Button(
|
||||
('project', p.name()),
|
||||
on_press = lambda x: on_project_click(p.id())
|
||||
) for p in task.projects()]
|
||||
if task.parent():
|
||||
components.append(urwid.Button(
|
||||
('task', 'Subtask of: %s' % task.parent().name()),
|
||||
on_press = lambda x: on_subtask_click(task.parent().id())
|
||||
))
|
||||
|
||||
self.memberships = urwid.ListBox(
|
||||
urwid.SimpleFocusListWalker(components)
|
||||
)
|
||||
|
||||
def component(self):
|
||||
return self.memberships
|
||||
|
||||
class CustomFields(object):
|
||||
def __init__(self, task):
|
||||
components = [urwid.Text('%s: %s' % (f.name(), f.string_value()))
|
||||
for f in task.custom_fields()]
|
||||
|
||||
self.custom_fields = urwid.Pile(components)
|
||||
|
||||
def component(self):
|
||||
return self.custom_fields
|
||||
|
||||
class Stories(object):
|
||||
def __init__(self, stories):
|
||||
components = [urwid.Text(s.string_value()) for s in stories]
|
||||
|
||||
self.stories = urwid.Pile(components)
|
||||
|
||||
def component(self):
|
||||
return self.stories
|
||||
63
ui/task_list.py
Normal file
63
ui/task_list.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import urwid
|
||||
|
||||
from ui.constants import keys
|
||||
|
||||
class TaskList(object):
|
||||
def __init__(self, tasks, header, on_task_click):
|
||||
self.callback = on_task_click
|
||||
self.grid = urwid.Frame(
|
||||
urwid.ListBox(
|
||||
urwid.SimpleFocusListWalker(
|
||||
[TaskRow(t, self.on_task_clicked) for t in tasks]
|
||||
)
|
||||
),
|
||||
header=urwid.Text(header),
|
||||
focus_part='body'
|
||||
)
|
||||
|
||||
def on_task_clicked(self, id):
|
||||
self.callback(id)
|
||||
|
||||
def component(self):
|
||||
return self.grid
|
||||
|
||||
class MyTasks(object):
|
||||
def __init__(self, tasks, on_task_click):
|
||||
all_tasks = [t for t in tasks]
|
||||
|
||||
today = [t for t in all_tasks if t.atm_section() == 'today']
|
||||
upcoming = [t for t in all_tasks if t.atm_section() == 'upcoming']
|
||||
later = [t for t in all_tasks if t.atm_section() == 'later']
|
||||
|
||||
self.today_grid = TaskList(today,
|
||||
('atm_section', 'Today'),
|
||||
on_task_click)
|
||||
self.upcoming_grid = TaskList(upcoming,
|
||||
('atm_section', 'Upcoming'),
|
||||
on_task_click)
|
||||
self.later_grid = TaskList(later,
|
||||
('atm_section', 'Later'),
|
||||
on_task_click)
|
||||
|
||||
def component(self):
|
||||
return urwid.Frame(urwid.Pile([
|
||||
self.today_grid.component(),
|
||||
self.upcoming_grid.component(),
|
||||
self.later_grid.component()
|
||||
]),
|
||||
header=urwid.Text(('header', 'My Tasks')),
|
||||
focus_part='body'
|
||||
)
|
||||
|
||||
class TaskRow(urwid.SelectableIcon):
|
||||
def __init__(self, task, on_click):
|
||||
self.on_click = on_click
|
||||
self.task = task
|
||||
style = 'section' if task.name()[-1] == ':' else 'task'
|
||||
super(TaskRow, self).__init__((style, task.name()))
|
||||
|
||||
def keypress(self, size, key):
|
||||
if key in keys['select']:
|
||||
self.on_click(self.task.id())
|
||||
else:
|
||||
return key
|
||||
72
ui/ui.py
Normal file
72
ui/ui.py
Normal file
@@ -0,0 +1,72 @@
|
||||
import urwid
|
||||
from threading import Thread
|
||||
|
||||
from asana_service import AsanaService
|
||||
|
||||
from ui.task_list import MyTasks, TaskList
|
||||
from ui.task_details import TaskDetails
|
||||
|
||||
class Ui(object):
|
||||
nav_stack = []
|
||||
def __init__(self, asana_service, update):
|
||||
self.asana_service = asana_service
|
||||
self.update = update
|
||||
|
||||
def my_tasks(self):
|
||||
self.nav_stack.append(('mytasks', None))
|
||||
|
||||
def runInThread():
|
||||
tasks = self.asana_service.get_my_tasks()
|
||||
self.update(MyTasks(tasks, self.task_details).component())
|
||||
|
||||
thread = Thread(target=runInThread())
|
||||
thread.start()
|
||||
|
||||
|
||||
def task_details(self, id):
|
||||
self.nav_stack.append(('task', id))
|
||||
def runInThread():
|
||||
task = self.asana_service.get_task(id)
|
||||
stories = self.asana_service.get_stories(id)
|
||||
self.update(TaskDetails(task,
|
||||
stories,
|
||||
self.task_details,
|
||||
self.task_list,
|
||||
None).component())
|
||||
thread = Thread(target=runInThread())
|
||||
thread.start()
|
||||
|
||||
def task_list(self, id):
|
||||
self.nav_stack.append(('project', id))
|
||||
def runInThread():
|
||||
tasks = self.asana_service.get_tasks(id)
|
||||
self.update(TaskList(tasks,
|
||||
'TODO: get project name',
|
||||
self.task_details
|
||||
).component())
|
||||
thread = Thread(target=runInThread())
|
||||
thread.run()
|
||||
|
||||
def go_back(self):
|
||||
if len(self.nav_stack) < 2:
|
||||
return
|
||||
|
||||
self.nav_stack.pop()
|
||||
(location, id) = self.nav_stack.pop()
|
||||
if location == 'mytasks':
|
||||
self.my_tasks()
|
||||
elif location == 'task':
|
||||
self.task_details(id)
|
||||
elif location == 'project':
|
||||
self.task_list(id)
|
||||
|
||||
|
||||
def loading():
|
||||
return urwid.Overlay(
|
||||
urwid.BigText('Loading...', urwid.font.HalfBlock5x4Font()),
|
||||
urwid.SolidFill('#'),
|
||||
'center',
|
||||
'pack',
|
||||
'middle',
|
||||
'pack'
|
||||
)
|
||||
Reference in New Issue
Block a user