• @mikael in my use case, I'm actually making a Gestures instance per-custom-widget. Since each of my widgets can have 2 or 3 gestures, it is simpler to just let each one have its own Gestures instance and install the various recognizers on each one. Gestures isn't particularly heavyweight, especially without the internal ui.Button instance, and then I don't need any global tracking of who has gestures installed, since when the widget goes away, it takes the gestures instance with it.

    Creating a little handler method in the gesture delegate class, which can be attached to a gesture recognizer is as simple as:

    ...existing gesture delegate definition... def handleGesture_(_self, _cmd, recognizer): import objc_util delegate = objc_util.ObjCInstance(_self) if not delegate: return recognizer = objc_util.ObjCInstance(recognizer) if not recognizer: return gestures = delegate._gestures() if not gestures: return gestures._handleGestureRecognizer(recognizer) methods = [... handleGesture_]

    Then, where you make the recognizers, instead of the whole button action thing, with all the associated bookkeeping:

    recognizer = \ objc_util.ObjCClass(recognizer_type).alloc() recognizer.initWithTarget_action_(self._delegate, objc_util.sel("handleGesture:")).autorelease() view.objc_instance.addGestureRecognizer_(recognizer)
  • @ccc I looked into using timeit to determine performance of all these changes but ultimately decided that performance was almost definitely not the problem my widget was encountering.

    Thank you for the dictionary approach anyway, it’s much more concise than I would’ve managed

  • @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.

  • Other ideas...

    import appex import requests import ui from objc_util import ObjCClass l = 0 device = ObjCClass('UIDevice').currentDevice() device.setBatteryMonitoringEnabled_(True) battery_percent = device.batteryLevel() * 100 device.setBatteryMonitoringEnabled_(False) off = True hum = 0 tem = 0 url = 'http://www.apple.com/#' # Added url definition # Do not worry about this, this changes my lights but will disable if I'm not # at home def button_tapped(sender): global l l += {'+': 10, '-': -10}.get(sender.name, 0) l = min(max(l, 0), 100) print('{}: {}'.format(l, requests.get(url + str(l)).text)) response = requests.get(url) tem = response.text if response.status_code == 200 else ' -- ' info = html = response.text def main(): label = ui.View(frame=(0, 0, 320, 64)) helv_15 = ('HelveticaNeue-Light', 15) # TEMPERATURE label.add_subview(ui.Label(frame=(1, 0, 100, 0), flex='wh', font=helv_15, text_color='white', alignment=ui.ALIGN_LEFT, text='Temperature:' + str(info)[3:7] + '°')) # HUMIDITY label.add_subview(ui.Label(frame=(1, 0, 150, 32), flex='wh', font=helv_15, text_color='white', alignment=ui.ALIGN_LEFT, text='Humidity:' + str(info)[11:13] + '%')) # LIVING ROOM LIGHTS monla_15 = ('Monla', 15) living_title = ui.Label(frame=(320 - 135, 0, 130, -20), flex='wh', font=monla_15, alignment=ui.ALIGN_RIGHT, text_color='white', text='Living Room Lights') # GREETING (WIP) greet = 'hi' # LIVING ROOM BUTTONS plus_btn = ui.Button(name='+', image=ui.Image('iow:ios7_plus_outline_32'), flex='hl', tint_color='#666', action=button_tapped) plus_btn.frame = (320 - 64, 0, 64, 64) minus_btn = ui.Button(name='-', image=ui.Image('iow:ios7_minus_outline_32'), flex='hl', tint_color='#666', action=button_tapped) minus_btn.frame = (320 - 64, 0, -64, 64) if tem != ' -- ': label.add_subview(minus_btn) label.add_subview(plus_btn) label.add_subview(living_title) else: # GREETING label.add_subview(ui.Label(frame=(320 - 135, 0, 130, -20), flex='wh', text_color='white', font=monla_15, alignment=ui.ALIGN_RIGHT, text=greet)) # BATTERY if battery_percent >= 85: img = 'full' elif battery_percent >= 50: img = 'half' elif battery_percent >= 30: img = 'low' else: img = 'empty' bat = ui.Button(name='batteryl', flex='hl', tint_color='#00d500', image=ui.Image('iow:battery_{}_24'.format(img)), action=button_tapped) bat.frame = (320 - 30, 64, 32, 32) label.add_subview(bat) # BACKGROUND COLOR label.background_color = '#1a1a1a' # SETS WIDGET appex.set_widget_view(label) if __name__ == '__main__': main()
  • You can't use sliders in Today widgets. As you've noticed, the system's gestures take precedence over your own controls.

  • 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.

  • @ccc , no I was not in any of the beta programs. I found the update worked from the updates page, although from the app's own page when an update is available the button changes from "open" to "update". I was not seeing that from the app's page itself. My only option was "open" and when I opened and went to the settings dialog in Pythonista 3 it clearly said 3.0 and not 3.1 (which it did display after updating from the updates page). Now I have the widget!

  • For reference, for anyone searching for this topic, why was this not done with corner_radius?

Internal error.

Oops! Looks like something went wrong!