<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Andreas’s Substack]]></title><description><![CDATA[Sharing insights from our journey building MealPrepPro.]]></description><link>https://andreaskambanis.com</link><image><url>https://substackcdn.com/image/fetch/$s_!wJdT!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F339c9f89-c32d-46ed-8591-ac12e1c02dfc_2728x2728.jpeg</url><title>Andreas’s Substack</title><link>https://andreaskambanis.com</link></image><generator>Substack</generator><lastBuildDate>Sat, 31 Oct 2026 09:59:31 GMT</lastBuildDate><atom:link href="https://andreaskambanis.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Andreas Kambanis]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[andreaskambanis@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[andreaskambanis@substack.com]]></itunes:email><itunes:name><![CDATA[Andreas Kambanis]]></itunes:name></itunes:owner><itunes:author><![CDATA[Andreas Kambanis]]></itunes:author><googleplay:owner><![CDATA[andreaskambanis@substack.com]]></googleplay:owner><googleplay:email><![CDATA[andreaskambanis@substack.com]]></googleplay:email><googleplay:author><![CDATA[Andreas Kambanis]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[A first look at MealPrepPro on iPhone Duo]]></title><description><![CDATA[We&#8217;ve always wanted to support adaptivity for MealPrepPro. The launch of the iPhone Duo was the excuse we were looking for.]]></description><link>https://andreaskambanis.com/p/a-first-look-at-mealpreppro-on-iphone</link><guid isPermaLink="false">https://andreaskambanis.com/p/a-first-look-at-mealpreppro-on-iphone</guid><dc:creator><![CDATA[Andreas Kambanis]]></dc:creator><pubDate>Tue, 13 Oct 2026 12:33:34 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!eTek!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F164c885c-a96f-43bc-ac41-a74a794cc310_2062x1498.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;d5de354a-b569-4e97-a8f1-26ffbee05416&quot;,&quot;duration&quot;:null}"></div><p>Back in July, we added foldable iPhone support to our goals for MealPrepPro.</p><p>The interesting challenge with iPhone Duo is that the screen can change while you&#8217;re using the app. You might open a recipe on the outer display, unfold the phone, rotate it, or resize the app.</p><p>Throughout all of that, you should still be looking at the same recipe. Your place in the app should stay intact. The interface needs to adjust without making you feel like you&#8217;ve started over.</p><p>The work started by making changes to our app startup code.</p><h2>One app, many sizes</h2><p>MealPrepPro has grown over almost nine years. Along the way, we&#8217;ve built layouts for different devices, added features, and made use of the space available on each screen.</p><p>Duo pushed us to revisit those decisions.</p><p>We turned to Claude&#8217;s recently added Design in Codebase feature. In earlier iterations of Claude Design we found it would often ignore the need to adapt designs for different screens.</p><p>Giving it the context of our code was a big breakthrough in terms of the quality of the designs we were getting back.</p><p>We started thinking about the elements of the page as &#8220;widgets&#8221; that would move around based on the space available.</p><p>Some screens were good to go - mostly where we&#8217;d stuck to Apple&#8217;s defaults (such as the settings screen) but other screens required much more work like the recipe view.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eTek!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F164c885c-a96f-43bc-ac41-a74a794cc310_2062x1498.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eTek!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F164c885c-a96f-43bc-ac41-a74a794cc310_2062x1498.webp 424w, https://substackcdn.com/image/fetch/$s_!eTek!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F164c885c-a96f-43bc-ac41-a74a794cc310_2062x1498.webp 848w, https://substackcdn.com/image/fetch/$s_!eTek!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F164c885c-a96f-43bc-ac41-a74a794cc310_2062x1498.webp 1272w, https://substackcdn.com/image/fetch/$s_!eTek!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F164c885c-a96f-43bc-ac41-a74a794cc310_2062x1498.webp 1456w" sizes="auto, 100vw"><img src="https://substackcdn.com/image/fetch/$s_!eTek!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F164c885c-a96f-43bc-ac41-a74a794cc310_2062x1498.webp" width="1456" height="1058" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/164c885c-a96f-43bc-ac41-a74a794cc310_2062x1498.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1058,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1577734,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://andreaskambanis.com/i/220183190?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F164c885c-a96f-43bc-ac41-a74a794cc310_2062x1498.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!eTek!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F164c885c-a96f-43bc-ac41-a74a794cc310_2062x1498.webp 424w, https://substackcdn.com/image/fetch/$s_!eTek!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F164c885c-a96f-43bc-ac41-a74a794cc310_2062x1498.webp 848w, https://substackcdn.com/image/fetch/$s_!eTek!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F164c885c-a96f-43bc-ac41-a74a794cc310_2062x1498.webp 1272w, https://substackcdn.com/image/fetch/$s_!eTek!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F164c885c-a96f-43bc-ac41-a74a794cc310_2062x1498.webp 1456w" sizes="auto, 100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Recipe view in MealPrepPro shown on the iPhone Duo in unfolded pose</figcaption></figure></div><p>In the recipe view, we redesigned the nutritional information section and made it more compact so it could fit neatly beneath the recipe intro.</p><p>This solved an issue of a lot of white space and it also responded to what we were hearing from users that they wanted calories and macros listed further up.</p><h2>Cooking on the iPhone Duo</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jV1r!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f92c5ef-e45f-4e62-88a8-d2a6559fdc58_2062x1498.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jV1r!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f92c5ef-e45f-4e62-88a8-d2a6559fdc58_2062x1498.png 424w, https://substackcdn.com/image/fetch/$s_!jV1r!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f92c5ef-e45f-4e62-88a8-d2a6559fdc58_2062x1498.png 848w, https://substackcdn.com/image/fetch/$s_!jV1r!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f92c5ef-e45f-4e62-88a8-d2a6559fdc58_2062x1498.png 1272w, https://substackcdn.com/image/fetch/$s_!jV1r!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f92c5ef-e45f-4e62-88a8-d2a6559fdc58_2062x1498.png 1456w" sizes="auto, 100vw"><img src="https://substackcdn.com/image/fetch/$s_!jV1r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f92c5ef-e45f-4e62-88a8-d2a6559fdc58_2062x1498.png" width="1456" height="1058" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4f92c5ef-e45f-4e62-88a8-d2a6559fdc58_2062x1498.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1058,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3538760,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://andreaskambanis.com/i/220183190?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f92c5ef-e45f-4e62-88a8-d2a6559fdc58_2062x1498.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jV1r!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f92c5ef-e45f-4e62-88a8-d2a6559fdc58_2062x1498.png 424w, https://substackcdn.com/image/fetch/$s_!jV1r!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f92c5ef-e45f-4e62-88a8-d2a6559fdc58_2062x1498.png 848w, https://substackcdn.com/image/fetch/$s_!jV1r!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f92c5ef-e45f-4e62-88a8-d2a6559fdc58_2062x1498.png 1272w, https://substackcdn.com/image/fetch/$s_!jV1r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f92c5ef-e45f-4e62-88a8-d2a6559fdc58_2062x1498.png 1456w" sizes="auto, 100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Cooking mode in MealPrepPro shown on the iPhone Duo</figcaption></figure></div><p>Cooking is a particularly interesting use case for Duo: a larger display gives ingredients and instructions room to sit alongside each other, so you can refer to both without constantly switching back and forth.</p><p>But a folding screen brings its own considerations. Controls need to remain easy to reach, and a button in the crease is hardly convenient when you&#8217;re halfway through making dinner.</p><h2>Making it work, then making it feel right</h2><p>By early October, we&#8217;d drawn a useful distinction between two stages of the work.</p><p>First, make the app resize and rotate properly. Keep content visible, preserve navigation, and use the available display without black borders.</p><p>Then, refine how each screen takes advantage of that space.</p><p>There are plenty of tempting possibilities for a device that can sit partially folded on a counter. But our first priority has been getting the adaptive foundation right, with more specialized layouts as something we&#8217;ve considered later in the project.</p><p>Tackling this with Claude available to us has definitely made us far more ambitious in what we&#8217;ve been able to do. It&#8217;s hard to imagine tackling a project like this in the pre-AI coding days.</p><h2>Part of something bigger</h2><p>I&#8217;m really excited for this update as it adds so many features and upgrades that we&#8217;ve repeatedly heard from customers.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://andreaskambanis.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[How we built MealPrepPro interactive widgets for iOS 17]]></title><description><![CDATA[Updating MealPrepPro widgets for iOS 17 and sharing data between the widget and the main iOS app.]]></description><link>https://andreaskambanis.com/p/how-we-built-mealpreppro-interactive</link><guid isPermaLink="false">https://andreaskambanis.com/p/how-we-built-mealpreppro-interactive</guid><dc:creator><![CDATA[Andreas Kambanis]]></dc:creator><pubDate>Fri, 25 Aug 2023 11:40:36 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!i31P!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c705d38-46bb-4a33-b1ce-15c63b7099a8_2000x1400.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;14a14756-e7a2-49b5-8816-1553b6056379&quot;,&quot;duration&quot;:null}"></div><p>With interactive widgets coming to iOS 17 we decided it was a great opportunity for us to update our widgets.</p><p>We started by going through the 2023 WWDC sessions:</p><ul><li><p><a href="https://developer.apple.com/videos/play/wwdc2023/10028/">Bring widgets to life - WWDC23</a></p></li><li><p><a href="https://developer.apple.com/videos/play/wwdc2023/10027/">Bring widgets to new places - WWDC23</a></p></li></ul><p>We also signed up to Apple&#8217;s developer labs.</p><h2>Widgets in MealPrepPro</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!i31P!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c705d38-46bb-4a33-b1ce-15c63b7099a8_2000x1400.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!i31P!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c705d38-46bb-4a33-b1ce-15c63b7099a8_2000x1400.png 424w, https://substackcdn.com/image/fetch/$s_!i31P!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c705d38-46bb-4a33-b1ce-15c63b7099a8_2000x1400.png 848w, https://substackcdn.com/image/fetch/$s_!i31P!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c705d38-46bb-4a33-b1ce-15c63b7099a8_2000x1400.png 1272w, https://substackcdn.com/image/fetch/$s_!i31P!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c705d38-46bb-4a33-b1ce-15c63b7099a8_2000x1400.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!i31P!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c705d38-46bb-4a33-b1ce-15c63b7099a8_2000x1400.png" width="1456" height="1019" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8c705d38-46bb-4a33-b1ce-15c63b7099a8_2000x1400.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1019,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:328932,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!i31P!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c705d38-46bb-4a33-b1ce-15c63b7099a8_2000x1400.png 424w, https://substackcdn.com/image/fetch/$s_!i31P!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c705d38-46bb-4a33-b1ce-15c63b7099a8_2000x1400.png 848w, https://substackcdn.com/image/fetch/$s_!i31P!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c705d38-46bb-4a33-b1ce-15c63b7099a8_2000x1400.png 1272w, https://substackcdn.com/image/fetch/$s_!i31P!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c705d38-46bb-4a33-b1ce-15c63b7099a8_2000x1400.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In MealPrepPro you can log meals by tapping the Eaten button. This also logs the calorie and nutritional information to Apple Health.</p><p>Our widgets give you an easy way to see your upcoming meal, log it and track your calories and macros.</p><h2>Widgets are independent mini apps</h2><p>iOS Widgets operate independently from iOS apps. They run on their own as mini apps, and often the main iOS app won&#8217;t be running at all. You might have quite a few widgets visible all the time on your home screen, and the parent iOS apps aren&#8217;t running in the background at all.</p><p>For widgets to run independently, they need their own supply of data. Some widgets get data from the main iOS app. Other apps get data directly from the internet.</p><h2>How the MealPrepPro widgets get data</h2><p>In iOS 16 and earlier, our iOS app writes data to a file in a shared area. The widget then picks up the data from that shared area when it runs.</p><p>To prevent the widget from running out of data, we give the widget enough data to show meals for the week ahead.</p><p>With iOS 17, widgets are no longer limited to just displaying data. You can now wire up buttons to trigger actions that might do things such as tick off items in a to do list.</p><h2>Widget Interactivity in iOS 17</h2><p>To add interactivity to widgets you use App Intents. The most well known example of app intents is the Shortcuts app.</p><p>Intents are pieces of an app's functionality that are exposed to the iOS system.</p><h2>&#129300; Challenge 1: How do we hookup the widget&#8217;s eaten button?</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jhaK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91693a9b-c827-423c-b68b-4a78059534fc_1080x1080.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jhaK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91693a9b-c827-423c-b68b-4a78059534fc_1080x1080.gif 424w, https://substackcdn.com/image/fetch/$s_!jhaK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91693a9b-c827-423c-b68b-4a78059534fc_1080x1080.gif 848w, https://substackcdn.com/image/fetch/$s_!jhaK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91693a9b-c827-423c-b68b-4a78059534fc_1080x1080.gif 1272w, https://substackcdn.com/image/fetch/$s_!jhaK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91693a9b-c827-423c-b68b-4a78059534fc_1080x1080.gif 1456w" sizes="auto, 100vw"><img src="https://substackcdn.com/image/fetch/$s_!jhaK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91693a9b-c827-423c-b68b-4a78059534fc_1080x1080.gif" width="1080" height="1080" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/91693a9b-c827-423c-b68b-4a78059534fc_1080x1080.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1080,&quot;width&quot;:1080,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2998080,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jhaK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91693a9b-c827-423c-b68b-4a78059534fc_1080x1080.gif 424w, https://substackcdn.com/image/fetch/$s_!jhaK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91693a9b-c827-423c-b68b-4a78059534fc_1080x1080.gif 848w, https://substackcdn.com/image/fetch/$s_!jhaK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91693a9b-c827-423c-b68b-4a78059534fc_1080x1080.gif 1272w, https://substackcdn.com/image/fetch/$s_!jhaK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91693a9b-c827-423c-b68b-4a78059534fc_1080x1080.gif 1456w" sizes="auto, 100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>For MealPrepPro, we wanted the Widget to have an Eaten button for a meal. This would:</p><ol><li><p>Mark the meal as Eaten inside the iOS app</p></li><li><p>Optionally log the calories and nutritional information to Apple Health</p></li></ol><p>However, this task proved to be more challenging than we initially anticipated. We mistakenly assumed that the App Intents feature for Widgets would work similarly to the Shortcuts app. We believed that tapping a button in the widget would trigger code <em>inside the main iOS app</em> to update the app's database. However, this was not the case.</p><p>The rules for what a Widget App Intent can do are:</p><ul><li><p>Can trigger code inside the Widget</p></li><li><p>Can trigger code that&#8217;s shared between the main iOS app and Widget</p></li><li><p>Cannot trigger code inside the iOS app that is not shared with the Widget</p></li></ul><p>In our case, we wanted to trigger code that was exclusively inside the iOS app and NOT shared with the widget. Specifically we wanted to update the iOS app&#8217;s database to update the Eaten (true/false) for a specific meal. The iOS app database is not visible to the widget.</p><h3>Option 1 - Add the iOS database to the widget</h3><p>The first solution we considered - could we make the iOS database visible to the widget? This would mean sharing the necessary database and model code with the widget.</p><p>It would mean moving the app&#8217;s database where the meals are logged to the shared area between the iOS app and widget. Our app&#8217;s database is based on SQLite (using GRDB), and sharing a database between the main app and a widget extension is particularly challenging and error-prone. The documentation recommends <a href="https://swiftpackageindex.com/groue/grdb.swift/master/documentation/grdb/databasesharing">avoiding this approach</a>.</p><h3>Option 2 - Get Firebase to update the widget</h3><p>We also considered using Firebase (via the network) to update the widget. However, we wanted to avoid adding complexity to the widget.</p><h3>Option 3 - Create a new mini &#8220;database&#8221;</h3><p>In the end we felt the least complicated solution would be to create a new mini database that would live inside the area that&#8217;s shared between the iOS app and the Widget Extension.</p><ul><li><p>When the iOS app changes the meal plan, it updates this new database so that the widget knows about the change</p></li><li><p>If the widget marks a meal as Eaten, it also updates this new database so that the iOS app can pick up the change.</p></li></ul><h1>&#129300; Challenge 2: Why is my widget button not working?</h1><p>We hooked up our Eaten button in our widget, put in place our new code for our new mini &#8220;database&#8221;&#8230; and found that it worked sometimes&#8230; but not always. Tapping the Eaten button in our widget didn&#8217;t always seem to work which was strange.</p><p>We assumed this was a bug in a beta version of iOS, so set the problem aside for a while and waited for a new beta. But with the new beta the problem was still there, so we were a bit stuck thinking that we were doing something wrong.</p><p>And then on 1st August we saw an interesting post on Mastodon from Michael Gorbach, the Engineering Manager for App Intents, Shortcuts and Proactive Intelligence at Apple:</p><p><a href="https://mastodon.social/@mgorbach/110812346248732071">https://mastodon.social/@mgorbach/110812346248732071</a></p><p>Michael explained that what happens when you tap a button or toggle in a Widget depends on whether the iOS app is running at the time or not. </p><p>In our case:</p><ul><li><p>If the iOS app is running, the App Intent triggered by the Widget runs in the iOS app</p></li><li><p>If the iOS app isn&#8217;t running, the App Intent triggered by the Widget runs in the Widget</p></li></ul><p>This explanation by Michael explained the inconsistent behaviour we were seeing.</p><p>We updated our code to take in to consideration if the app is running or not.</p><h2>Ready to go &#128640; </h2><p>We&#8217;re happy with how MealPrepPro widgets turned out for iOS 17 and looking forward to launching them in September.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nE5D!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb26f64fd-dfe4-4dd5-ac1b-ec7b356cdc37_1388x1168.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nE5D!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb26f64fd-dfe4-4dd5-ac1b-ec7b356cdc37_1388x1168.png 424w, https://substackcdn.com/image/fetch/$s_!nE5D!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb26f64fd-dfe4-4dd5-ac1b-ec7b356cdc37_1388x1168.png 848w, https://substackcdn.com/image/fetch/$s_!nE5D!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb26f64fd-dfe4-4dd5-ac1b-ec7b356cdc37_1388x1168.png 1272w, https://substackcdn.com/image/fetch/$s_!nE5D!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb26f64fd-dfe4-4dd5-ac1b-ec7b356cdc37_1388x1168.png 1456w" sizes="auto, 100vw"><img src="https://substackcdn.com/image/fetch/$s_!nE5D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb26f64fd-dfe4-4dd5-ac1b-ec7b356cdc37_1388x1168.png" width="1388" height="1168" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b26f64fd-dfe4-4dd5-ac1b-ec7b356cdc37_1388x1168.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1168,&quot;width&quot;:1388,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:896392,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nE5D!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb26f64fd-dfe4-4dd5-ac1b-ec7b356cdc37_1388x1168.png 424w, https://substackcdn.com/image/fetch/$s_!nE5D!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb26f64fd-dfe4-4dd5-ac1b-ec7b356cdc37_1388x1168.png 848w, https://substackcdn.com/image/fetch/$s_!nE5D!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb26f64fd-dfe4-4dd5-ac1b-ec7b356cdc37_1388x1168.png 1272w, https://substackcdn.com/image/fetch/$s_!nE5D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb26f64fd-dfe4-4dd5-ac1b-ec7b356cdc37_1388x1168.png 1456w" sizes="auto, 100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://andreaskambanis.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe for more updates on our journey of building MealPrepPro</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>