Esempio n. 1
0
    def __init__(self, dir="./", work_mins=25, rest_mins=5):
        """default config file directory is current directory
       work time 25 min
       rest time 5 min
    """
        self._dir = dir
        self._work_mins = work_mins
        self._rest_mins = rest_mins

        # Two Models App deals with
        self.todos = None
        self.summary = None

        # platform dependeny notifier
        if platform == "darwin":
            self._nc = OSXNotifier()
        elif platform == "linux2":
            self._nc = UbuntuNotifier()
        else:
            self._nc = None

        self.init_ui()

        # ui style
        palette = [
            ("body", "dark blue", "", "standout"),
            ("footer", "light red", "", "black"),
            ("header", "light blue", "black"),
            ("select", "light red", "", "black"),
        ]

        # set main loop
        self.loop = urwid.MainLoop(self.frame, palette, unhandled_input=self.app_keypress)

        # Store alarm handles
        self._timer_handle = None
        # you don't break until you finish a task
        self._break = False
Esempio n. 2
0
class App:
    def __init__(self, dir="./", work_mins=25, rest_mins=5):
        """default config file directory is current directory
       work time 25 min
       rest time 5 min
    """
        self._dir = dir
        self._work_mins = work_mins
        self._rest_mins = rest_mins

        # Two Models App deals with
        self.todos = None
        self.summary = None

        # platform dependeny notifier
        if platform == "darwin":
            self._nc = OSXNotifier()
        elif platform == "linux2":
            self._nc = UbuntuNotifier()
        else:
            self._nc = None

        self.init_ui()

        # ui style
        palette = [
            ("body", "dark blue", "", "standout"),
            ("footer", "light red", "", "black"),
            ("header", "light blue", "black"),
            ("select", "light red", "", "black"),
        ]

        # set main loop
        self.loop = urwid.MainLoop(self.frame, palette, unhandled_input=self.app_keypress)

        # Store alarm handles
        self._timer_handle = None
        # you don't break until you finish a task
        self._break = False

    def init_logger(self):
        # init logger
        # TODO get name, instead of hardcode
        logger = logging.getLogger("tosu")
        # TODO path should be defined in cfg file
        hdlr = logging.FileHandler("./tosu.log")
        formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s")
        hdlr.setFormatter(formatter)
        logger.addHandler(hdlr)
        logger.setLevel(logging.DEBUG)

        logger.debug("init ok")

    def init_models(self):
        pass

    def init_ui(self):
        # reusable widges
        self.divider = urwid.Divider(u"-")

        # header
        header_text = u"Summary"
        self.header = urwid.AttrWrap(urwid.Text(u"Editing: %s\n" % header_text), "header")

        # footer_pile = footer + txt
        self.footer = urwid.Text(u"")
        self.txt = urwid.Text(u"")  # display
        self.footer_pile = urwid.AttrWrap(urwid.Pile([self.txt, self.footer]), "footer")

        # Summary
        # summary_fill can be frame.body, option 1
        # This will be created when first typed command ':s'

        # Todos
        # todo_fill can be frame.body, option 2
        self.todos = []
        self.todos_view = []

        # mode = 1, insert mode TODO costomize mode
        self.todo_edit = TodoEdit(caption=u"Todo:\n>>> ", multiline=False, mode=1, app=self)
        # TODO change this pile, need to change many parts
        self.todos_view.append(self.todo_edit)

        # Only todo data stored in pickle TODO move it
        self._pickle_file = os.path.join(self._dir, "tosu_data.pickle")

        # if data available
        if os.path.exists(self._pickle_file):
            self.todos = MyUnpickler(open(self._pickle_file)).load()

        # TODO why reverse?
        for obj in reversed(self.todos):
            # show undone todo item
            if obj._done == False:
                # create view for each todo instance
                new_view_item = urwid.AttrWrap(TodoItem(str(obj), data=obj), "body")
                self.todos_view.append(new_view_item)

        """ todos_view 
        1. todo_edit widget
        2. todo_item
        3. todo_item
        .
        .
        .
    """
        self.todo_pile = urwid.Pile(self.todos_view, focus_item=0)
        self.todo_fill = urwid.Filler(self.todo_pile, "top")

        # TODO chose which view to show first in cfg file, now show todo by default
        self.frame = urwid.AttrWrap(urwid.Frame(self.todo_fill, header=self.header, footer=self.footer_pile), "body")

        # used by TodoEdit in widgets.py
        self._todo_focus = 0  # focus todo_edit at first place

    def get_todo_focus(self):
        # used by TodoEdit in widgets.py
        # TODO this is same as todos_view.focus
        return self._todo_focus

    def set_todo_focus(self, i):
        # used by TodoEdit in widgets.py
        # TODO this is same as todos_view.focus
        self._todo_focus = i

    def run(self):
        self.todo = Todo(app=self, dirname=self._dir)
        self.header.set_text(self.todo.md_filepath)  # TODO change this title
        self.loop.run()

    def display(self, something):
        self.txt.set_text(u"Display: " + str(something))

    def app_keypress(self, key):
        # 1. Check Body = ?
        if self.frame.get_body() == self.todo_fill:
            target = self.todo_edit
            target_label = "todo"
        elif self.frame.get_body() == self.summary_fill:
            target = self.summary_pile.focus_item
            target_label = "summary"
        else:
            return

        if target == None:
            return key

        # 2. Handle
        if key == "esc":
            pass
        elif key == "tab" and target_label == "summary":
            # tab only works in summary mode
            cur = self.summary_pile.focus_position
            summary_pile_len = len(self.summary_pile.widget_list)

            if cur == summary_pile_len - 1:
                self.summary_pile.focus_position = 0
            else:
                self.summary_pile.focus_position = cur + 1

        elif key == "enter":
            command = target.key_buf[:-1]  # pop the 'enter' key
            target.key_buf = []
            # self.display(command)

            if last(2, command) == ":q":
                raise urwid.ExitMainLoop()

            if last(2, command) == ":w":
                self.update(target_label)
                self.save(target_label)

            if last(2, command) == ":x" or last(3, command) == ":wq":
                self.update(target_label)
                self.save(target_label)
                time.sleep(0.2)  # flash the message
                raise urwid.ExitMainLoop()

            if last(3, command) == ":to" or last(2, command) == ":t":
                self.update(target_label)
                self.save(target_label)
                self.frame.set_body(self.todo_fill)
                self.todo_edit.keypress = self.todo_edit.cmd_keypress

            if last(3, command) == ":su" or last(2, command) == ":s":
                self.update(target_label)
                self.save(target_label)

                summary_list = []

                for todo_obj in self.todos:
                    # Generate Summary views
                    if todo_obj._done:
                        # TODO load existing summary
                        summary_list.append(
                            ViEdit("* " + todo_obj.content + "\n", multiline=True, app=self, todo=todo_obj)
                        )
                if len(summary_list) == 0:
                    return

                self.summary_pile = urwid.Pile(summary_list)
                self.summary_fill = urwid.Filler(self.summary_pile, "top")
                self.frame.set_body(self.summary_fill)
                # self.summary_edit.keypress = self.summary_edit.cmd_keypress
        # End elif 'enter'

    # End func

    def update(self, target_label=None):
        if target_label == None:
            return
        elif target_label == "summary":
            for summary_view in self.summary_pile.widget_list:
                if summary_view.todo:
                    summary_view.todo._summary = summary_view.edit_text
        elif target_label == "todo":
            pass

    def save(self, target_label=None):
        if target_label == None:
            return
        elif target_label == "summary":
            f = open("test.json", "w")
            f.write("\n{[")
            f.write("\n".join([su.todo.to_json() for su in self.summary_pile.widget_list if su.todo]))
            f.write("\n]}")
            f.close()

        #      msg = self.summary.save_md()
        #      self.footer.set_text(u'Summary saved to: %s' % msg)

        elif target_label == "todo":
            self.footer.set_text(u"todo saved")

            #      for item in self.todos:
            #        item.view = None

            # TODO backup
            pickle.dump(self.todos, open(self._pickle_file, "wb"))

    def set_alarm(self):
        # Read mins from config file
        if not self._work_mins:
            sec = 25 * 60
        else:
            sec = self._work_mins * 60

        logger = logging.getLogger("tosu")

        # starting sound effect & notification
        # the dict is passed into callback: self.alarm
        play_sound("scifi_start.wav")
        if self._nc:
            self._nc.notify("A task have been started", title="todo-summary")

        self._m1 = sec * 1 / 3
        self._m2 = sec * 2 / 3
        self._timer_handle = self.loop.set_alarm_in(0, self.timer, sec)

        # TODO
        # 5. Add time, minuste time, move to next task

    def remove_clock_alarm(self):
        self.footer.set_text(u"Timer stopped.")
        self.loop.remove_alarm(self._timer_handle)
        self._timer_handle = None

    def clock_tick(self, time_left):
        # refresh display
        self.display(str(datetime.timedelta(seconds=time_left))[2:])

    def timer(self, loop, sec):
        # count down timer, it is a callback.
        # When called, it will register itself to be called after 1 sec.
        if sec == 0:
            self.clock_tick(sec)
            self._timer_handle = None

            if not self._break:
                # Start break timer
                cur = self.get_todo_focus()
                if cur != 0:
                    view = self.todo_pile.widget_list[cur]
                    view.update_time()

                if self._nc:
                    self._nc.notify("Time to break", title="todo-summary")
                # TODO make sound in cfg
                play_sound("horn.wav")
                self.footer.set_text("Coffee time...")

                self._m1 = None
                self._m2 = None
                self._break = True
                # Start break timer
                self._timer_handle = self.loop.set_alarm_in(1, self.timer, self._rest_mins * 60)
            else:
                # break stop
                # TODO play a different sound
                self._break = False
                if self._nc:
                    self._nc.notify("Break done", title="todo-summary")
                play_sound("paper.wav")

            logger = logging.getLogger("tosu")
            logger.debug("timer exit")
            return
        else:
            self.clock_tick(sec)

            # TODO make sound in cfg
            if sec == self._m1 or sec == self._m2:
                play_sound("paper.wav")

            logger = logging.getLogger("tosu")
            logger.debug("timer")
            # save handle for the newly set alarm in app
            self._timer_handle = self.loop.set_alarm_in(1, self.timer, sec - 1)