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.


    Widget self-called refresh/animation

    Pythonista
    widget objcutil ui.view objc
    2
    3
    3547
    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.
    • RealTexasSwag
      RealTexasSwag last edited by

      Hi all, this is my first post, although I've been enjoying Pythonista for several years now. Wonderful app!

      Recently I've been working with the new Widget functionality. I'm currently trying to make a widget that represents the decibel sound level. I'm able to get this decibel information from an "AVAudioSession" using objc_util. My problem is displaying it.

      The below code works fine in the widget simulator (when it's run from the file, in-app), but only refreshes once in Today View. I have tried everything I can think of: wrapping it in a ui.View class, creating a custom draw method, calling set_needs_display, ... nothing works. I ran into this same problem when I tried to write a text-based snake game for the widget. Hopefully one of you will be able to figure out where I went wrong.

      (I say "self-called refresh" as opposed to being called by a touch or button--those seem to work fine. Perhaps the solution is to simulate a button press to refresh.)

      #!python3
      from objc_util import *
      import os, ui
      import appex
      import time
      
      def record():
        AVAudioSession = ObjCClass('AVAudioSession')
        NSURL = ObjCClass('NSURL')
        AVAudioRecorder = ObjCClass('AVAudioRecorder')
        shared_session = AVAudioSession.sharedInstance()
        category_set = shared_session.setCategory_error_(ns('AVAudioSessionCategoryPlayAndRecord'), None)
        settings = {ns('AVFormatIDKey'): ns(1633772320), ns('AVSampleRateKey'):ns(0.5), ns('AVNumberOfChannelsKey'):ns(1)}
        output_path = os.path.abspath('Recording.m4a')
        out_url = NSURL.fileURLWithPath_(ns(output_path))
        recorder = AVAudioRecorder.alloc().initWithURL_settings_error_(out_url, settings, None)
        recorder.record()
        recorder.setMeteringEnabled_(True)
        return recorder
      
      label = ui.Label()
      label.text = 'Please wait...'
      label.font = ('Menlo', 24)
      label.alignment = ui.ALIGN_CENTER
      label.text_color = 'red'
      appex.set_widget_view(label)
      recorder = record()
      while True:
        recorder.updateMeters()
        label.text = str(recorder.peakPowerForChannel_(0))[: 6] + ' dB'
        label.set_needs_display()
        time.sleep(.25)
      
      1 Reply Last reply Reply Quote 0
      • JonB
        JonB last edited by

        I suspect certain things don't happen until the script exits. You migt try using a ui.delay or threading.Thread rather than a while True loop in the main program flow.

        i.e

        def loop():
           # add an exit criteria
           if some_criteria:
               return
           ui.delay(loop, 0.25)
           # do stuff
        ui.delay(loop,0)
        
        1 Reply Last reply Reply Quote 1
        • RealTexasSwag
          RealTexasSwag last edited by

          Thanks for those suggestions, learning about threading was very helpful.

          Apparently, the while loop was working the whole time! I feel very silly now. It didn't appear to be working because it always updated the decibel level to be -120 (which is unusual because -160 is typically silence). It is my hypothesis that Apple restricts widgets in certain ways like recording (which is odd because I've used taptic feedback in a widget before). (Ex: the Shazam app has a widget, but it has to open the app to work.) Anyway, my new problem will be figuring out if it's possible to collect and analyze the recording elsewhere and pass that information to the widget through some sort of callback url.

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