Shopping list app for Mealie
Changes README discusses Forage and Forage2 (working title) development
Added tag v1.2.0 for changeset 3902465813c7
Updates to newer Fyne, and polishes the edit function.

heads

tip
browse log
v1.2.0
browse .tar.gz

clone

read-only
https://hg.sr.ht/~ser/forage
read/write
ssh://hg@hg.sr.ht/~ser/forage

#forage

#V0 Warning

This application was build against the Mealie v0 API. This version of Mealie is no longer being developed, work having shifted to Mealie v1. The Mealie v1 API is vastly different and incompatible with v0. Consequently, this version of Forage is being frozen, and I've stopped work on it. In other environments I'd just release a new app version under the same name with some backwards compatibility, but because of several challenges[^1] and the target platform -- mobile -- where size matters, I'm planning on releasing a rewritten app under a different name that's compatible only with Mealie v1.

Forage2 is in early stages; because downstream packagers depend on source locations not moving, there'll have to be some restructuring; the project README will point you in the right direction if you're looking for source info on the rebuild.

#And now for something completely different

A shopping list front-end for your (self-hosted) Mealie instance.

Build statusReleasesBugs

Mealie is self-hosted recipe manager, meal planner, and shopping list web app. Forage is an application aimed to improve the shopping list experience of Mealie by providing a native (non-web) interface via the Mealie API.

With the release of Forage v1, Forage can work entirely in offline mode without a server. Without a server, it functions as a non-connected shopping list app, albeit currently limited in editing.

There is a public chat available at #forage:matrix.org.

#Features & screenshots

Forage connects to your Mealie instance and shows you a list of all of your shopping lists. When you select one, it shows you the shopping list, which you can then check items off or add items to. Changes are sync'd back to your Mealie server.

  • Runs on Linux, Android, Darwin, Windows, iOS, and FreeBSD (builds are provided for the first four)
  • Native interface, not a repackaged web framework like PhoneGap.
  • Selection & creation of lists
  • Adding & completing (checking) items off a list
  • Stays logged in
  • Battery-friendly
  • Concurrent list edit support (list change merging). Forage was designed to be used by multiple users concurrently, and will merge edits done while offline, and update when things change on the server side. It was designed, in fact, to be used by a shopper while someone else might still be adding or changing items.
  • Lists are sorted, with unchecked items at the top, and then lexically ignoring any initial units. E.g., "6 apples" will sort before "Banana" or "1 avocado".
  • If Forage can't connect to your server to save changes, it retries occasionally until it can. Unless you exit Forage before the changes are saved, it will eventually succeed.
  • Offline caching. Forage will persist data to the phone and still work in offline mode.
  • Lists can be "purged", such that checked items are deleted from the list.
  • Forage can be set to "offline," to prevent list changes, or when network connection is particularly sketchy. This can make it behave better when, e.g., Android puts the app into the background.

#Caveats

  • Forage is built with Go and Fyne. Executables on desktop are 12MB, and Android APKs are 80MB. IMO this is pretty huge, but it's the price of the tooling.
  • Fyne is like Swing: widgets and interactions are bespoke, not calls down to the underlying windowing widget GUI. You won't see a native-looking UI.
  • There are occasional crashes; it's nothing spectacular, just the application exits. It's rare enough to be difficult to track down, and so far I haven't seen any data loss as a result.

That said, it's not (IMO) ugly, and Fyne is surprisingly light on the battery. I haven't seen it yet near the top of battery use on my phone, or at the top of top on my laptop.

#How to...

#... use it

Enter your Mealie server URL and login credentials (user name & password). You can also create a token through the Mealie web UI and put that in for the password; in this case, leave the user name blank. Forage only uses user credentials to fetch a token.

Once logged in, you'll be presented with a list of all of the shopping lists defined on the server. Choose one of those, and you'll see a list of all shopping items in the list. You can check them off or add new items to the list; these changes are saved back to the server. If you want to change shopping lists, use the tab at the top to go back to the list-of-lists tab. You can change your server by going back to the Server tab.

Long-press (or right-click) an item to edit it in the edit widget (at the top). Press Enter to make the change, or click/touch elsewhere outside the widget to cancel.

Forage can not do many of the things Mealie can, although it can do most of the things you can do with shopping lists, and it can do a couple of things that can't be done in the Mealie web UI.

