Little Mobile Lifesavers (i.e. Pull-to-refresh)

Sure this is old news to this awesome community, but this is a neat (and easy to implement) trick for dealing with mobile versions of Anvil Apps being used as PWAs saved to home screen.

Step 1:

Let’s make sure the app knows it’s being presented on mobile and as a PWA…

In your Startup form, import anvil.js and add this to your init:

self.is_pwa_on_mobile()

Then add your function:

def is_pwa_on_mobile(self,**kwargs):
    is_pwa = anvil.js.window.matchMedia("(display-mode: standalone)").matches
    is_mobile = anvil.js.window.navigator.userAgent.lower().find("mobi") > -1
    Globals.is_pwa = is_pwa
    Globals.is_mobile = is_mobile

Step 2:

In your Globals module (add one if you don’t have one) add:

is_pwa = False
is_mobile = False

Step 3:

In your form where you want to refresh things and normally use a poll timer (for the sake of example), import anvil.js.

In your init, get your content_panel’s dom node and set up some listeners and measuring tools:

    content_panel = anvil.js.get_dom_node(self.content_panel)
    content_panel.addEventListener('touchstart', self.on_touch_start)
    content_panel.addEventListener('touchmove', self.on_touch_move)
    content_panel.addEventListener('touchend', self.on_touch_end)

    self.touch_start_y = None
    self.touch_end_y = None

Also in your init, build in the check for whether it’s a mobile/PWA presentation of your app and turn off your poll timer if it is.

if Globals.is_pwa and Globals.is_mobile:
      self.timer_1.interval = None

Step 4:

Get ready to recycle your existing refresh_data() function (currently triggered by your poll timer), which could be anything, such as:

def refresh_data(self, **event_args):
    self.updatestuff_func()

Step 5:

Last step, add your touch event functions:

  def on_touch_start(self, event):
    self.touch_start_y = event.touches[0].clientY

  def on_touch_move(self, event):
    self.touch_end_y = event.touches[0].clientY

  def on_touch_end(self, event):
    if self.touch_start_y is not None and self.touch_end_y is not None:
      pull_distance = self.touch_end_y - self.touch_start_y
      if pull_distance > 50:
        self.refresh_data()
    self.touch_start_y = None
    self.touch_end_y = None

Recap:

  • You’ve added a check for whether your app is running on mobile AND as a PWA.

  • You’ve added touch event listeners which work out when a user pulls down and releases, rather than just touches or scrolls.

  • You’ve gotten rid of poll timers on the mobile version of your app, so expect less App Offline errors too.

And that’s it. Pull to refresh, no libraries or faff, just great mobile apps all built with Anvil.

12 Likes

First of all, Thank you very much! I didn’t know about some of these tips and will definitely use them.

This is great timing because I resolved some issues of mine and would like to share!

Prevent Polling When Application is in the background (Not Visible):

This always you to still have all your polls available, but make sure they are not called and raise the AppOfflineError when your appis in the background.

Raise FormShow() When Mobile Application is brought to the foreground:

I recently ran into an issue where my expectations did not match reality. The form_show event does not raise when the mobile device is brough back to the foreground. To resolve this, you can the following event handler:

window.addEventListener('visibilitychange',self.form_show)
Note this will call form_show when the application is hidden and shown, so you’ll have to check visibilty if you do not want it to be called on being put in the background (you can you the wrapper linked )
5 Likes

No problem and thank you, this is super useful for another problem I was having!!

1 Like