mo-nomz's People
mo-nomz's Issues
Edit/Merge behavior
When adding or removing new items (link/blob/list), existing edits and merges are forgotten.
- When adding, don't refresh the list just update it.
- When removing, remove all items in that recipe
- Warn when merging that if you delete or deactivate a recipe it'll delete merged items if they're in the deleted recipe. To avoid this don't merge until you're done.
UX/UI feedback
- Make circle selection buttons bigger
- Don't know what the
+
sign means when adding new ingredients - Clicking "save" on add new ingredients page doesn't use the in-progress ingredients
- Icons are weird for adding
- The link should be a plus
- The clipboard should be a pencil
- The plus should be a ???
- "Save" is a weird word
- When adding new ingredients, make the picker taller so that you can see the other options
- Make all the pickers the same height
- When adding a blob, tell people they can add multiple
- Instead of having two buttons for adding items, have one button and a toggle for structured/unstructured input
- In structured input, ingredient before unit
- Export should prepend a title
- Reordering drag and drop
Keyboard notification acts strangely for add link
Input views don't scroll
When entering bulk or individual items, list gets too long
Parsing produces weird symbols
Need an example
Structured ingredient input
Be able to input an ingredient at a time with structured input instead of pasting. User should be able to submit multiple at once. Get rid of the pasting view entirely.
Ingredients outside of a recipe
Ability to add ingredients that are not tied to a recipe, and which live in the grocery list.
UI Feedback
- Deleting a recipe doesn't delete from the grocery list
- Better icon for "bulk remove"
- Weird symbols in recipe/ingredient list after parsing - see #16
- Keyboard goes over text input so you can't see it
- Word wrap on recipe titles
Manual items fixup
It's kind of confusing as is right now
Better backend scraping and parsing
Better backend scraping and parsing which will scrape more fields from the HTML and eagerly parse. Refactor parser types. Add tests.
- Add a bunch of links
- Paste
- Link -> export -> paste?
- Platform detection instead of probability based
Sharing bugs
- Safari doesn't work - you can share, but does not make API call
- Notes doesn't work - you can't share
Group ingredients
A way to group ingredients so that you can add them to the list together
Check for duplicated recipe links
When adding a recipe link, check to make sure there's not already one that matches.
Do this on the backend and just set the existing one to active.
V2 improvements
- App name doesn't match the art
- Add better keywords
- Remove lines between rows in list view
- Landing page in app for marketing
- Move privacy policy and support page over to static HTML
Edit, delete, and merge recipe ingredients
Release the app
- Heroku uptime - Hobby ($7/month)
- Test on all different size simulators and portrait/landscape mode
- Promotional materials like screenshots for the App Store
- Run the test plan
- Pull the trigger
Add back merge
- Dedicated database actions (like Database.hs)
- Automerge
- Unmerge
- Merge on purpose
- Dismissable merge tip
- Fix existing actions
Better error messages
For parsing and elsewhere in the app when there's no connectivity
Enable iPad
Ability to reorder items arbitrarily
Use categories, predefined
Bug report
- Export is not ordered correctly
- Automerge is not working correctly
- Create recipe blob is not dismissing window and reloading
- Reorder broken
- Cancel after selecting item keeps it selected
- Top margin when keyboard shows
- Manual add opacity change
Hard to reorder
Button is too close to the scroll bar
Investigate embedded browser
Maybe a button to open a browser view
Drag and drop reorder on arrows
Decide on pricing scheme
A few options:
- Sell it for $1 or $2
- Link to venmo/square/patreon
- In app purchases which is just a "thank you"
- In app purchases which guard a feature
Decide on one and then do it
Metric conversion table
Clicking on a saved for later recipe crashes the app
Write blog post on the experience of creating an app
Nomz
I created the iOS app Nomz (link to it). The app functions as a meal planner. You add links to recipes; the backend parses the ingredient list and adds them to a grocery list. You can also add freeform groceries to your list, say if you know you need eggs or milk. It integrates with other apps like Reminders, Notes, and Safari. You can save recipes for later if you want to make them at some point in the future.
For years, I've been interested in the idea of passive income and financial independence. I don't want to retire early, but rather have the freedom to pursue interests irrespective of being tied to a tech salary. I decided to create an app to see what the challenges would be. The point would not to make money, though a requirement was that the app would be able to generate revenue. My goal was research, with the hope that down the line I could set up a few modest income sources based off of apps.
My fiancee at the time (now wife) came up with the idea. We used to grocery shop by going down each aisle and buying whatever looked good. The result was a large bill and lots of wasted food. A few months ago, we switched to planning our meals using recipes we wanted to cook and buying the ingredients for 4 or 5 of them per week depending on how many times we wanted to get take out. Our spending instantly fell 25%, we stopped wasting as much food, and we started eating healthier. The biggest issue was that my wife was finding recipe links online and transcribing the ingredients to a grocery list by hand. She saved the links in a note on her phone.
Naturally, when I asked my wife what she wanted in an app, she had a very clear idea.
I started Easter weekend, working nights and weekends for 6 weeks until I got to the point at which I had a working prototype. I had 5 testers, the most important being my wife who, every week, would download the most recent version, add the recipes we planned to make that week, and then provide the feedback which I worked on addressing the next week. This continued 6 weeks until my wife decided that all her needs were addressed. The following are the features we decided on.
Features
- Parse an ingredient list from a recipe link
- Supply freeform groceries
- Merge two groceries together
- "Auto merge" groceries with the same name
- Merge groceries manually (say, "cubed butter" and "butter" on its own)
- Reordering items
- Allow users to group groceries based on where they are in the store
- Save recipes for later
- Mark groceries as bought
- Allow users to re-add them to the list later if desired
- Export to other apps
- Notes, Reminders, copy to clipboard, etc
- Import from other apps
- Links from Safari, freeform text from Notes, etc
- Clear the list
- Delete freeform groceries and save all recipes for later
- Revenue generation
- Pay for the app, provide ads, or use the "freemium" model
Takeaways
Cost
To date, I've spent $100 on the apple developer license for 1 year, and $7 per month (1 month in) on the lowest paid Heroku tier (what is its name). If the app gets popular it's possible I'll have to start paying $25 per month for additional instances. I used the one free private repository afforded to my GitHub account.
Effort
I underestimated how much effort it would take. That's coming from a software developer with years of experience! In truth, I did correctly estimate how much time it would take to make a proof of concept (about 2 weeks), but I didn't understand how much iteration would be needed. The app is exceedingly simple, and I can't really think of any way to make it simpler, but getting it into its simplistic state took a lot of time and effort. The next time I go down this route, I'll be more prepared to iterate.
Monetization
Monetizing an app is about maximizing dollars per download. The least amount of effort would have been to charge a flat fee in the app store ($1 or $2). However, nobody would have bought my app for two reasons. First, because of all the free options out there. Second, this isn't the sort of app which is going to become ubiquitous on all phones. It solves a very niche problem, easily solvable with pen and paper, so the barrier to download needed to be low.
Another option would have been to provide a "freemium" model, with some features available for free and others available after paying a modest fee. This struck me as a bad idea because the app is already so simple, removing any features would basically make it useless.
Eventually, I decided to provide the app for free with ads. I decided against going with a freemium model (pay to remove ads) from the outset in the interest of spending more time providing core features. If the app gets popular I may add a paid tier.
In exploring all these options it struck me how much time I spent monetizing the app as opposed to adding features. Initially it seemed ironic that in order to make less money per download (offering ads instead of upfront cost in the app store) I had to do more work, but I know that monetization is the core of every business so I'm happy to have gone through the process of weighing the tradeoffs.
Technical challenges
Parsing the ingredient lists was more difficult than I thought. So much so that I'll be writing another blog post on the challenges I faced making a robust scraper and parser. Stay tuned!
Rate recipes
Ability to rate recipes out of 5 stars so you know which ones you liked
Drag and drop to top crashes the app
Small input window for manual items when keyboard is active
Consolidate or clarify add buttons
The plus and pencil are too confusing together
Add notes to recipes
"Don't use as much sugar"
"Don't make as much of the sauce"
Update GIFs and images
- Blog
- Website
- App store
Once you have settled on the new UI
Store recipes and ingredients on phone
So now I’m off to the grocery store with my list. My phone automatically connected to the store’s wifi and the connection is bad so when I opened Nomz I got a loading icon that just spun and eventually got an error that said it couldn’t connect to Nomz. And now I’m about to be real mad because I don’t understand why I need internet access for a grocery list.
Swipe right to delete
With a tip
Adds 2-3 into 5
See quantityImproper
in Parser.hs
Add a donation link
To the website
To the app
Rename the app
Give it a better name and rebrand for competition with other grocery list apps
Marketing materials
- Release blog post
- Link to blog post in app store and website
- Share with food bloggers
- Add images and gifs to website and blog posts
- Nutritionists and dietitians
Recipe detail page
- Go to recipe
- Rating
- Notes
Better UX for reordering (plus merge)
I wanted to reorder the items to be in the grocery store order. For my store dairy is first, produce is last and then cereal and canned goods are in the middle.
That took a bit to figure out. There were up/down icons that indicated I could reorder things but if I tapped them nothing happened.
Then I tried tap and hold and then worked once so I thought I had figured it out but on subsequent tries it tried to merge items (which I don’t understand why that’s a thing you’d want to do) but I think where you click and hold on the item determines what it does.
Use CloudKit
Recipe drag and drop does not work in the lower part of the scroll view
FAQ page
Add an FAQ page for explanations of features like sharing
HTML status page
Make a status page you can load in the browser
Should it do ekg?
Write blog posts on technical limitations
Ingredient Representation
This post is part 2 of 3 in a series on the Nomz Meal Planner
for iOS. Original post is [here]({% post_url 2021-05-31-nomz-meal-planner %}).
Recipe ingredients are tricky. Some quick examples:
- 1 cup milk (name, unit, and quantity)
- 1 egg (no unit)
- Salt and pepper (no unit or quantity)
- 1 slice of bread (nonstandard unit)
In creating a model for an app with a core feature dedicated to auto merging items, it's imperative to be able to
capture all different combinations. I made the quantity and unit optional, and provided a conversion table where
complementary units were concerned (both imperial and metric units, in addition to singular and plural forms of the same
unit).
Conversion table
I wrote a companion function to grab all possible conversions for a unit - inputting "ounce" outputs a map containing
[(ounce, 1), (cup, 8), (tablespoon, 128), (teaspoon, 384), (pinch, 1536)]
.
Merging items
In the case where items share a name and unit, or had complementary units (teaspoon and tablespoon, milliliter and
liter, etc), the backend automatically merges those items using the conversion table.
Fractions
Recipes typically deal with fractions with denominators of 2, 3, or 4. I made a simplifying assumption to enumerate
these values: 1/4, 1/3, 1/2, 2/3, and 3/4. After applying the conversion math between complementary units, I constrained
the decimal portion of each computed quantity to the nearest enumerated value.
User input
In the app, I used the enumeration indices as identifiers in the picker view. Using modular arithmetic, it also made it
easy to infer the quantity when the user merged two items. Instead of doing complicated fractional addition, I was able
to simply add the enumerated indices!
Conclusion
Simplifying assumptions around quantities based on the data available worked out great. Conversions between
complementary units were a crucial step towards implementing auto merge, but didn't quite achieve the elegance I
desired.
Stay tuned for the next post in the series, on scraping recipe websites!
Parsing
This post is part 3 of 3 in a series on the Nomz Meal Planner
for iOS. Original post is [here]({% post_url 2021-06-01-nomz-ingredient-representation %}).
An app that parses recipe ingredients requires both a robust parser and a powerful HTML scraper.
Parsing
Attempting to write a parser for real world data, especially when hosted on webpages, is difficult. A robust parser for
lists of recipe ingredients needs to:
- Parse fractions in many forms (1/2 and 1/2)
- Parse written quantities ("five")
- Parse decimals
- Understand abbreviations ("T", "tbsp", and "tablespoon" are the same)
- Understand ranges of quantities ("1-2 cups")
- Understand that sometimes a dash ("-") means a range and sometimes it means add two quantities ("1-1/2")
- Understand that sometimes quantities and units are missing
- Probably some other things I missed
I'll spare the boring details about the actual Haskell code in this part.
Scraping
Turns out there are a few recipe blog vendors in addition to the common brand names like Betty Crocker, Pillsbury, and
Food Network, and I implemented the scraping logic to dispatch based on domain name and/or a test in the HTML.
Integration
After writing a robust parser and scraper, hooking the two components up was easy.
Testing
I wrote unit tests for both the parser and scraper. Some tests are highly specific, inputting a recipe link and testing
the output matches exactly what's on the page, but since I needed hundreds of tests (for hundreds of websites and blogs)
I ended up writing most tests using a few heuristics:
- At least 5 ingredients parsed
- At least one ingredient parsed with both quantity and unit
- No duplicate ingredients
- Similar seeming ingredients are allowed (like "butter" and "butter, cubed") but only up to 3 of them
Ideally, I'd run these tests every night and alert if one of them broke. After all, HTML scraping is extremely brittle
and I'd want to know ASAP if something was broken, especially in production.
Better app name and iOS metadata
- Nomz meal planner & grocery list
- Better subtitle
- New icons
Error messages say mo nomz sometimes
Any other places that should be changed to just nomz?
App crashes when you search for something without a space
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.