#... get it

  • Builds for Android are submitted to F-Droid.
  • Binaries for Linux, Android, Mac, and Windows are provided here. Packages are signed with my (published) public key, and are compressed with zstd (you'll need to uncompress them after downloading). Submit a ticket if you'd like me to add other architectures; there are a lot of possible permutations, so I'm only adding them as requested.
  • You can review the code and build it yourself if you'd like

I'm still figuring out how to compile for iOS on the automated build server. Apple does not make it easy.

My signing key is signed with my more venerable -- and more heavily validated -- personal key.

#... build it

The technologies aren't important, except when they are. Forage's UI is provided by Fyne, a cross-platform GUI toolkit for Go. As such, it does not provide a "native" experience, on any platform. OTOH, it doesn't look bad, and it allows compiling apps that work on Windows, Linux, Mac, iOS, and Android.

This may be your best bet, short-term, for getting an iOS build.

In any case, you need Go 1.17 or later. It may work with an earlier version. Once you check out the sourcecode, it should build with:

go build .

If you want to build an Android APK, make sure you have the Android NDK and Fyne installed. Installation for Android will vary with your OS/Distribution; on Arch, it's:

pacman -S android-ndk

And Fyne can be installed with:

go install fyne.io/fyne/v2/cmd/fyne@latest

Then call:

fyne package -os android

The icon is stored in the repo as SVG and needs to be converted to PNG before being used.

For iOS, you need to additionally have XCode installed, but you should then be able to run:

fyne package -os ios

This is untested as I don't have access to a modern Mac.

Finally, move the package to your device and install it. I recommend Wormhole William (Android). For example, I do this on my laptop to move the APK over to my phone:

wormhole-william send --qr Forage.apk

#... contribute

I'm happy to review pull requests.

While I've set up the tracker for public requests, for my own purposes I used Legume to track bugs and todos. If you'd like to see what's on my mind, run leg in a check-out of the source.

There's a mock Mealie server in test/cmd. Run it with go run ./test/cmd; it listens on localhost:9999 and starts with a couple of lists, persisting changes to memory. Authentication is utterly missing, so you can't test that; in fact, if you supply a username/password combo, the Go OAuth2 library will fail, so put a value only in the password field. It doesn't matter what. The code used by this mock server is also used by the unit tests, exercised by go test ..

There's a command-line argument you can provide to mess with the batching time. Batching defaults to 30 seconds, and you can override it with the -T argument, which is in milliseconds. Set it to 0 and you'll disable the buffering. This is what the unit tests do.

#... testing

A dummy server that provides the shopping-list API from Mealie is included in test/cmd. If you run go run ./test/cmd, it'll start up a test server on 127.0.0.1:9999 prepopulated with data in test/lists. Run Forage and point it to localhost:9999 and you can play around with Forage without connecting to a real Mealie instance. Changes are stored in memory and are lost when you kill the server. If you're handy with Android's development environment, you can use this to run Forage in an emulator instance and connect to the test server at 10.0.2.2:9999.

#... get Mealie

Setting up your own Mealie server is beyond the scope of this README; I'm not directly associated with the project. However, I found it very easy to run using podman:

sudo mkdir /var/db/mealie
sudo chown $USER:$USER /var/db/mealie
sudo chmod ug+s /var/db/mealie
podman create --name=mealie -e TZ=America/Chicago -p 9284:80 \
   -v /var/db/mealie:/app/data --restart unless-stopped \
      docker.io/hkotel/mealie:latest
podman start mealie

I then proxied from Caddy to 9284. YMMV, so I'd recommend following instructions on Mealie's site.

[^1] The Mealie v1 API is in no way backwards compatible; it's about as different an API as could possibly be. In most ways, it's an improvement on v0, which was too simple and caused challenges for clients. On the other hand, it was quite simple, and easy to write clients against. The new API follows better practices, and especially for clients such as Forage, but it is also more complex; data structures have more depth, there's paging to deal with, the data is more rich, and the types of fields have changed.

It's so different, my attempts to adapt Forage to support both v0 and v1 failed. It might have been possible to shove v0 objects into a v1 structure, but the field type changes and introduction of enumerables really set any backwards compatibility effort up for failure. Possibly a greater challenge is that Fyne tightly couples the view to the model, to the point of including its own database and filesystem. While there may be good reasons for this, it makes attempts to support multiple conflicting data models nearly impossible, and even changing a Fyne app to use a new data model is a large effort. Fyne quickly evolved from a library to a platform, and I have strong opinions about platforms, re-enforced by experiences such as this.