omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    Today Widget - Just some comments

    Pythonista
    widget today
    3
    7
    5391
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Phuket2
      Phuket2 last edited by

      Sorry if this has been covered before.
      But I tried to use the Today Widget, today (I have tried before, but long time ago). Anyway, I was suprised about what I could do.
      I was able to load a CustomView using @JonB PYUILoader (loading a pyui file into a Custom Class) , I was able to use the update method in the custom class to update a timer value. Interact with a database (a single call for now).

      Anyway, it all just works. Well execpt for the bg_color. The way I am doing it, I end up with a white bg_color. I tried setting the bg_color = None, that does not work. I will have to find out how to do that.

      but the below code is not runable on anothers device, I just wanted to start something and see if things like update method would work.
      I am not sure if different devices get more memory to run today widgets or not.
      So the below code is not meant to be smart/polished. Just wanted to see if it would work.

      #!python3
      
      import appex
      import ui
      import arrow
      from tinydb import TinyDB, where
      
      
      class PYUILoader(ui.View):
          # this acts as a normal Custom ui.View class
          # the root view of the class is the pyui file read in
          def WrapInstance(obj):
              class Wrapper(obj.__class__):
                  def __new__(cls):
                      return obj
              return Wrapper
      
          def __init__(self, pyui_fn, *args, **kwargs):
              bindings = globals().copy()
              bindings[self.__class__.__name__] = self.WrapInstance()
      
              ui.load_view(pyui_fn, bindings)
      
              # call after so our kwargs modify attrs
              super().__init__(*args, **kwargs)
      
      
      def GetTimerFinished(db_fn, timer_name):
          with TinyDB(db_fn) as db:
              rec = db.search(where('timer_name') == timer_name)
              return rec[0]
      
      
      def SetTimerFinished(db_fn, timer_name, days=0, hours=0, minutes=0):
          utc = arrow.utcnow()
          finish_time = utc.shift(days=+days, hours=+hours, minutes=+minutes)
          rec = dict(timer_name=timer_name,
                     entered=utc.for_json(),
                     finish_time=finish_time.for_json(),
                     elapased=False,
                     )
          with TinyDB(db_fn) as db:
              db.upsert(rec, where('timer_name') == rec['timer_name'])
              return rec
      
      
      class AppexTestClass(PYUILoader):
          def __init__(self, pyui_fn, db_fn, timer_name, *args, **kwargs):
              super().__init__(pyui_fn, *args, **kwargs)
              #self.bg_color = None
              self.db_fn = db_fn
              self.timer_name = timer_name
              self.local_finish_time = 0
              rec = GetTimerFinished(db_fn, self.timer_name)
      
              self.update_interval = 1
              self.count = 0
              self.expired = False
              self.calc_time()
              self['f_timer_name'].text = rec['timer_name']
      
          def calc_time(self):
              timer_rec = GetTimerFinished(self.db_fn, self.timer_name)
              self.timer_name = timer_rec['timer_name']
              utc = arrow.get(timer_rec['finish_time'])
              local_finish_time = utc.to('Asia/Bangkok')
              self.local_finish_time = local_finish_time
      
              if self.local_finish_time < arrow.now():
                  self.expired = True
      
          def time_remaining(self):
              return self.local_finish_time - arrow.now()
      
          def update(self):
              if self.expired:
                  self['f_time_left'].text = 'Expired'
                  return
              self['f_time_left'].text =\
                  self.format_timedelta(self.local_finish_time - arrow.now())
      
          def format_timedelta(self, td):
              hours, remainder = divmod(td.total_seconds(), 3600)
              minutes, seconds = divmod(remainder, 60)
              hours, minutes, seconds = int(hours), int(minutes), int(seconds)
              if hours < 10:
                  hours = '0%s' % int(hours)
              if minutes < 10:
                  minutes = '0%s' % minutes
              if seconds < 10:
                  seconds = '0%s' % seconds
              return '%s:%s:%s' % (hours, minutes, seconds)
      
      
      def main():
          db_fn = 'my_timers.json'
          pyui_fn = 'appex_test_ui.pyui'
          timer_name = 'Wonder Wars'
          #SetTimerFinished(db_fn, timer_name, hours=5, minutes=35 )
          v = AppexTestClass(pyui_fn, db_fn, timer_name)
          appex.set_widget_view(v)
      
      
      if __name__ == '__main__':
          main()
      

      Screen shot

      1 Reply Last reply Reply Quote 0
      • ccc
        ccc last edited by

            def format_timedelta(self, td):
                hours, remainder = divmod(td.total_seconds(), 3600)
                minutes, seconds = divmod(remainder, 60)
                return '%02.0f:%02.0f:%02.0f' % (hours, minutes, seconds)
        
        Phuket2 1 Reply Last reply Reply Quote 1
        • Phuket2
          Phuket2 @ccc last edited by

          @ccc , thanks. Actually I just copied that code from Stackflow. I hadn't realised before that there is no built formatting for TimeDelta objects. The method posted is also good enough as its limited to by hours. I got another code snippet off ActiveCode that handles Weeks all the way down to microsecond's if you need it. The code is here.
          I am still looking at the arrow docs to see if it has support to format TimeDelta objects. As far as I see it doesn't. When you do a calculation operation in arrow, you are returned a TimeDelta object, not an arrow object. Just for fun, I will look at Maya to see if it supports it. Would not make me swap if it did though because arrow ships with Pythonista. Oh, arrow has the humanise method, not the same but still handy.

          I went through the code above more closely and see I had quite a few mistakes I fixed up. Mainly the way I built it up. Wasn't sure what would work. I am suprised it works. Using the PYUILoader and update functions etc... But I guess its a nice testament to how well things are put together in Pythonista.

          The other thing that I was able to do was add a table to the view. I didn't try interacting with it. Just added a TableView on in the Designer. I think this maybe getting to the edge though, as I often got 'Unable to Load' message in the Today view. I didn't realise at first, but that message is a button. If you tap it the view loads.

          Screen Shot of TableView in Today widget. Maybe this is no news for a lot of people. I am not sure I have seen a scrolling table in a Today Widget before (I mean from an company).

          1 Reply Last reply Reply Quote 0
          • chriswilson
            chriswilson last edited by

            @Phuket2

            Regarding the clear background thing: I’ve just started playing with the Today Widget as well and I used this code to load a standard PYUI file (as might be done for a normal script). It also sets a clear background. I hope it’s helpful!

            v = ui.load_view()
            v.background_color = ui.set_color("clear")
            appex.set_widget_view(v)
            
            Phuket2 1 Reply Last reply Reply Quote 0
            • Phuket2
              Phuket2 @chriswilson last edited by

              @chriswilson , thanks for the reply. However, I am not sure "clear" is actually recognised as a legitimate param (if its a css name then it would be), but calling ui.set_color(x) if x is not recognised it will set the bg_color to (0.0, 0.0, 0.0, 0.0) regardless - tuple of RGBA. Eg. You could call ui.set_color(None) or ui.set_color("Hey_Jude") and it will still return (0.0, 0.0, 0.0, 0.0).

              Again, maybe "clear" is recognised, but maybe its not, and the default behaviour for an un-recognised param is being returned

              1 Reply Last reply Reply Quote 0
              • chriswilson
                chriswilson last edited by

                @Phuket2

                Ah I see. Good to know. I tried this and it got me a nice transparent background to my widget, but of course setting alpha to zero would do the same thing!

                I was basing this on the Swift iOS colours (UIColor class which has a UIColor.clear) rather than CSS. I’m not sure if this is what is going on behind the scenes of the UI module though.

                Phuket2 1 Reply Last reply Reply Quote 0
                • Phuket2
                  Phuket2 @chriswilson last edited by

                  @chriswilson, I just looked up the css colours and there is no 'clear' defined. It makes sense as its only RGB. But it still could have been an alias representation, you never know :)
                  css colors
                  But as you say its still good to find out.

                  1 Reply Last reply Reply Quote 0
                  • First post
                    Last post
                  Powered by NodeBB Forums | Contributors