<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>AppMakers.Dev</title>
	<atom:link href="https://appmakers.dev/feed/" rel="self" type="application/rss+xml" />
	<link>https://appmakers.dev/</link>
	<description>SwiftUI Tutorials, iOS App Development, SwiftUI, Swift</description>
	<lastBuildDate>Fri, 27 Jun 2025 18:43:32 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://appmakers.dev/wp-content/uploads/2024/10/cropped-AppMakersDev-32x32.jpg</url>
	<title>AppMakers.Dev</title>
	<link>https://appmakers.dev/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>What Apple’s WWDC 2025 Means for Developers: Liquid Glass, On-Device AI, and the New Era of App Design</title>
		<link>https://appmakers.dev/what-apples-wwdc-2025-means-for-developers-liquid-glass-on-device-ai-and-the-new-era-of-app-design/</link>
		
		<dc:creator><![CDATA[AppMakers]]></dc:creator>
		<pubDate>Fri, 27 Jun 2025 18:43:32 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[iOS Development]]></category>
		<category><![CDATA[WWDC 2025]]></category>
		<guid isPermaLink="false">https://appmakers.dev/?p=1999</guid>

					<description><![CDATA[<p>A New Chapter for Apple Developers Apple’s WWDC 2025 wasn’t just about new products—it was a blueprint for the next generation of app development. From the sleek visual language of Liquid Glass to privacy-first on-device AI, Apple made it clear: apps should feel alive, intelligent, and deeply integrated across devices. This article breaks down the&#8230;</p>
<p>The post <a href="https://appmakers.dev/what-apples-wwdc-2025-means-for-developers-liquid-glass-on-device-ai-and-the-new-era-of-app-design/">What Apple’s WWDC 2025 Means for Developers: Liquid Glass, On-Device AI, and the New Era of App Design</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 data-start="626" data-end="665">A New Chapter for Apple Developers</h2>
<p data-start="666" data-end="963">Apple’s WWDC 2025 wasn’t just about new products—it was a <strong data-start="724" data-end="780">blueprint for the next generation of app development</strong>. From the sleek visual language of <strong data-start="816" data-end="832">Liquid Glass</strong> to privacy-first <strong data-start="850" data-end="866">on-device AI</strong>, Apple made it clear: apps should feel alive, intelligent, and deeply integrated across devices.</p>
<p data-start="965" data-end="1220">This article breaks down the biggest developer updates from <strong data-start="1025" data-end="1069">Apple’s 2025 Platform State of the Union</strong>, explains what they mean in plain English, and shows how you can apply them in your own apps—whether you build for iOS, macOS, visionOS, or all three.</p>
<hr data-start="1222" data-end="1225" />
<h2 data-start="1227" data-end="1279">1. A New Design Standard: What is Liquid Glass?</h2>
<p data-start="1280" data-end="1452">One of the most visible—and beautiful—announcements was the introduction of <strong data-start="1356" data-end="1372">Liquid Glass</strong>, a modern design system that redefines how apps look and feel on Apple devices.</p>
<h3 data-start="1454" data-end="1472">Key Takeaways:</h3>
<ul data-start="1473" data-end="1767">
<li data-start="1473" data-end="1546">
<p data-start="1475" data-end="1546">Transparent, <strong data-start="1488" data-end="1512">glass-like UI layers</strong> that adapt to content and light</p>
</li>
<li data-start="1547" data-end="1621">
<p data-start="1549" data-end="1621">UI elements now <strong data-start="1565" data-end="1593">float, bend, and shimmer</strong> based on user interaction</p>
</li>
<li data-start="1622" data-end="1687">
<p data-start="1624" data-end="1687">Built to work across iPhone, iPad, Mac, Watch, and Vision Pro</p>
</li>
<li data-start="1688" data-end="1767">
<p data-start="1690" data-end="1767"><strong data-start="1690" data-end="1716">Out-of-the-box support</strong> in SwiftUI, UIKit, and AppKit with no code changes</p>
</li>
</ul>
<p data-start="1769" data-end="1873">Imagine the feel of frosted glass—not just as a texture, but as a living interface. That’s Liquid Glass.</p>
<p data-start="1875" data-end="1991">You can test it now simply by recompiling in <strong data-start="1920" data-end="1932">Xcode 26</strong>. No redesign needed unless you want to fully customize it.</p>
<hr data-start="1993" data-end="1996" />
<h2 data-start="1998" data-end="2047">2. Meet Apple Intelligence: Your AI Co-Pilot</h2>
<p data-start="2048" data-end="2209">Apple took a bold step away from cloud-based LLMs with the launch of <strong data-start="2117" data-end="2139">Apple Intelligence</strong>—a private, fast, and offline AI engine that runs right on the device.</p>
<h3 data-start="2211" data-end="2230">Why It Matters:</h3>
<ul data-start="2231" data-end="2531">
<li data-start="2231" data-end="2296">
<p data-start="2233" data-end="2296">You get a <strong data-start="2243" data-end="2270">powerful language model</strong> on-device, ready to use</p>
</li>
<li data-start="2297" data-end="2479">
<p data-start="2299" data-end="2369">Apple provides a new <strong data-start="2320" data-end="2351">Foundation Models framework</strong> for tasks like:</p>
<ul data-start="2372" data-end="2479">
<li data-start="2372" data-end="2395">
<p data-start="2374" data-end="2395">Summarizing content</p>
</li>
<li data-start="2398" data-end="2417">
<p data-start="2400" data-end="2417">Generating text</p>
</li>
<li data-start="2420" data-end="2448">
<p data-start="2422" data-end="2448">Creating structured data</p>
</li>
<li data-start="2451" data-end="2479">
<p data-start="2453" data-end="2479">Tagging and tool-calling</p>
</li>
</ul>
</li>
<li data-start="2480" data-end="2531">
<p data-start="2482" data-end="2531">No privacy concerns, server costs, or rate limits</p>
</li>
</ul>
<p data-start="2533" data-end="2771">Plus, Apple made integrating AI shockingly simple. With just a few lines of Swift, you can bring real intelligence into your app—whether it’s generating travel plans, helping users write journal entries, or powering smart recommendations.</p>
<hr data-start="2773" data-end="2776" />
<h2 data-start="2778" data-end="2825">3. Xcode 26: Now with Built-In AI and More</h2>
<p data-start="2826" data-end="2894">Apple’s developer toolkit just got way more powerful—and more human.</p>
<h3 data-start="2896" data-end="2916">New in Xcode 26:</h3>
<ul data-start="2917" data-end="3186">
<li data-start="2917" data-end="2958">
<p data-start="2919" data-end="2958"><strong data-start="2919" data-end="2946">ChatGPT-style assistant</strong>, built-in</p>
</li>
<li data-start="2959" data-end="3014">
<p data-start="2961" data-end="3014">Inline previews, bug fixes, refactoring suggestions</p>
</li>
<li data-start="3015" data-end="3062">
<p data-start="3017" data-end="3062">Smart code generation from text or drawings</p>
</li>
<li data-start="3063" data-end="3130">
<p data-start="3065" data-end="3130">Ability to <strong data-start="3076" data-end="3108">scrub through prompt history</strong> and go back in time</p>
</li>
<li data-start="3131" data-end="3186">
<p data-start="3133" data-end="3186">Integrates with OpenAI, Claude, and even local models</p>
</li>
</ul>
<p data-start="3188" data-end="3277">You don’t need an API key to get started. Xcode’s AI tools are built right into the beta.</p>
<p data-start="3279" data-end="3388">Whether you want to generate SwiftUI views or explain legacy code, you now have a teammate that never sleeps.</p>
<hr data-start="3390" data-end="3393" />
<h2 data-start="3395" data-end="3443">4. Swift 6.2: Performance without Sacrifice</h2>
<p data-start="3444" data-end="3603">Apple continues to push the Swift language forward, and Swift 6.2 brings <strong data-start="3517" data-end="3553">serious performance improvements</strong>—especially for memory-heavy or system-level apps.</p>
<h3 data-start="3605" data-end="3627">Notable Additions:</h3>
<ul data-start="3628" data-end="3891">
<li data-start="3628" data-end="3690">
<p data-start="3630" data-end="3690"><strong data-start="3630" data-end="3647">Inline Arrays</strong>: faster data storage without heap memory</p>
</li>
<li data-start="3691" data-end="3741">
<p data-start="3693" data-end="3741"><strong data-start="3693" data-end="3706">Span type</strong>: a safe way to access raw memory</p>
</li>
<li data-start="3742" data-end="3792">
<p data-start="3744" data-end="3792"><strong data-start="3744" data-end="3767">WebAssembly support</strong> for browser deployment</p>
</li>
<li data-start="3793" data-end="3836">
<p data-start="3795" data-end="3836">Improved <strong data-start="3804" data-end="3834">C++ and JavaScript interop</strong></p>
</li>
<li data-start="3837" data-end="3891">
<p data-start="3839" data-end="3891">Better concurrency defaults and <code class="" data-line="">MainActor</code> behavior</p>
</li>
</ul>
<p data-start="3893" data-end="4025">This release shows Swift is no longer just an iOS language—it’s a powerful systems language ready for servers, browsers, and beyond.</p>
<hr data-start="4027" data-end="4030" />
<h2 data-start="4032" data-end="4081">5. SwiftUI: Cleaner Code, Faster Performance</h2>
<p data-start="4082" data-end="4162">SwiftUI got a major tune-up in 2025, making it even more robust for modern apps.</p>
<h3 data-start="4164" data-end="4179">What&#8217;s New:</h3>
<ul data-start="4180" data-end="4505">
<li data-start="4180" data-end="4247">
<p data-start="4182" data-end="4247">Full support for <strong data-start="4199" data-end="4220">rich text editing</strong> using <code class="" data-line="">AttributedString</code></p>
</li>
<li data-start="4248" data-end="4303">
<p data-start="4250" data-end="4303">Native <strong data-start="4257" data-end="4268">WebView</strong> and programmatic browser control</p>
</li>
<li data-start="4304" data-end="4356">
<p data-start="4306" data-end="4356">Gorgeous new <strong data-start="4319" data-end="4339">3D charting APIs</strong> via RealityKit</p>
</li>
<li data-start="4357" data-end="4419">
<p data-start="4359" data-end="4419">Dramatically improved list performance—<strong data-start="4398" data-end="4417">up to 6x faster</strong></p>
</li>
<li data-start="4420" data-end="4505">
<p data-start="4422" data-end="4505">New APIs for <strong data-start="4435" data-end="4452">drag and drop</strong>, <strong data-start="4454" data-end="4474">scene management</strong>, and <strong data-start="4480" data-end="4505">SwiftData subclassing</strong></p>
</li>
</ul>
<p data-start="4507" data-end="4574">If you’ve been waiting to go all-in on SwiftUI—this is your moment.</p>
<hr data-start="4576" data-end="4579" />
<h2 data-start="4581" data-end="4629">6. Spatial Apps Are the Future: visionOS 26</h2>
<p data-start="4630" data-end="4718">Apple’s spatial computing platform is becoming more developer-friendly—and more magical.</p>
<h3 data-start="4720" data-end="4741">New Capabilities:</h3>
<ul data-start="4742" data-end="4969">
<li data-start="4742" data-end="4781">
<p data-start="4744" data-end="4781"><strong data-start="4744" data-end="4766">Volumetric layouts</strong> with SwiftUI</p>
</li>
<li data-start="4782" data-end="4826">
<p data-start="4784" data-end="4826">Shared spatial windows and world anchors</p>
</li>
<li data-start="4827" data-end="4863">
<p data-start="4829" data-end="4863">Automatically persistent widgets</p>
</li>
<li data-start="4864" data-end="4915">
<p data-start="4866" data-end="4915">Convert 2D images into 3D environments using AI</p>
</li>
<li data-start="4916" data-end="4969">
<p data-start="4918" data-end="4969">FaceTime spatial personas for shared AR experiences</p>
</li>
</ul>
<p data-start="4971" data-end="5046">This opens the door for apps that feel more like environments than screens.</p>
<hr data-start="5048" data-end="5051" />
<h2 data-start="5053" data-end="5101">7. Gaming on Apple Devices? It&#8217;s Happening.</h2>
<p data-start="5102" data-end="5169">Yes, <em data-start="5107" data-end="5113">real</em> gaming is coming to Mac—and Apple’s not joking anymore.</p>
<p data-start="5171" data-end="5252">With <strong data-start="5176" data-end="5187">Metal 4</strong>, Apple is embracing GPU-powered realism and AI-enhanced visuals.</p>
<h3 data-start="5254" data-end="5277">Metal 4 Highlights:</h3>
<ul data-start="5278" data-end="5546">
<li data-start="5278" data-end="5327">
<p data-start="5280" data-end="5327"><strong data-start="5280" data-end="5300">Neural rendering</strong> and lighting via shaders</p>
</li>
<li data-start="5328" data-end="5377">
<p data-start="5330" data-end="5377"><strong data-start="5330" data-end="5375">MetalFX upscaling and frame interpolation</strong></p>
</li>
<li data-start="5378" data-end="5437">
<p data-start="5380" data-end="5437">Game Porting Toolkit v2: port PC games faster than ever</p>
</li>
<li data-start="5438" data-end="5491">
<p data-start="5440" data-end="5491">PlayStation VR2 controller support for Vision Pro</p>
</li>
<li data-start="5492" data-end="5546">
<p data-start="5494" data-end="5546">Full cloud saves with the new <strong data-start="5524" data-end="5546">GameSave framework</strong></p>
</li>
</ul>
<p data-start="5548" data-end="5622"><em data-start="5548" data-end="5564">Cyberpunk 2077</em> now runs at 60 FPS on MacBook M4. That alone says it all.</p>
<hr data-start="5624" data-end="5627" />
<h2 data-start="5629" data-end="5680">8. Smarter System Integration with App Intents</h2>
<p data-start="5681" data-end="5767">Apple is making your app more discoverable than ever—with or without a homescreen tap.</p>
<h3 data-start="5769" data-end="5808">App Intents Framework Now Works In:</h3>
<ul data-start="5809" data-end="5915">
<li data-start="5809" data-end="5833">
<p data-start="5811" data-end="5833"><strong data-start="5811" data-end="5831">Spotlight search</strong></p>
</li>
<li data-start="5834" data-end="5864">
<p data-start="5836" data-end="5864"><strong data-start="5836" data-end="5862">Control Center buttons</strong></p>
</li>
<li data-start="5865" data-end="5892">
<p data-start="5867" data-end="5892"><strong data-start="5867" data-end="5890">Lock Screen widgets</strong></p>
</li>
<li data-start="5893" data-end="5915">
<p data-start="5895" data-end="5915"><strong data-start="5895" data-end="5915">Siri &amp; Shortcuts</strong></p>
</li>
</ul>
<p data-start="5917" data-end="6052">You can also use <strong data-start="5934" data-end="5962">Visual Intelligence APIs</strong> to recognize content in photos and link users directly into your app—even if it’s closed.</p>
<p data-start="6054" data-end="6117">This makes your app’s features feel like part of the OS itself.</p>
<p>The post <a href="https://appmakers.dev/what-apples-wwdc-2025-means-for-developers-liquid-glass-on-device-ai-and-the-new-era-of-app-design/">What Apple’s WWDC 2025 Means for Developers: Liquid Glass, On-Device AI, and the New Era of App Design</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Build a SwiftUI Widget with App Intents and SwiftData ( Configurable Widget )</title>
		<link>https://appmakers.dev/how-to-build-a-swiftui-widget-with-app-intents-and-swiftdata-configurable-widget/</link>
		
		<dc:creator><![CDATA[AppMakers]]></dc:creator>
		<pubDate>Fri, 13 Jun 2025 17:56:33 +0000</pubDate>
				<category><![CDATA[iOS Development]]></category>
		<category><![CDATA[Source Code]]></category>
		<category><![CDATA[Swift]]></category>
		<category><![CDATA[SwiftUI]]></category>
		<category><![CDATA[SwiftUI Widgets]]></category>
		<category><![CDATA[WidgetKit]]></category>
		<category><![CDATA[Widgets]]></category>
		<guid isPermaLink="false">https://appmakers.dev/?p=1994</guid>

					<description><![CDATA[<p>In this comprehensive tutorial, we’ll guide you through the process of constructing a fully functional Configurable Widget utilizing the latest SwiftUI technologies. This widget will empower users to select content from your app, such as a motivational quote, and display it conveniently on their Home Screen. Additionally, users will have the option to select a&#8230;</p>
<p>The post <a href="https://appmakers.dev/how-to-build-a-swiftui-widget-with-app-intents-and-swiftdata-configurable-widget/">How to Build a SwiftUI Widget with App Intents and SwiftData ( Configurable Widget )</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<div class="gp go hi hj hk">
<div class="ac cb">
<div class="ci bh gv gw gx gy">
<p id="6f98" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">In this comprehensive tutorial, we’ll guide you through the process of constructing a fully functional Configurable Widget utilizing the latest SwiftUI technologies. This widget will empower users to select content from your app, such as a motivational quote, and display it conveniently on their Home Screen. Additionally, users will have the option to select a background color and toggle the Favorite state for the widget.</p>
<h2 id="ecdb" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph=""><a class="ag gn" href="https://appmakers.gumroad.com/l/swiftui-widget-swiftdata-appintents-configurable" target="_blank" rel="noopener ugc nofollow">📦 Download the Code for this Tutorial 📥</a></h2>
<h1 id="162b" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">🛠 Step 1: Project Setup</h1>
<h1 id="e291" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">1. Create the Base App</h1>
<ul class="">
<li id="cbf1" class="ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa pz qa qb bk" data-selectable-paragraph="">Open Xcode, navigate to File, select New, and choose Project. Set the name to ConfigurableWidgetsApp. For the Interface, select SwiftUI, and for the Language, select Swift.</li>
</ul>
<h1 id="087d" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">2. Add a Widget Extension</h1>
<ul class="">
<li id="8b12" class="ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa pz qa qb bk" data-selectable-paragraph="">Go to File → New → Target → Select Widget Extension. Uncheck Live Activity and Control, and check Include Configuration App Intent. Name it ConfigurableWidget. If prompted, activate the ConfigurableWidgetExtension scheme.</li>
</ul>
<h1 id="8898" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">3. Enable App Groups</h1>
<p id="6452" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">We utilize App Groups to facilitate data sharing between your app and widget. To proceed, navigate to your app target, select Signing &amp; Capabilities, and then click on Add App Groups. Next, create a new App Group with the name group.com.yourname.ConfigurableWidgets. Repeat the same process for your widget target. It’s crucial to ensure that both appGroups share the same group container name to enable data sharing between your app and widget.</p>
<h1 id="7ac4" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">🧱 Step 2: Create the SwiftData Model</h1>
<p id="fb6c" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Inside your app, create a file <code class="" data-line="">Motivation.swift.</code></p>
<p id="71ce" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">This SwiftData model represents a single motivational message.</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="5d27" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-type">Model</span>
<span class="hljs-keyword">final</span> <span class="hljs-keyword">class</span> <span class="hljs-title.class">Motivation</span>: <span class="hljs-title.class">Identifiable</span> {
    
    <span class="hljs-keyword">var</span> id: <span class="hljs-type">UUID</span>?
    <span class="hljs-keyword">var</span> message: <span class="hljs-type">String</span>?
    <span class="hljs-keyword">var</span> timestamp: <span class="hljs-type">Date</span>?

    <span class="hljs-keyword">init</span>(<span class="hljs-params">message</span>: <span class="hljs-type">String</span>?, <span class="hljs-params">timestamp</span>: <span class="hljs-type">Date</span> <span class="hljs-operator">=</span> .now) {
        <span class="hljs-keyword">self</span>.id <span class="hljs-operator">=</span> <span class="hljs-type">UUID</span>()
        <span class="hljs-keyword">self</span>.message <span class="hljs-operator">=</span> message
        <span class="hljs-keyword">self</span>.timestamp <span class="hljs-operator">=</span> timestamp
    }
}</span></pre>
<p id="1fc3" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">To ensure that your file is accessible within your WidgetExtension, you must attach the “Motivation.swift” file to the Target. This process applies to any file you intend to use within your extension.</p>
<h2 id="467c" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">Register the model in your app</h2>
<p id="e07d" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Open <code class="" data-line="">ConfigurableWidgetsApp.swift</code> and configure the model container with <code class="" data-line="">.modelContainer(for: [Motivation.self])</code> Don&#8217;t forget to add <code class="" data-line="">import SwiftData</code></p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="3b1f" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">import</span> SwiftData

<span class="hljs-keyword">@main</span>
<span class="hljs-keyword">struct</span> <span class="hljs-title.class">ConfigurableWidgetsApp</span>: <span class="hljs-title.class">App</span> {
    <span class="hljs-keyword">var</span> body: <span class="hljs-keyword">some</span> <span class="hljs-type">Scene</span> {
        <span class="hljs-type">WindowGroup</span> {
            <span class="hljs-type">ContentView</span>()
        }
        .modelContainer(for: [<span class="hljs-type">Motivation</span>.<span class="hljs-keyword">self</span>])
    }
}</span></pre>
<p id="be44" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">This sets up your SwiftData model and prepares it for storage and syncing.</p>
<h1 id="7daf" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">📲 Step 3: Build the Motivation List UI</h1>
<p id="62e9" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Now, let’s construct the user interface that enables you to manage your list of motivations within the app.</p>
<p id="62e9" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">We’ll create or update ContentView.swift to implement these features.</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="220f" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">import</span> SwiftUI
<span class="hljs-keyword">import</span> SwiftData

<span class="hljs-keyword">struct</span> <span class="hljs-title.class">ContentView</span>: <span class="hljs-title.class">View</span> {
    
    <span class="hljs-meta">@Environment</span>(\.modelContext) <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> modelContext
    <span class="hljs-meta">@Query</span>(sort: \<span class="hljs-type">Motivation</span>.timestamp, order: .reverse) <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> motivations: [<span class="hljs-type">Motivation</span>]
    
    <span class="hljs-meta">@State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> showAllUsedAlert <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>
    
    <span class="hljs-keyword">let</span> motivationSamples <span class="hljs-operator">=</span> [
        <span class="hljs-string">"Keep going!"</span>,
        <span class="hljs-string">"You got this!"</span>,
        <span class="hljs-string">"Make it happen!"</span>,
        <span class="hljs-string">"Dream big, act bigger."</span>,
        <span class="hljs-string">"Stay hungry, stay foolish."</span>,
        <span class="hljs-string">"Progress, not perfection."</span>,
        <span class="hljs-string">"Push beyond limits."</span>,
        <span class="hljs-string">"Your only limit is you."</span>,
        <span class="hljs-string">"Success is a habit."</span>,
        <span class="hljs-string">"Discipline &gt; Motivation."</span>,
        <span class="hljs-string">"Every step counts."</span>,
        <span class="hljs-string">"Don’t stop now."</span>,
        <span class="hljs-string">"You were made for more."</span>,
        <span class="hljs-string">"Do it scared."</span>,
        <span class="hljs-string">"Tiny wins every day."</span>,
        <span class="hljs-string">"No zero days."</span>,
        <span class="hljs-string">"Trust the process."</span>,
        <span class="hljs-string">"The future is yours to shape."</span>,
        <span class="hljs-string">"Create your own momentum."</span>,
        <span class="hljs-string">"Consistency is your superpower."</span>
    ]

    <span class="hljs-keyword">var</span> body: <span class="hljs-keyword">some</span> <span class="hljs-type">View</span> {
            <span class="hljs-type">NavigationStack</span> {
                <span class="hljs-type">List</span> {
                    <span class="hljs-type">ForEach</span>(motivations) { motivation <span class="hljs-keyword">in</span>
                        <span class="hljs-type">VStack</span>(alignment: .leading) {
                            <span class="hljs-type">Text</span>(motivation.message <span class="hljs-operator">??</span> <span class="hljs-string">"No message"</span>)
                                .font(.headline)
                            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> timestamp <span class="hljs-operator">=</span> motivation.timestamp {
                                <span class="hljs-type">Text</span>(timestamp.formatted(date: .abbreviated, time: .shortened))
                                    .font(.caption)
                                    .foregroundStyle(.gray)
                            }
                        }
                        .padding(.vertical, <span class="hljs-number">4</span>)
                    }
                    .onDelete(perform: deleteItems)
                }
                .navigationTitle(<span class="hljs-string">"Your Motivations"</span>)
                .toolbar {
                    <span class="hljs-type">ToolbarItem</span>(placement: .bottomBar) {
                        <span class="hljs-type">Button</span>(action: addItem) {
                            <span class="hljs-type">Label</span>(<span class="hljs-string">"Add Motivation"</span>, systemImage: <span class="hljs-string">"plus.circle.fill"</span>)
                                .font(.headline)
                        }
                    }
                }
                .alert(<span class="hljs-string">"All Motivations Added"</span>, isPresented: <span class="hljs-variable">$showAllUsedAlert</span>) {
                    <span class="hljs-type">Button</span>(<span class="hljs-string">"OK"</span>, role: .cancel) {}
                } message: {
                    <span class="hljs-type">Text</span>(<span class="hljs-string">"You've already added all available motivation samples."</span>)
                }
            }
        }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">func</span> <span class="hljs-title.function">addItem</span>() {
        
        <span class="hljs-comment">// Check which messages are not yet in the list</span>
        <span class="hljs-keyword">let</span> existingMessages <span class="hljs-operator">=</span> <span class="hljs-type">Set</span>(motivations.compactMap { <span class="hljs-variable">$0</span>.message })
        <span class="hljs-keyword">let</span> availableMessages <span class="hljs-operator">=</span> motivationSamples.filter { <span class="hljs-operator">!</span>existingMessages.contains(<span class="hljs-variable">$0</span>) }

        <span class="hljs-comment">// If no new messages left, show alert</span>
        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> newMessage <span class="hljs-operator">=</span> availableMessages.randomElement() <span class="hljs-keyword">else</span> {
            showAllUsedAlert <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>
            <span class="hljs-keyword">return</span>
        }

        <span class="hljs-keyword">let</span> newMotivation <span class="hljs-operator">=</span> <span class="hljs-type">Motivation</span>(message: newMessage)
        modelContext.insert(newMotivation)
        <span class="hljs-keyword">try?</span> modelContext.save()
        
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">func</span> <span class="hljs-title.function">deleteItems</span>(<span class="hljs-params">at</span> <span class="hljs-params">offsets</span>: <span class="hljs-type">IndexSet</span>) {
        
        <span class="hljs-keyword">for</span> index <span class="hljs-keyword">in</span> offsets {
            <span class="hljs-keyword">let</span> item <span class="hljs-operator">=</span> motivations[index]
            modelContext.delete(item)
            <span class="hljs-keyword">try?</span> modelContext.save()
        }
        
    }
    
}</span></pre>
<h1 id="b448" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">🧠 Step 4: Let Users Choose a Motivation in the Widget Configuration Panel</h1>
<p>Widgets powered by AppIntentConfiguration can display dynamic content that users can choose from, such as motivational quotes from your SwiftData model. To achieve this, we need to ensure that our SwiftData model (Motivation) is compatible with the widget configuration UI.</p>
<p>AppEntity and EntityQuery play a crucial role in this process.</p>
<h2 id="e110" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">4.1. Define an AppEntity Wrapper: <code class="" data-line="">MotivationEntity</code></h2>
<p id="0636" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Inside <code class="" data-line="">AppIntent.swift</code>, add this struct:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="354f" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">struct</span> <span class="hljs-title.class">MotivationEntity</span>: <span class="hljs-title.class">AppEntity</span> {
    <span class="hljs-keyword">var</span> id: <span class="hljs-type">String</span>
    <span class="hljs-keyword">var</span> message: <span class="hljs-type">String</span>

    <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> typeDisplayRepresentation: <span class="hljs-type">TypeDisplayRepresentation</span> <span class="hljs-operator">=</span> <span class="hljs-string">"Motivation"</span>
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> defaultQuery <span class="hljs-operator">=</span> <span class="hljs-type">MotivationQuery</span>()

    <span class="hljs-keyword">var</span> displayRepresentation: <span class="hljs-type">DisplayRepresentation</span> {
        <span class="hljs-type">DisplayRepresentation</span>(
            title: <span class="hljs-type">LocalizedStringResource</span>(<span class="hljs-string">"<span class="hljs-subst">\(message)</span>"</span>),
            subtitle: <span class="hljs-type">LocalizedStringResource</span>(<span class="hljs-string">"<span class="hljs-subst">\(id)</span>"</span>)
        )
    }
}</span><code class="" data-line=""></code></pre>
<h2 id="a101" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">4.2. Add a Query to Load Motivations from SwiftData</h2>
<p id="e68b" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Still in <code class="" data-line="">AppIntent.swift</code>, define the following below <code class="" data-line="">MotivationEntity</code>:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="c03b" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">struct</span> <span class="hljs-title.class">MotivationQuery</span>: <span class="hljs-title.class">EntityQuery</span> {
    
    <span class="hljs-keyword">func</span> <span class="hljs-title.function">suggestedEntities</span>() <span class="hljs-keyword">async</span> <span class="hljs-keyword">throws</span> -&gt; [<span class="hljs-type">MotivationEntity</span>] {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">try</span> <span class="hljs-keyword">await</span> fetchMotivations()
    }

    <span class="hljs-keyword">func</span> <span class="hljs-title.function">defaultResult</span>() <span class="hljs-keyword">async</span> -&gt; <span class="hljs-type">MotivationEntity</span>? {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">try?</span> <span class="hljs-keyword">await</span> fetchMotivations().first
    }

    <span class="hljs-keyword">func</span> <span class="hljs-title.function">entities</span>(<span class="hljs-params">for</span> <span class="hljs-params">identifiers</span>: [<span class="hljs-type">String</span>]) <span class="hljs-keyword">async</span> <span class="hljs-keyword">throws</span> -&gt; [<span class="hljs-type">MotivationEntity</span>] {
        <span class="hljs-keyword">let</span> motivations <span class="hljs-operator">=</span> <span class="hljs-keyword">try</span> <span class="hljs-keyword">await</span> fetchMotivations()
        <span class="hljs-keyword">return</span> motivations.filter { identifiers.contains(<span class="hljs-variable">$0</span>.id) }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">func</span> <span class="hljs-title.function">fetchMotivations</span>() <span class="hljs-keyword">async</span> <span class="hljs-keyword">throws</span> -&gt; [<span class="hljs-type">MotivationEntity</span>] {
        <span class="hljs-keyword">let</span> container <span class="hljs-operator">=</span> <span class="hljs-keyword">try</span> <span class="hljs-type">ModelContainer</span>(for: <span class="hljs-type">Motivation</span>.<span class="hljs-keyword">self</span>)
        <span class="hljs-keyword">let</span> context <span class="hljs-operator">=</span> <span class="hljs-type">ModelContext</span>(container)
        <span class="hljs-keyword">let</span> results <span class="hljs-operator">=</span> <span class="hljs-keyword">try</span> context.fetch(<span class="hljs-type">FetchDescriptor</span>&lt;<span class="hljs-type">Motivation</span>&gt;())

        <span class="hljs-keyword">return</span> results.compactMap {
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> id <span class="hljs-operator">=</span> <span class="hljs-variable">$0</span>.id<span class="hljs-operator">?</span>.uuidString, <span class="hljs-keyword">let</span> message <span class="hljs-operator">=</span> <span class="hljs-variable">$0</span>.message <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span> }
            <span class="hljs-keyword">return</span> <span class="hljs-type">MotivationEntity</span>(id: id, message: message)
        }
    }
}</span><code class="" data-line=""></code></pre>
<h2 id="d791" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">4.3. Update the Intent Itself</h2>
<p id="0721" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Finally, let’s replace the default emoji parameter with our motivation selection.</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="4a0b" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph="">
<span class="hljs-keyword">struct</span> <span class="hljs-title.class">ConfigurationAppIntent</span>: <span class="hljs-title.class">WidgetConfigurationIntent</span> {
    
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> title: <span class="hljs-type">LocalizedStringResource</span> <span class="hljs-operator">=</span> <span class="hljs-string">"Choose Motivation"</span>
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> description <span class="hljs-operator">=</span> <span class="hljs-type">IntentDescription</span>(<span class="hljs-string">"Pick a motivation message to show in your widget."</span>)

    <span class="hljs-meta">@Parameter</span>(title: <span class="hljs-string">"Motivation"</span>)
    <span class="hljs-keyword">var</span> motivation: <span class="hljs-type">MotivationEntity</span>?
    
}</span></pre>
<p id="ffd0" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">Now, when users long-press your widget and tap “Edit,” they’ll see a dropdown list of motivational quotes directly pulled from your app’s database. However, to test this feature, we need to make some adjustments in our Configurable Widget to align with our new Intent.</p>
<h1 id="63f5" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">Step 5: Update the Widget Provider to Display Selected Motivation</h1>
<p>Users can now select a motivational message in the widget’s configuration screen using ConfigurationAppIntent. To display their selection, we need to update the actual widget logic in ConfigurableWidget.swift.</p>
<h2 id="12cb" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">Step 5.1: Update <code class="" data-line="">TimelineEntry</code></h2>
<p id="f017" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph=""><strong class="nk ho">SimpleEntry: TimelineEntry</strong> is a struct — the data model for a widget at a specific point in time.</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="4e72" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">struct</span> <span class="hljs-title.class">SimpleEntry</span>: <span class="hljs-title.class">TimelineEntry</span> {
    <span class="hljs-keyword">let</span> date: <span class="hljs-type">Date</span>
    <span class="hljs-keyword">let</span> configuration: <span class="hljs-type">ConfigurationAppIntent</span>
}</span></pre>
<h2 id="59eb" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">Step 5.2: Update AppIntentTimelineProvider</h2>
<p>This is your AppIntentTimelineProvider, which is responsible for creating placeholder, snapshot, and timeline entries. It serves as the central component of your widget, determining what content to display and when to display it to WidgetKit.</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="618a" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">struct</span> <span class="hljs-title.class">Provider</span>: <span class="hljs-title.class">AppIntentTimelineProvider</span> {

<span class="hljs-operator">...</span> }</span></pre>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="959b" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">func</span> <span class="hljs-title.function">placeholder</span>(<span class="hljs-params">in</span> <span class="hljs-params">context</span>: <span class="hljs-type">Context</span>) -&gt; <span class="hljs-type">SimpleEntry</span> {
    <span class="hljs-type">SimpleEntry</span>(date: .now, configuration: <span class="hljs-type">ConfigurationAppIntent</span>())
}</span></pre>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="099c" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">func</span> <span class="hljs-title.function">snapshot</span>(<span class="hljs-params">for</span> <span class="hljs-params">configuration</span>: <span class="hljs-type">ConfigurationAppIntent</span>, <span class="hljs-params">in</span> <span class="hljs-params">context</span>: <span class="hljs-type">Context</span>) <span class="hljs-keyword">async</span> -&gt; <span class="hljs-type">SimpleEntry</span> {
    <span class="hljs-type">SimpleEntry</span>(date: .now, configuration: configuration)
}</span></pre>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="bc5e" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">func</span> <span class="hljs-title.function">timeline</span>(<span class="hljs-params">for</span> <span class="hljs-params">configuration</span>: <span class="hljs-type">ConfigurationAppIntent</span>, <span class="hljs-params">in</span> <span class="hljs-params">context</span>: <span class="hljs-type">Context</span>) <span class="hljs-keyword">async</span> -&gt; <span class="hljs-type">Timeline</span>&lt;<span class="hljs-type">SimpleEntry</span>&gt; {
    <span class="hljs-keyword">let</span> entry <span class="hljs-operator">=</span> <span class="hljs-type">SimpleEntry</span>(date: .now, configuration: configuration)
    <span class="hljs-keyword">return</span> <span class="hljs-type">Timeline</span>(entries: [entry], policy: .never)
}</span></pre>
<h1 id="58f8" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">🖼 Step 6: Design the Widget View</h1>
<p>Now that your timeline provider is ready, let’s enhance the widget’s visual appeal. Our objective is to present the user-selected motivational quote in a clean and visually appealing layout.</p>
<h2 id="61d1" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">6.1 Update <code class="" data-line="">ConfigurableWidgetEntryView</code></h2>
<p id="aa4a" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">We’ll update the widget view to display:</p>
<ul class="">
<li id="ed42" class="ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa pz qa qb bk" data-selectable-paragraph="">A motivational message (from <code class="" data-line="">entry.configuration.motivation.message</code>)</li>
<li id="18cb" class="ni nj hn nk b il qc nm nn io qd np nq fi qe ns nt fl qf nv nw fo qg ny nz oa pz qa qb bk" data-selectable-paragraph="">A timestamp for when the widget was last refreshed (optional but helpful for debugging or dynamic updates later)</li>
</ul>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="4053" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-comment">/// The actual content shown in the widget on the Home Screen</span>
<span class="hljs-keyword">struct</span> <span class="hljs-title.class">ConfigurableWidgetEntryView</span>: <span class="hljs-title.class">View</span> {
   
    <span class="hljs-keyword">var</span> entry: <span class="hljs-type">Provider</span>.<span class="hljs-type">Entry</span>

    <span class="hljs-keyword">var</span> body: <span class="hljs-keyword">some</span> <span class="hljs-type">View</span> {
        <span class="hljs-type">ZStack</span> {

            <span class="hljs-type">VStack</span>(alignment: .leading, spacing: <span class="hljs-number">8</span>) {
                <span class="hljs-comment">// Main motivation text</span>
                <span class="hljs-type">Text</span>(entry.configuration.motivation<span class="hljs-operator">?</span>.message <span class="hljs-operator">??</span> <span class="hljs-string">"Test"</span>)
                    .font(.headline)
                    .lineLimit(<span class="hljs-number">3</span>)
                    .minimumScaleFactor(<span class="hljs-number">0.5</span>)
                    .bold()
                    .multilineTextAlignment(.leading)

                <span class="hljs-type">Spacer</span>()

                <span class="hljs-comment">// Optional timestamp (can remove in production)</span>
                <span class="hljs-type">Text</span>(entry.date, style: .time)
                    .font(.caption2)
                    .foregroundStyle(.gray)
            }
            .padding()
        }
    }
    
}</span><code class="" data-line=""></code></pre>
<h2 id="1374" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">6.2 <code class="" data-line="">ConfigurableWidget</code> Definition — Widget</h2>
<p id="213a" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">ConfigurableWidget struct registers your widget with the system, connecting your Provider, ConfigurableWidgetEntryView, and ConfigurationAppIntent.</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="fa5c" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">struct</span> <span class="hljs-title.class">ConfigurableWidget</span>: <span class="hljs-title.class">Widget</span> {
    
    <span class="hljs-keyword">let</span> kind: <span class="hljs-type">String</span> <span class="hljs-operator">=</span> <span class="hljs-string">"ConfigurableWidget"</span>

    <span class="hljs-keyword">var</span> body: <span class="hljs-keyword">some</span> <span class="hljs-type">WidgetConfiguration</span> {
        <span class="hljs-type">AppIntentConfiguration</span>(
            kind: kind,
            intent: <span class="hljs-type">ConfigurationAppIntent</span>.<span class="hljs-keyword">self</span>,
            provider: <span class="hljs-type">Provider</span>()
        ) { entry <span class="hljs-keyword">in</span>
            <span class="hljs-type">ConfigurableWidgetEntryView</span>(entry: entry)
                .containerBackground(<span class="hljs-type">Color</span>(.systemBackground), for: .widget)
        }
    }
    
}</span></pre>
<h2 id="5dba" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">6.3 Widget Preview With Motivation Entities</h2>
<p id="7bb9" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Update the widget preview block to use the sample motivations:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="2347" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph="">#<span class="hljs-type">Preview</span>(as: .systemSmall) {
    <span class="hljs-type">ConfigurableWidget</span>()
} timeline: {
    <span class="hljs-type">SimpleEntry</span>(date: .now, configuration: .sampleMotivation1)
    <span class="hljs-type">SimpleEntry</span>(date: .now, configuration: .sampleMotivation2)
}</span></pre>
<pre class="gm qi oe qj bp qk bb bk"><span id="0e38" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">extension</span> <span class="hljs-title.class">ConfigurationAppIntent</span> {
    
    <span class="hljs-comment">/// Sample configuration using a fake MotivationEntity</span>
    <span class="hljs-keyword">fileprivate</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> sampleMotivation1: <span class="hljs-type">ConfigurationAppIntent</span> {
        <span class="hljs-keyword">let</span> intent <span class="hljs-operator">=</span> <span class="hljs-type">ConfigurationAppIntent</span>()
        intent.motivation <span class="hljs-operator">=</span> <span class="hljs-type">MotivationEntity</span>(
            id: <span class="hljs-type">UUID</span>().uuidString,
            message: <span class="hljs-string">"Push beyond limits."</span>
        )
        <span class="hljs-keyword">return</span> intent
    }

    <span class="hljs-keyword">fileprivate</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> sampleMotivation2: <span class="hljs-type">ConfigurationAppIntent</span> {
        <span class="hljs-keyword">let</span> intent <span class="hljs-operator">=</span> <span class="hljs-type">ConfigurationAppIntent</span>()
        intent.motivation <span class="hljs-operator">=</span> <span class="hljs-type">MotivationEntity</span>(
            id: <span class="hljs-type">UUID</span>().uuidString,
            message: <span class="hljs-string">"The future is yours to shape."</span>
        )
        <span class="hljs-keyword">return</span> intent
    }
}</span></pre>
<h1 id="4fb6" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">Step 7: Test the Widget in Simulator (and Improve Selection UI)</h1>
<p id="da85" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Before we refine the widget configuration UI, test your widget setup in the Simulator to ensure everything functions correctly.</p>
<h1 id="74ec" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">🔍 How to Test in Simulator</h1>
<ol class="">
<li id="a8cd" class="ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa qv qa qb bk" data-selectable-paragraph=""><strong class="nk ho">Run your app first</strong> to populate SwiftData with some motivations.</li>
<li id="9096" class="ni nj hn nk b il qc nm nn io qd np nq fi qe ns nt fl qf nv nw fo qg ny nz oa qv qa qb bk" data-selectable-paragraph=""><strong class="nk ho">Long-press the Home Screen</strong> in the Simulator.</li>
<li id="b798" class="ni nj hn nk b il qc nm nn io qd np nq fi qe ns nt fl qf nv nw fo qg ny nz oa qv qa qb bk" data-selectable-paragraph="">Tap <strong class="nk ho">“+” (Add Widget)</strong> → choose your widget → <strong class="nk ho">Add to Home Screen</strong>.</li>
<li id="565f" class="ni nj hn nk b il qc nm nn io qd np nq fi qe ns nt fl qf nv nw fo qg ny nz oa qv qa qb bk" data-selectable-paragraph=""><strong class="nk ho">Tap and hold the widget</strong>, choose <strong class="nk ho">Edit</strong>, and you’ll see the motivational message dropdown.</li>
</ol>
<figure class="or os ot ou ov ow oo op paragraph-image"></figure>
<p>Right now, the widget configuration uses the default dropdown UI, which works well, but it becomes cumbersome and difficult to search when you have numerous motivation entries.</p>
<p>To address this issue, we aim to enhance the configuration panel by implementing the following changes:</p>
<p>&#8211; Displaying motivations in a popup list.</p>
<p>&#8211; Enabling a search bar.</p>
<h1 id="08e9" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">Step 8: Enable Searchable Picker for MotivationEntity</h1>
<p id="0a8d" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">To enable a searchable experience within the widget configuration, we must update the MotivationQuery to support live filtering.</p>
<p id="0a8d" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Firstly, ensure that your query struct adheres to the EntityStringQuery protocol, not just the EntityQuery protocol. Modify the declaration accordingly:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="5030" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">struct</span> <span class="hljs-title.class">MotivationQuery</span>: <span class="hljs-title.class">EntityStringQuery</span> {</span></pre>
<p id="2f64" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">Then, implement the required <code class="" data-line="">entities(matching:)</code> method to support real-time search:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="49a7" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph="">    <span class="hljs-keyword">func</span> <span class="hljs-title.function">entities</span>(<span class="hljs-params">matching</span> <span class="hljs-params">string</span>: <span class="hljs-type">String</span>) <span class="hljs-keyword">async</span> <span class="hljs-keyword">throws</span> -&gt; [<span class="hljs-type">MotivationEntity</span>] {
          <span class="hljs-keyword">let</span> motivations <span class="hljs-operator">=</span> <span class="hljs-keyword">try</span> <span class="hljs-keyword">await</span> fetchMotivations()
          <span class="hljs-keyword">return</span> motivations.filter {
              <span class="hljs-variable">$0</span>.message.localizedCaseInsensitiveContains(string)
          }
      }</span></pre>
<p id="ae68" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">Rebuild the app, run it in the simulator or on a physical device, and edit your widget. As you type in the Motivation field, the results should now appear in real time.</p>
<h1 id="19fe" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">🎨 Step 9: Add Custom Background Color and Favorite Toggle</h1>
<p id="92b5" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">To make your widget more personalized, let’s give users control over the following:</p>
<p id="92b5" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">&#8211; Custom background color (stored in SwiftData)</p>
<p id="92b5" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">&#8211; Marking a motivation as a favorite</p>
<h2 id="fbb7" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">9.1: Update the SwiftData Model</h2>
<p id="0b4b" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Open <code class="" data-line="">Motivation.swift</code> and update the model:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="8835" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-meta">@Model</span>
<span class="hljs-keyword">final</span> <span class="hljs-keyword">class</span> <span class="hljs-title.class">Motivation</span>: <span class="hljs-title.class">Identifiable</span> {
    
    <span class="hljs-keyword">var</span> id: <span class="hljs-type">String</span>?
    <span class="hljs-keyword">var</span> message: <span class="hljs-type">String</span>?
    <span class="hljs-keyword">var</span> timestamp: <span class="hljs-type">Date</span>?
    
    <span class="hljs-keyword">var</span> isFavorite: <span class="hljs-type">Bool</span>?
    <span class="hljs-keyword">var</span> backgroundColorHex: <span class="hljs-type">String</span>?

    <span class="hljs-keyword">init</span>(<span class="hljs-params">message</span>: <span class="hljs-type">String</span>?, <span class="hljs-params">timestamp</span>: <span class="hljs-type">Date</span> <span class="hljs-operator">=</span> .now, <span class="hljs-params">isFavorite</span>: <span class="hljs-type">Bool</span> <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>, <span class="hljs-params">backgroundColorHex</span>: <span class="hljs-type">String</span>? <span class="hljs-operator">=</span> <span class="hljs-literal">nil</span>) {
        
        <span class="hljs-keyword">self</span>.id <span class="hljs-operator">=</span> <span class="hljs-type">UUID</span>().uuidString
        <span class="hljs-keyword">self</span>.message <span class="hljs-operator">=</span> message
        <span class="hljs-keyword">self</span>.timestamp <span class="hljs-operator">=</span> timestamp
        <span class="hljs-keyword">self</span>.isFavorite <span class="hljs-operator">=</span> isFavorite
        <span class="hljs-keyword">self</span>.backgroundColorHex <span class="hljs-operator">=</span> backgroundColorHex
        
    }
    
}</span></pre>
<h2 id="20c6" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">9.2 Update the MotivationEntity: AppEntity Wrapper</h2>
<p id="06ab" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Since the widget relies on <code class="" data-line="">MotivationEntity</code>, we’ll add these fields to pass to the widget:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="0a4b" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">struct</span> <span class="hljs-title.class">MotivationEntity</span>: <span class="hljs-title.class">AppEntity</span> {
    
    <span class="hljs-keyword">var</span> id: <span class="hljs-type">String</span>
    <span class="hljs-keyword">var</span> message: <span class="hljs-type">String</span>
    <span class="hljs-keyword">var</span> isFavorite: <span class="hljs-type">Bool</span>
    <span class="hljs-keyword">var</span> backgroundColorHex: <span class="hljs-type">String</span>?
    
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> typeDisplayRepresentation: <span class="hljs-type">TypeDisplayRepresentation</span> <span class="hljs-operator">=</span> <span class="hljs-string">"Motivation"</span>
   
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> defaultQuery <span class="hljs-operator">=</span> <span class="hljs-type">MotivationQuery</span>()
    
    <span class="hljs-keyword">var</span> displayRepresentation: <span class="hljs-type">DisplayRepresentation</span> {
        <span class="hljs-type">DisplayRepresentation</span>(
            title: <span class="hljs-type">LocalizedStringResource</span>(<span class="hljs-string">"<span class="hljs-subst">\(message)</span>"</span>),  
            subtitle: <span class="hljs-type">LocalizedStringResource</span>(isFavorite <span class="hljs-operator">?</span> <span class="hljs-string">"⭐️ <span class="hljs-subst">\(id)</span>"</span> : <span class="hljs-string">"<span class="hljs-subst">\(id)</span>"</span>)   
        )
    }
}</span></pre>
<h2 id="cd3f" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">9.3: Update fetchMotivations() Logic</h2>
<p id="64b8" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">In <code class="" data-line="">MotivationQuery</code>, update the conversion method to include the new properties:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="b7f4" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph="">        <span class="hljs-keyword">return</span> results.compactMap {
               <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> id <span class="hljs-operator">=</span> <span class="hljs-variable">$0</span>.id, <span class="hljs-keyword">let</span> message <span class="hljs-operator">=</span> <span class="hljs-variable">$0</span>.message <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span> }
               <span class="hljs-keyword">return</span> <span class="hljs-type">MotivationEntity</span>(
                   id: id,
                   message: message,
                   isFavorite: <span class="hljs-variable">$0</span>.isFavorite <span class="hljs-operator">??</span> <span class="hljs-literal">false</span>,
                   backgroundColorHex: <span class="hljs-variable">$0</span>.backgroundColorHex
               )
           }</span></pre>
<h2 id="bc00" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">9.4 Update Preview Samples for Widget Testing</h2>
<p id="d183" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">To test your widget with styled previews, update your <code class="" data-line="">.sampleMotivation1</code> and <code class="" data-line="">.sampleMotivation2</code> values:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="b927" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">extension</span> <span class="hljs-title.class">ConfigurationAppIntent</span> {
    
    <span class="hljs-comment">/// Preview: Configuration with sample motivation 1</span>
    <span class="hljs-keyword">fileprivate</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> sampleMotivation1: <span class="hljs-type">ConfigurationAppIntent</span> {
        <span class="hljs-keyword">let</span> intent <span class="hljs-operator">=</span> <span class="hljs-type">ConfigurationAppIntent</span>()
        intent.motivation <span class="hljs-operator">=</span> <span class="hljs-type">MotivationEntity</span>(
            id: <span class="hljs-type">UUID</span>().uuidString,
            message: <span class="hljs-string">"Push beyond limits."</span>, isFavorite: <span class="hljs-literal">true</span>, backgroundColorHex: <span class="hljs-string">"#D3D3D3"</span>
        )
        <span class="hljs-keyword">return</span> intent
    }

    <span class="hljs-comment">/// Preview: Configuration with sample motivation 2</span>
    <span class="hljs-keyword">fileprivate</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> sampleMotivation2: <span class="hljs-type">ConfigurationAppIntent</span> {
        <span class="hljs-keyword">let</span> intent <span class="hljs-operator">=</span> <span class="hljs-type">ConfigurationAppIntent</span>()
        intent.motivation <span class="hljs-operator">=</span> <span class="hljs-type">MotivationEntity</span>(
            id: <span class="hljs-type">UUID</span>().uuidString,
            message: <span class="hljs-string">"The future is yours to shape."</span>, isFavorite: <span class="hljs-literal">false</span>, backgroundColorHex: <span class="hljs-string">"#FFFFFF"</span>
        )
        <span class="hljs-keyword">return</span> intent
    }
}</span></pre>
<h2 id="26dd" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">9.5 Update the Widget View</h2>
<p id="5cfd" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Check the <code class="" data-line="">isFavorite</code> flag to display a star</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="33ce" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">struct</span> <span class="hljs-title.class">ConfigurableWidgetEntryView</span>: <span class="hljs-title.class">View</span> {
   
    <span class="hljs-keyword">var</span> entry: <span class="hljs-type">Provider</span>.<span class="hljs-type">Entry</span>

    <span class="hljs-keyword">var</span> body: <span class="hljs-keyword">some</span> <span class="hljs-type">View</span> {
        <span class="hljs-type">ZStack</span> {
            <span class="hljs-type">VStack</span>(alignment: .leading, spacing: <span class="hljs-number">8</span>) {

                <span class="hljs-comment">// Motivation message text (user-selected)</span>
                <span class="hljs-type">Text</span>(entry.configuration.motivation<span class="hljs-operator">?</span>.message <span class="hljs-operator">??</span> <span class="hljs-string">"Stay motivated!"</span>)
                    .font(.headline)
                    .lineLimit(<span class="hljs-number">3</span>)
                    .minimumScaleFactor(<span class="hljs-number">0.5</span>)
                    .bold()
                    .multilineTextAlignment(.leading)

                <span class="hljs-type">Spacer</span>()
                
                <span class="hljs-type">HStack</span> {
                    
                    <span class="hljs-comment">// Timestamp (optional: shows when widget was last updated)</span>
                    <span class="hljs-type">Text</span>(entry.date, style: .time)
                        .font(.caption2)
                        .foregroundStyle(.gray)
                    
                    <span class="hljs-type">Spacer</span>()
                    
                    <span class="hljs-keyword">if</span> entry.configuration.motivation<span class="hljs-operator">?</span>.isFavorite <span class="hljs-operator">==</span> <span class="hljs-literal">true</span> {
                                     <span class="hljs-type">Text</span>(<span class="hljs-string">"⭐️"</span>)
                                         .font(.caption)
                                         .foregroundStyle(.yellow)
                                 }
                    
                }
            }
            .padding()
        }
    }
}</span></pre>
<p id="1ad8" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">Create a new Helpers.swift file and add a Color extension to it, allowing you to create a Color from a String. Remember to check the Widget target for this file to ensure it’s visible within the Widgets Extension.</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="60a7" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">extension</span> <span class="hljs-title.class">Color</span> {
    <span class="hljs-keyword">init</span>(<span class="hljs-params">hex</span>: <span class="hljs-type">String</span>) {
        <span class="hljs-keyword">let</span> hex <span class="hljs-operator">=</span> hex.trimmingCharacters(in: <span class="hljs-type">CharacterSet</span>.alphanumerics.inverted)
        <span class="hljs-keyword">var</span> int <span class="hljs-operator">=</span> <span class="hljs-type">UInt64</span>()
        <span class="hljs-type">Scanner</span>(string: hex).scanHexInt64(<span class="hljs-operator">&amp;</span>int)
        
        <span class="hljs-keyword">let</span> r, g, b: <span class="hljs-type">UInt64</span>
        <span class="hljs-keyword">switch</span> hex.count {
        <span class="hljs-keyword">case</span> <span class="hljs-number">6</span>: <span class="hljs-comment">// RGB (24-bit)</span>
            (r, g, b) <span class="hljs-operator">=</span> ((int <span class="hljs-operator">&gt;&gt;</span> <span class="hljs-number">16</span>) <span class="hljs-operator">&amp;</span> <span class="hljs-number">0xFF</span>, (int <span class="hljs-operator">&gt;&gt;</span> <span class="hljs-number">8</span>) <span class="hljs-operator">&amp;</span> <span class="hljs-number">0xFF</span>, int <span class="hljs-operator">&amp;</span> <span class="hljs-number">0xFF</span>)
        <span class="hljs-keyword">default</span>:
            (r, g, b) <span class="hljs-operator">=</span> (<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>)
        }

        <span class="hljs-keyword">self</span>.<span class="hljs-keyword">init</span>(.sRGB, red: <span class="hljs-type">Double</span>(r) <span class="hljs-operator">/</span> <span class="hljs-number">255</span>, green: <span class="hljs-type">Double</span>(g) <span class="hljs-operator">/</span> <span class="hljs-number">255</span>, blue: <span class="hljs-type">Double</span>(b) <span class="hljs-operator">/</span> <span class="hljs-number">255</span>)
    }
}</span></pre>
<p id="d74e" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">Next, let’s make sure our widget uses the entity background</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="c4d6" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">struct</span> <span class="hljs-title.class">ConfigurableWidget</span>: <span class="hljs-title.class">Widget</span> {
    
    <span class="hljs-comment">// Unique identifier for this widget</span>
    <span class="hljs-keyword">let</span> kind: <span class="hljs-type">String</span> <span class="hljs-operator">=</span> <span class="hljs-string">"ConfigurableWidget"</span>

    <span class="hljs-keyword">var</span> body: <span class="hljs-keyword">some</span> <span class="hljs-type">WidgetConfiguration</span> {
        <span class="hljs-type">AppIntentConfiguration</span>(
            kind: kind,
            intent: <span class="hljs-type">ConfigurationAppIntent</span>.<span class="hljs-keyword">self</span>,  <span class="hljs-comment">// Our custom intent with motivation</span>
            provider: <span class="hljs-type">Provider</span>()                  <span class="hljs-comment">// The logic that supplies timeline entries</span>
        ) { entry <span class="hljs-keyword">in</span>
            <span class="hljs-type">ConfigurableWidgetEntryView</span>(entry: entry)
                .containerBackground(<span class="hljs-type">Color</span>(hex: entry.configuration.motivation<span class="hljs-operator">?</span>.backgroundColorHex <span class="hljs-operator">??</span> <span class="hljs-string">"#D3D3D3"</span>), for: .widget) 
        }
    }
}</span></pre>
<h1 id="ecab" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">🧭 Step 10: Display Favorites and Background Color in the Main App</h1>
<h2 id="598e" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">🔧 10.1 Update the List Row in <code class="" data-line="">ContentView.swift</code></h2>
<p id="9d8a" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Replace the <code class="" data-line="">VStack</code> for each motivation in your <code class="" data-line="">ForEach</code> block with this:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="0bb7" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""> <span class="hljs-type">ZStack</span> {
                            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> hex <span class="hljs-operator">=</span> motivation.backgroundColorHex {
                                <span class="hljs-type">Color</span>(hex: hex)                                    .cornerRadius(<span class="hljs-number">8</span>)
                            }

                                <span class="hljs-type">HStack</span> {
                                    
                                    <span class="hljs-type">VStack</span>(alignment: .leading, spacing: <span class="hljs-number">8</span>) {
                                        
                                        <span class="hljs-type">Text</span>(motivation.message <span class="hljs-operator">??</span> <span class="hljs-string">"No message"</span>)
                                            .font(.headline)
                                            .foregroundStyle(.primary)
                                        
                                        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> timestamp <span class="hljs-operator">=</span> motivation.timestamp {
                                            <span class="hljs-type">Text</span>(timestamp.formatted(date: .abbreviated, time: .shortened))
                                                .font(.caption)
                                                .foregroundStyle(.gray)
                                        }
                                        
                                    }
                                 
                                    <span class="hljs-type">Spacer</span>()
                                    
                                    <span class="hljs-keyword">if</span> motivation.isFavorite <span class="hljs-operator">==</span> <span class="hljs-literal">true</span> {
                                        <span class="hljs-type">Spacer</span>()
                                        <span class="hljs-type">Text</span>(<span class="hljs-string">"⭐️"</span>)
                                            .foregroundStyle(.yellow)
                                            .font(.headline)
                                    }
                                }
                                .background(<span class="hljs-type">Color</span>(hex: motivation.backgroundColorHex <span class="hljs-operator">??</span> <span class="hljs-string">"F1F1F1"</span>))

                               
                            .padding(<span class="hljs-number">20</span>)
                        }
                        .listRowInsets(<span class="hljs-type">EdgeInsets</span>())
                        .listRowBackground(<span class="hljs-type">Color</span>.clear)</span></pre>
<h1 id="89f8" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">Step 11: Add Background Color Picker to Each Row</h1>
<p id="ea8e" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">We’ll do 3 things:</p>
<ol class="">
<li id="4caa" class="ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa qv qa qb bk" data-selectable-paragraph="">Move the full row UI into a reusable <code class="" data-line="">MotivationRowView</code>.</li>
<li id="de2f" class="ni nj hn nk b il qc nm nn io qd np nq fi qe ns nt fl qf nv nw fo qg ny nz oa qv qa qb bk" data-selectable-paragraph="">Show a <code class="" data-line="">ColorPicker</code> inline inside each row.</li>
<li id="55e1" class="ni nj hn nk b il qc nm nn io qd np nq fi qe ns nt fl qf nv nw fo qg ny nz oa qv qa qb bk" data-selectable-paragraph="">Save the picked color as a hex string to SwiftData.</li>
</ol>
<h2 id="b4d6" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">🔧 11.1 Create a Row View</h2>
<p id="910b" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">In a new file (or below <code class="" data-line="">ContentView</code>), create this:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="98f6" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">struct</span> <span class="hljs-title.class">MotivationRowView</span>: <span class="hljs-title.class">View</span> {
    <span class="hljs-meta">@Bindable</span> <span class="hljs-keyword">var</span> motivation: <span class="hljs-type">Motivation</span>
    <span class="hljs-meta">@Environment</span>(\.modelContext) <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> modelContext

    <span class="hljs-keyword">var</span> body: <span class="hljs-keyword">some</span> <span class="hljs-type">View</span> {
        <span class="hljs-type">VStack</span>(alignment: .leading, spacing: <span class="hljs-number">6</span>) {
            <span class="hljs-type">HStack</span> {
                <span class="hljs-type">Text</span>(motivation.message <span class="hljs-operator">??</span> <span class="hljs-string">"No message"</span>)
                    .font(.headline)
                    .foregroundStyle(.primary)
                    .lineLimit(<span class="hljs-number">2</span>)

                <span class="hljs-keyword">if</span> motivation.isFavorite <span class="hljs-operator">==</span> <span class="hljs-literal">true</span> {
                    <span class="hljs-type">Spacer</span>()
                    <span class="hljs-type">Text</span>(<span class="hljs-string">"⭐️"</span>)
                        .foregroundStyle(.yellow)
                }
            }

            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> timestamp <span class="hljs-operator">=</span> motivation.timestamp {
                <span class="hljs-type">Text</span>(timestamp.formatted(date: .abbreviated, time: .shortened))
                    .font(.caption)
                    .foregroundStyle(.gray)
            }

            <span class="hljs-comment">// Inline Color Picker</span>
            <span class="hljs-type">ColorPicker</span>(motivation.backgroundColorHex <span class="hljs-operator">??</span> <span class="hljs-string">"#FFFFFF"</span>, selection: <span class="hljs-type">Binding</span>(
                get: {
                    <span class="hljs-type">Color</span>(hex: motivation.backgroundColorHex <span class="hljs-operator">??</span> <span class="hljs-string">"#FFFFFF"</span>)
                },
                set: { newColor <span class="hljs-keyword">in</span>
                    motivation.backgroundColorHex <span class="hljs-operator">=</span> newColor.toHex()
                    <span class="hljs-keyword">try?</span> modelContext.save()
                }
            ))
            .font(.caption)
        }
        .padding()
        .background(
            <span class="hljs-type">Color</span>(hex: motivation.backgroundColorHex <span class="hljs-operator">??</span> <span class="hljs-string">"#F2F2F7"</span>)
                .cornerRadius(<span class="hljs-number">10</span>)
        )
    }
}</span></pre>
<h2 id="4081" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">📦 11.2 Update <code class="" data-line="">ContentView.swift</code></h2>
<p id="b2a0" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Replace your <code class="" data-line="">ForEach</code> block with this:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="13b7" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-type">ForEach</span>(<span class="hljs-variable">$motivations</span>) { <span class="hljs-variable">$motivation</span> <span class="hljs-keyword">in</span>
     <span class="hljs-type">MotivationRowView</span>(motivation: motivation)
                        .listRowBackground(<span class="hljs-type">Color</span>.clear)
}
.onDelete(perform: deleteItems)</span></pre>
<h2 id="8f3f" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">🧩 11.3 Add <code class="" data-line="">Color.toHex()</code> Extension</h2>
<p id="1be7" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">In <code class="" data-line="">Helpers.swift</code> (shared with widget), add:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="8f64" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph="">   <span class="hljs-keyword">func</span> <span class="hljs-title.function">toHex</span>() -&gt; <span class="hljs-type">String</span> {
        <span class="hljs-keyword">let</span> uiColor <span class="hljs-operator">=</span> <span class="hljs-type">UIColor</span>(<span class="hljs-keyword">self</span>)
        <span class="hljs-keyword">var</span> r: <span class="hljs-type">CGFloat</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>, g: <span class="hljs-type">CGFloat</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>, b: <span class="hljs-type">CGFloat</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>, a: <span class="hljs-type">CGFloat</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>
        uiColor.getRed(<span class="hljs-operator">&amp;</span>r, green: <span class="hljs-operator">&amp;</span>g, blue: <span class="hljs-operator">&amp;</span>b, alpha: <span class="hljs-operator">&amp;</span>a)
        <span class="hljs-keyword">return</span> <span class="hljs-type">String</span>(format: <span class="hljs-string">"#%02X%02X%02X"</span>, <span class="hljs-type">Int</span>(r <span class="hljs-operator">*</span> <span class="hljs-number">255</span>), <span class="hljs-type">Int</span>(g <span class="hljs-operator">*</span> <span class="hljs-number">255</span>), <span class="hljs-type">Int</span>(b <span class="hljs-operator">*</span> <span class="hljs-number">255</span>))
    }</span></pre>
<h1 id="df75" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">Step 12: Test it and force Updates</h1>
<p id="111a" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Delete the app, create 4 new Motivations and set colors to Yellow, Green, Red, Blue inside the app. After that create 4 widgets for these 4 motivations. Works great right.</p>
<figure class="or os ot ou ov ow oo op paragraph-image">
<div class="ox oy dy oz bh pa" tabindex="0" role="button"></div>
</figure>
<h1 id="e8fe" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">Manually Reload the Widget Timeline</h1>
<ul class="">
<li id="cec6" class="ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa pz qa qb bk" data-selectable-paragraph="">Tell WidgetKit to reload the timeline of our widget whenever a Motivation is updated.</li>
<li id="89c2" class="ni nj hn nk b il qc nm nn io qd np nq fi qe ns nt fl qf nv nw fo qg ny nz oa pz qa qb bk" data-selectable-paragraph="">Trigger this in a clean and efficient way inside SwiftUI, <strong class="nk ho">every time a user picks a new color</strong> (or you update any field).</li>
</ul>
<h2 id="d651" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">🛠 Trigger Timeline Reload on Color Change</h2>
<p id="c448" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Update the <code class="" data-line="">ColorPicker</code> binding’s setter:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="5378" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-type">ColorPicker</span>(<span class="hljs-string">"Background Color"</span>, selection: <span class="hljs-type">Binding</span>(
    get: {
        <span class="hljs-type">Color</span>(hex: motivation.backgroundColorHex <span class="hljs-operator">??</span> <span class="hljs-string">"#FFFFFF"</span>)
    },
    set: { newColor <span class="hljs-keyword">in</span>
        motivation.backgroundColorHex <span class="hljs-operator">=</span> newColor.toHex()
        <span class="hljs-keyword">try?</span> modelContext.save()

        <span class="hljs-comment">// Reload widget</span>
        <span class="hljs-type">WidgetCenter</span>.shared.reloadAllTimelines()
    }
))
.font(.caption)</span></pre>
<p id="317f" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">Repeat this pattern for any other motivation updates that will appear in the future</p>
<h2 id="d329" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">🔄 Optional: Refresh on App Become Active</h2>
<p id="ef5f" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">You can also call: <code class="" data-line="">WidgetCenter.shared.reloadAllTimelines()</code>inside <code class="" data-line="">onChange(of: scenePhase)</code> in your <code class="" data-line="">App</code> :</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="5373" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph="">.onChange(of: scenePhase) { oldPhase, newPhase <span class="hljs-keyword">in</span>
            
            <span class="hljs-keyword">if</span> newPhase <span class="hljs-operator">==</span> .background { 
                
                <span class="hljs-comment">// Optional</span>
                <span class="hljs-type">WidgetCenter</span>.shared.reloadAllTimelines()
            }
            
        }</span></pre>
<p id="c04d" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">If your app becomes more complex, consider calling: <code class="" data-line="">WidgetCenter.shared.reloadTimelines(ofKind: “ConfigurableWidget”)</code> instead of <code class="" data-line="">.reloadAllTimelines()</code> to avoid refreshing other widgets unnecessarily.</p>
<h1 id="74f5" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">⭐️ Step 13: Make the “Favorite” Toggle Configurable from the Widget</h1>
<p>Let’s take your configurable widget to the next level by enabling users to toggle the “Favorite” status directly from the widget itself. This feature synchronizes the change with your SwiftData model shared with the main app, providing powerful bidirectional control and enhancing the user experience.</p>
<p>Previously, widget configuration was limited to reading from SwiftData. Now, we’re introducing write-back capabilities. When a user taps the star button in the widget, it will toggle the favorite status and persist the change to SwiftData. Consequently, the app UI and the widget will automatically update with the changes.</p>
<h3>🧱 13.1 Add a Shared SwiftData Container</h3>
<p>To enable the widget extension to write to your SwiftData store, create a singleton container shared via App Group.</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="8e90" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-comment">// MARK: - Shared Model Container</span>
<span class="hljs-comment">/// Singleton container for shared access across app and widget</span>
<span class="hljs-keyword">class</span> <span class="hljs-title.class">SharedModelContainer</span> {
    
   <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> shared <span class="hljs-operator">=</span> <span class="hljs-type">SharedModelContainer</span>()
   
   <span class="hljs-keyword">let</span> container: <span class="hljs-type">ModelContainer</span>
   
   <span class="hljs-keyword">private</span> <span class="hljs-keyword">init</span>() {
       <span class="hljs-comment">// Configure the container for shared access via App Group</span>
       <span class="hljs-keyword">let</span> schema <span class="hljs-operator">=</span> <span class="hljs-type">Schema</span>([<span class="hljs-type">Motivation</span>.<span class="hljs-keyword">self</span>])
       <span class="hljs-keyword">let</span> modelConfiguration <span class="hljs-operator">=</span> <span class="hljs-type">ModelConfiguration</span>(schema: schema, groupContainer: .identifier(<span class="hljs-string">"group.com.adelmaer.ConfigurableWidgetsApp"</span>))
       
       <span class="hljs-keyword">do</span> {
           container <span class="hljs-operator">=</span> <span class="hljs-keyword">try</span> <span class="hljs-type">ModelContainer</span>(for: schema, configurations: modelConfiguration)
       } <span class="hljs-keyword">catch</span> {
           <span class="hljs-built_in">fatalError</span>(<span class="hljs-string">"Could not create ModelContainer: <span class="hljs-subst">\(error)</span>"</span>)
       }
   }
}</span></pre>
<p id="7979" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">Next, within your main application add <code class="" data-line="">.modelContainer(SharedModelContainer.shared.container)</code></p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="2cf3" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">import</span> SwiftUI
<span class="hljs-keyword">import</span> SwiftData
<span class="hljs-keyword">import</span> WidgetKit

<span class="hljs-keyword">@main</span>
<span class="hljs-keyword">struct</span> <span class="hljs-title.class">ConfigurableWidgetsAppApp</span>: <span class="hljs-title.class">App</span> {
    
    <span class="hljs-meta">@Environment</span>(\.scenePhase) <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> scenePhase

    <span class="hljs-keyword">var</span> body: <span class="hljs-keyword">some</span> <span class="hljs-type">Scene</span> {
        <span class="hljs-type">WindowGroup</span> {
            <span class="hljs-type">ContentView</span>()
        }
        .modelContainer(<span class="hljs-type">SharedModelContainer</span>.shared.container)
        .onChange(of: scenePhase) { <span class="hljs-keyword">_</span>, newPhase <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">if</span> newPhase <span class="hljs-operator">==</span> .background {
                <span class="hljs-type">WidgetCenter</span>.shared.reloadAllTimelines()
            }
        }
    }
}</span></pre>
<p id="fe16" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">This ensures both the app and widget share the same SwiftData storage, keeping everything in sync.</p>
<h2 id="7492" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">🧠 13.2 Create an AppIntent to Toggle Favorite</h2>
<p id="8476" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">We’ll now create a standalone intent that, when the user taps the star icon in the widget, toggles the favorite status. This intent retrieves data from SwiftData using the shared model container, toggles the isFavorite field, and saves the result. AppIntent is a protocol in Swift that defines actions an app can perform, allowing interaction with system features like widgets and shortcuts.</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="a993" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph="">
<span class="hljs-keyword">struct</span> <span class="hljs-title.class">ToggleMotivationIsFavoriteIntent</span>: <span class="hljs-title.class">AppIntent</span> {
    
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> title: <span class="hljs-type">LocalizedStringResource</span> <span class="hljs-operator">=</span> <span class="hljs-string">"Toggle Favorite Status"</span>
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> description <span class="hljs-operator">=</span> <span class="hljs-type">IntentDescription</span>(<span class="hljs-string">"Toggle favorite status for a motivation message"</span>)
    
    <span class="hljs-meta">@Parameter</span>(title: <span class="hljs-string">"Motivation"</span>)
    <span class="hljs-keyword">var</span> motivation: <span class="hljs-type">MotivationEntity</span>
    
    <span class="hljs-keyword">init</span>(<span class="hljs-params">motivation</span>: <span class="hljs-type">MotivationEntity</span>) {
          <span class="hljs-keyword">self</span>.motivation <span class="hljs-operator">=</span> motivation
      }

    <span class="hljs-keyword">init</span>() {}

    <span class="hljs-keyword">func</span> <span class="hljs-title.function">perform</span>() <span class="hljs-keyword">async</span> <span class="hljs-keyword">throws</span> -&gt; <span class="hljs-keyword">some</span> <span class="hljs-type">IntentResult</span> {
       
        <span class="hljs-keyword">let</span> modelContext <span class="hljs-operator">=</span> <span class="hljs-type">ModelContext</span>(<span class="hljs-type">SharedModelContainer</span>.shared.container)
        <span class="hljs-keyword">let</span> id <span class="hljs-operator">=</span> motivation.id
        
        <span class="hljs-comment">// Find and update the motivation</span>
        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> motivation <span class="hljs-operator">=</span> <span class="hljs-keyword">try!</span> modelContext.fetch(
            <span class="hljs-type">FetchDescriptor</span>&lt;<span class="hljs-type">Motivation</span>&gt;(
                predicate: #<span class="hljs-type">Predicate</span> { <span class="hljs-variable">$0</span>.id <span class="hljs-operator">==</span> id }
            )).first <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> .result()
        }
        
        <span class="hljs-comment">// Toggle favorite status</span>
        motivation.isFavorite <span class="hljs-operator">=</span> <span class="hljs-operator">!</span>(motivation.isFavorite <span class="hljs-operator">??</span> <span class="hljs-literal">false</span>)
        
        <span class="hljs-comment">// Save changes</span>
        <span class="hljs-keyword">try?</span> modelContext.save()
        
        <span class="hljs-comment">// Refresh widget</span>
        <span class="hljs-type">WidgetCenter</span>.shared.reloadAllTimelines()
        
        <span class="hljs-keyword">return</span> .result()
  
    }

}</span></pre>
<h2 id="158f" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">⭐️ 13.3 Add a Star Toggle Button to the Widget</h2>
<p id="3ccc" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Now add a custom button view to trigger the intent:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="137c" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph="">
<span class="hljs-keyword">struct</span> <span class="hljs-title.class">ToggleFavoriteButton</span>: <span class="hljs-title.class">View</span> {
    <span class="hljs-keyword">let</span> motivation: <span class="hljs-type">MotivationEntity</span>
    
    <span class="hljs-keyword">var</span> body: <span class="hljs-keyword">some</span> <span class="hljs-type">View</span> {
        <span class="hljs-type">Button</span>(
            intent: <span class="hljs-type">ToggleMotivationIsFavoriteIntent</span>(motivation: motivation)
        ) {
            <span class="hljs-type">Image</span>(systemName: motivation.isFavorite <span class="hljs-operator">?</span> <span class="hljs-string">"star.fill"</span> : <span class="hljs-string">"star"</span>)
                .foregroundStyle(motivation.isFavorite <span class="hljs-operator">?</span> .yellow : .gray)
                .contentTransition(.symbolEffect(.replace))
        }
        .buttonStyle(.plain)
    }
    
}</span></pre>
<h2 id="55ff" class="of og hn bf oh fc oi fd fe ff oj fg fh fi ok fj fk fl ol fm fn fo om fp fq on bk" data-selectable-paragraph="">🎨 13.4 Integrate ToggleFavoriteButton Into the Widget View</h2>
<p id="f1bf" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Inside your <code class="" data-line="">ConfigurableWidgetEntryView</code>, update the UI to conditionally show the star toggle if a motivation was selected:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="9989" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> motivation <span class="hljs-operator">=</span> entry.configuration.motivation {
    <span class="hljs-type">ToggleFavoriteButton</span>(motivation: motivation)
}</span></pre>
<p id="2d61" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">This allows users to mark a message as a favorite directly from the widget by tapping the star — no app opening needed.</p>
<h1 id="da36" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">⭐️ Step 14: Add a Show/Hide Timestamp Toggle to Widget Configuration</h1>
<p id="2627" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Do you want to give users complete control over the widget’s appearance? If so, let’s add a new toggle in the configuration screen that allows users to choose whether to display or hide the timestamp.</p>
<h1 id="6a64" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">🧱 14.1 Update the ConfigurationAppIntent</h1>
<p id="b8e9" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Open <code class="" data-line="">AppIntent.swift</code> and update your <code class="" data-line="">ConfigurationAppIntent</code>:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="a634" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">struct</span> <span class="hljs-title.class">ConfigurationAppIntent</span>: <span class="hljs-title.class">WidgetConfigurationIntent</span> {
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> title: <span class="hljs-type">LocalizedStringResource</span> <span class="hljs-operator">=</span> <span class="hljs-string">"Choose Motivation"</span>
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> description <span class="hljs-operator">=</span> <span class="hljs-type">IntentDescription</span>(<span class="hljs-string">"Pick a motivation message to show in your widget."</span>)

    <span class="hljs-meta">@Parameter</span>(title: <span class="hljs-string">"Motivation"</span>)
    <span class="hljs-keyword">var</span> motivation: <span class="hljs-type">MotivationEntity</span>?

    <span class="hljs-meta">@Parameter</span>(title: <span class="hljs-string">"Show Timestamp"</span>)
    <span class="hljs-keyword">var</span> showTimestamp: <span class="hljs-type">Bool</span>?
}</span></pre>
<p id="90d0" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">By adding <code class="" data-line="">showTimestamp</code>, the user will now see a toggle when editing the widget.</p>
<h1 id="abc4" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">🧠 14.2 Update the Widget Entry and View</h1>
<p id="45f5" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Since SimpleEntry now includes the showTimestamp feature, you’re already passing configuration into it. Therefore, you need to update your view to respond accordingly.</p>
<p id="45f5" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">In ConfigurableWidgetEntryView.swift, update this block:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="4232" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph=""><span class="hljs-keyword">if</span> entry.configuration.showTimestamp <span class="hljs-operator">??</span> <span class="hljs-literal">false</span> {
    <span class="hljs-type">Text</span>(entry.date, style: .time)
        .font(.caption2)
        .foregroundStyle(.gray)
}</span></pre>
<p id="aa0f" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph="">This conditionally displays the timestamp only when <code class="" data-line="">showTimestamp</code> is enabled.</p>
<h1 id="f536" class="pc og hn bf oh pd pe in fe pf pg iq fh ph pi pj pk pl pm pn po pp pq pr ps pt bk" data-selectable-paragraph="">🧪 14.3 Update Widget Previews</h1>
<p id="00bd" class="pw-post-body-paragraph ni nj hn nk b il pu nm nn io pv np nq fi pw ns nt fl px nv nw fo py ny nz oa gp bk" data-selectable-paragraph="">Update your <code class="" data-line="">sampleMotivation1</code> and <code class="" data-line="">sampleMotivation2</code> preview values to test this:</p>
<pre class="or os ot ou ov qi oe qj bp qk bb bk"><span id="20a8" class="ql og hn oe b bg qm qn m qo qp" data-selectable-paragraph="">    <span class="hljs-comment">/// Preview: Configuration with sample motivation 1</span>
    <span class="hljs-keyword">fileprivate</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> sampleMotivation1: <span class="hljs-type">ConfigurationAppIntent</span> {
        <span class="hljs-keyword">let</span> intent <span class="hljs-operator">=</span> <span class="hljs-type">ConfigurationAppIntent</span>()
        intent.motivation <span class="hljs-operator">=</span> <span class="hljs-type">MotivationEntity</span>(
            id: <span class="hljs-type">UUID</span>().uuidString,
            message: <span class="hljs-string">"Push beyond limits."</span>,
            isFavorite: <span class="hljs-literal">true</span>,
            backgroundColorHex: <span class="hljs-string">"#D3D3D3"</span>
        )
        intent.showTimestamp <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>
        <span class="hljs-keyword">return</span> intent
    }</span></pre>
<p>✅ App Groups are required for shared data widgets (e.g., SwiftData + AppIntent + AppEntity) — like the one we built.</p>
<p>✅ Your iPhone must be running iOS 14 or later (iOS 17+ recommended for best performance and widget interaction).</p>
<p><a href="https://appmakers.gumroad.com/l/swiftui-widget-swiftdata-appintents-configurable">📦 Download the Code 📥</a></p>
<p>Want to support this SwiftUI learning journey or get the full commented source code for this Tutorial? Consider purchasing the complete example.</p>
<p>It includes:</p>
<p>SwiftData + WidgetKit integration</p>
<p>AppIntent + AppEntity patterns</p>
<p>Color + favorite + timestamp configuration</p>
</div>
</div>
</div>
<div class="gp go hi hj hk">
<div class="ac cb">
<div class="ci bh gv gw gx gy">
<p id="ebab" class="pw-post-body-paragraph ni nj hn nk b il nl nm nn io no np nq fi nr ns nt fl nu nv nw fo nx ny nz oa gp bk" data-selectable-paragraph=""><a class="ag gn" href="https://appmakers.gumroad.com/l/swiftui-widget-swiftdata-appintents-configurable" target="_blank" rel="noopener ugc nofollow">📥 <strong class="nk ho">DOWNLOAD SOURCE CODE for this Tutorial</strong></a></p>
</div>
</div>
</div>
<p>The post <a href="https://appmakers.dev/how-to-build-a-swiftui-widget-with-app-intents-and-swiftdata-configurable-widget/">How to Build a SwiftUI Widget with App Intents and SwiftData ( Configurable Widget )</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Build Your First Widget in SwiftUI — A Guide with Source Code</title>
		<link>https://appmakers.dev/build-your-first-widget-in-swiftui-a-guide-with-source-code/</link>
		
		<dc:creator><![CDATA[AppMakers]]></dc:creator>
		<pubDate>Mon, 09 Jun 2025 21:17:47 +0000</pubDate>
				<category><![CDATA[iOS Development]]></category>
		<category><![CDATA[Source Code]]></category>
		<category><![CDATA[SwiftUI]]></category>
		<category><![CDATA[SwiftUI Tutorials]]></category>
		<category><![CDATA[SwiftUI Widgets]]></category>
		<guid isPermaLink="false">https://appmakers.dev/?p=1985</guid>

					<description><![CDATA[<p>Want to bring widgets to your SwiftUI app but not sure where to begin? This updated tutorial walks you through the entire process of creating a SwiftUI Widget using WidgetKit, complete with step-by-step guidance and working code. By the end, you’ll have a motivational widget that refreshes every 10 minutes with custom colors and messages.&#8230;</p>
<p>The post <a href="https://appmakers.dev/build-your-first-widget-in-swiftui-a-guide-with-source-code/">Build Your First Widget in SwiftUI — A Guide with Source Code</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Want to bring widgets to your SwiftUI app but not sure where to begin? This updated tutorial walks you through the entire process of creating a SwiftUI Widget using WidgetKit, complete with step-by-step guidance and working code. By the end, you’ll have a motivational widget that refreshes every 10 minutes with custom colors and messages.</p>
<p><a href="https://appmakers.gumroad.com/l/swiftui-widget-basic">🔗 <strong data-start="9287" data-end="9330">Download the full commented source code (Xcode Project) for this Tutorial</strong></a></p>
<h2 data-start="688" data-end="742">🧰 Getting Started — Create a Fresh SwiftUI Project</h2>
<p data-start="744" data-end="775">Open Xcode and start a new app:</p>
<ul data-start="777" data-end="903">
<li data-start="777" data-end="815">
<p data-start="779" data-end="815">Go to <strong data-start="785" data-end="815">File → New → Project → App</strong></p>
</li>
<li data-start="816" data-end="862">
<p data-start="818" data-end="862">Name your project something like <code class="" data-line="">WidgetApp</code></p>
</li>
<li data-start="863" data-end="885">
<p data-start="865" data-end="885">Interface: SwiftUI</p>
</li>
<li data-start="886" data-end="903">
<p data-start="888" data-end="903">Language: Swift</p>
</li>
</ul>
<p data-start="905" data-end="951">Save the project and move on to the next step.</p>
<h2 data-start="958" data-end="987">➕ Add the Widget Extension</h2>
<p data-start="989" data-end="1026">Now it’s time to add a widget target:</p>
<ul data-start="1028" data-end="1259">
<li data-start="1028" data-end="1053">
<p data-start="1030" data-end="1053"><strong data-start="1030" data-end="1053">File → New → Target</strong></p>
</li>
<li data-start="1054" data-end="1083">
<p data-start="1056" data-end="1083">Select <strong data-start="1063" data-end="1083">Widget Extension</strong></p>
</li>
<li data-start="1084" data-end="1165">
<p data-start="1086" data-end="1106">Uncheck the options:</p>
<ul data-start="1109" data-end="1165">
<li data-start="1109" data-end="1124">
<p data-start="1111" data-end="1124">Live Activity</p>
</li>
<li data-start="1127" data-end="1136">
<p data-start="1129" data-end="1136">Control</p>
</li>
<li data-start="1139" data-end="1165">
<p data-start="1141" data-end="1165">Configuration App Intent</p>
</li>
</ul>
</li>
<li data-start="1166" data-end="1208">
<p data-start="1168" data-end="1208">Name it something like <code class="" data-line="">WidgetAppWidget</code></p>
</li>
<li data-start="1209" data-end="1259">
<p data-start="1211" data-end="1259">Confirm and activate the new scheme if prompted.</p>
</li>
</ul>
<h2 data-start="1266" data-end="1307">🔍 Understand the Auto-Generated Files</h2>
<p data-start="1309" data-end="1341">Xcode will create two key files:</p>
<h3 data-start="1343" data-end="1384"><code class="" data-line="">AppWidgetBundle.swift</code> – Entry Point</h3>
<p data-start="1386" data-end="1461">This struct defines your widget bundle and serves as the extension&#8217;s entry:</p>
<pre><code class="language-swift" data-line="">import WidgetKit
import SwiftUI

@main
struct AppWidgetBundle: WidgetBundle {
    var body: some Widget {
        AppWidget()
    }
}</code></pre>
<div class="contain-inline-size rounded-2xl border-[0.5px] border-token-border-medium relative bg-token-sidebar-surface-primary"></div>
<ul data-start="1635" data-end="1791">
<li data-start="1635" data-end="1722">
<p data-start="1637" data-end="1722">The <code class="" data-line="">@main</code> attribute designates this as the starting point of your widget extension.</p>
</li>
<li data-start="1723" data-end="1791">
<p data-start="1725" data-end="1791">You can group multiple widgets into this bundle in future updates.</p>
</li>
</ul>
<h3 data-start="1798" data-end="1842"><code class="" data-line="">AppWidget.swift</code> – The Core Widget File</h3>
<p data-start="1844" data-end="1892">This file contains everything your widget needs:</p>
<ul data-start="1893" data-end="2076">
<li data-start="1893" data-end="1927">
<p data-start="1895" data-end="1927">A <strong data-start="1897" data-end="1911">data model</strong> (<code class="" data-line="">SimpleEntry</code>)</p>
</li>
<li data-start="1928" data-end="1953">
<p data-start="1930" data-end="1953">A <strong data-start="1932" data-end="1953">timeline provider</strong></p>
</li>
<li data-start="1954" data-end="1984">
<p data-start="1956" data-end="1984">A <strong data-start="1958" data-end="1984">view for the widget UI</strong></p>
</li>
<li data-start="1985" data-end="2034">
<p data-start="1987" data-end="2034">The actual <strong data-start="1998" data-end="2015">widget struct</strong> with configuration</p>
</li>
<li data-start="2035" data-end="2076">
<p data-start="2037" data-end="2076">A <strong data-start="2039" data-end="2051">#Preview</strong> section to test in Xcode</p>
</li>
</ul>
<h2 data-start="2083" data-end="2122">📦 1. Define the Widget’s Data Model</h2>
<p data-start="2124" data-end="2202">The <code class="" data-line="">SimpleEntry</code> struct represents the snapshot of data shown at each update:</p>
<pre><code class="language-swift" data-line="">struct SimpleEntry: TimelineEntry {
    let date: Date
    let emoji: String
}
</code></pre>
<ul>
<li data-start="2297" data-end="2348">
<p data-start="2299" data-end="2348"><code class="" data-line="">date</code>: Tells the system when to show this entry.</p>
</li>
<li data-start="2349" data-end="2448">
<p data-start="2351" data-end="2448"><code class="" data-line="">emoji</code>: Temporary example content — later, we’ll replace it with a message and background color.</p>
</li>
</ul>
<h2 data-start="2455" data-end="2494">🧠 2. Implement the TimelineProvider</h2>
<p data-start="2496" data-end="2594">The <code class="" data-line="">TimelineProvider</code> tells WidgetKit what to display and when. It includes three main functions:</p>
<pre><code class="language-swift" data-line="">struct Provider: TimelineProvider {
   // 1️⃣ func placeholder(in context: Context) -&gt; SimpleEntry { … }
   // 2️⃣ func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -&gt; ()) { … }
   // 3️⃣ func getTimeline(in context: Context, completion: @escaping (Timeline&lt;SimpleEntry&gt;) -&gt; ()) { … }
}
</code></pre>
<h3 data-start="2921" data-end="2947">1️⃣ <code class="" data-line="">placeholder(in:)</code></h3>
<p data-start="2948" data-end="2994">Shows temporary content in the widget gallery.</p>
<pre><code class="language-swift" data-line="">func placeholder(in context: Context) -&gt; SimpleEntry {
    SimpleEntry(date: Date(), emoji: &quot;😀&quot;)
}
</code></pre>
<h3 data-start="3110" data-end="3136">2️⃣ <code class="" data-line="">getSnapshot(in:)</code></h3>
<p data-start="3137" data-end="3172">Provides a static snapshot of data.</p>
<pre><code class="language-swift" data-line="">func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -&gt; ()) {
    let entry = SimpleEntry(date: Date(), emoji: &quot;😀&quot;)
    completion(entry)
}
</code></pre>
<h3 data-start="3350" data-end="3376">3️⃣ <code class="" data-line="">getTimeline(in:)</code></h3>
<p data-start="3377" data-end="3414">Generates a list of timeline entries.</p>
<pre><code class="language-swift" data-line="">func getTimeline(in context: Context, completion: @escaping (Timeline&lt;Entry&gt;) -&gt; ()) {
    var entries: [SimpleEntry] = []

    let currentDate = Date()
    for hourOffset in 0 ..&lt; 5 {
        let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
        let entry = SimpleEntry(date: entryDate, emoji: &quot;😀&quot;)
        entries.append(entry)
    }

    let timeline = Timeline(entries: entries, policy: .atEnd)
    completion(timeline)
}
</code></pre>
<h2 data-start="3908" data-end="3951">🖼️ 3. Create the Widget UI with SwiftUI</h2>
<p data-start="3953" data-end="4018">Use SwiftUI to define how your widget appears on the home screen.</p>
<pre><code class="language-swift" data-line="">struct AppWidgetEntryView : View {
    var entry: Provider.Entry

    var body: some View {
        VStack {
            Text(&quot;Time:&quot;)
            Text(entry.date, style: .time)
            Text(&quot;Emoji:&quot;)
            Text(entry.emoji)
        }
    }
}
</code></pre>
<h2 data-start="4292" data-end="4331">🧱 4. Configure the Widget Structure</h2>
<p data-start="4333" data-end="4405">This section ties everything together and registers the widget with iOS.</p>
<pre><code class="language-swift" data-line="">struct AppWidget: Widget {
    let kind: String = &quot;AppWidget&quot;

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            if #available(iOS 17.0, *) {
                AppWidgetEntryView(entry: entry)
                    .containerBackground(.fill.tertiary, for: .widget)
            } else {
                AppWidgetEntryView(entry: entry)
                    .padding()
                    .background()
            }
        }
        .configurationDisplayName(&quot;My Widget&quot;)
        .description(&quot;This is an example widget.&quot;)
    }
}
</code></pre>
<h2 data-start="5029" data-end="5060">👀 5. Previewing Your Widget</h2>
<p data-start="5062" data-end="5125">SwiftUI’s new <code class="" data-line="">#Preview</code> lets you simulate the widget in Xcode.</p>
<pre><code class="language-swift" data-line="">#Preview(as: .systemSmall) {
    AppWidget()
} timeline: {
    SimpleEntry(date: .now, emoji: &quot;😀&quot;)
    SimpleEntry(date: .now, emoji: &quot;🤩&quot;)
}
</code></pre>
<h2 data-start="5289" data-end="5343">🎯 Make It Useful — Show Random Motivational Quotes</h2>
<p data-start="5345" data-end="5383">Let’s make this widget more inspiring.</p>
<p data-start="5385" data-end="5483">Instead of an emoji, we’ll show motivational quotes every 10 minutes and change background colors.</p>
<p data-start="5385" data-end="5483">🛠 Update SimpleEntry</p>
<pre><code class="language-swift" data-line="">struct SimpleEntry: TimelineEntry {
    let date: Date
    let message: String
    let color: Color
}
</code></pre>
<h3 data-start="5638" data-end="5660">🧠 Update Provider</h3>
<p data-start="5662" data-end="5693">Add sample messages and colors:</p>
<pre><code class="language-swift" data-line="">let messages = [
    &quot;Keep going 💪&quot;, &quot;You&#039;re doing great!&quot;, &quot;Just one more step 🚶&quot;,
    &quot;Stay focused 🎯&quot;, &quot;You’ve got this 🔥&quot;, &quot;Make it count 💥&quot;,
    &quot;Smile, breathe, move 🌿&quot;, &quot;Every moment matters ⏳&quot;
]

let backgroundColors: [Color] = [
    .blue, .green, .orange, .pink, .purple, .yellow, .teal, .mint
]

let defaultColor: Color = .gray
let defaultMessage = &quot;Keep going 💪&quot;
</code></pre>
<p>Update <code class="" data-line="">placeholder</code> and <code class="" data-line="">getSnapshot</code>:</p>
<pre><code class="language-swift" data-line="">func placeholder(in context: Context) -&gt; SimpleEntry {
    SimpleEntry(date: Date(), message: defaultMessage, color: defaultColor)
}

func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -&gt; ()) {
    let entry = SimpleEntry(date: Date(), message: defaultMessage, color: defaultColor)
    completion(entry)
}
</code></pre>
<p>Update <code class="" data-line="">getTimeline</code>:</p>
<pre><code class="language-swift" data-line="">func getTimeline(in context: Context, completion: @escaping (Timeline&lt;Entry&gt;) -&gt; ()) {
    var entries: [SimpleEntry] = []
    let currentDate = Date()

    for minuteOffset in 0 ..&lt; 6 {
        let entryDate = Calendar.current.date(byAdding: .minute, value: minuteOffset * 10, to: currentDate)!
        let message = messages.randomElement() ?? defaultMessage
        let backgroundColor = backgroundColors.randomElement() ?? defaultColor
        let entry = SimpleEntry(date: entryDate, message: message, color: backgroundColor)
        entries.append(entry)
    }

    let timeline = Timeline(entries: entries, policy: .atEnd)
    completion(timeline)
}
</code></pre>
<p>🎨 Redesign the Widget View</p>
<pre><code class="language-swift" data-line="">struct AppWidgetEntryView : View {
    var entry: Provider.Entry

    var body: some View {
        ZStack {
            VStack(spacing: 10) {
                Text(entry.message)
                    .font(.headline)
                    .multilineTextAlignment(.center)
                    .minimumScaleFactor(0.5)
                    .lineLimit(1)
                    .foregroundStyle(.primary)

                Text(entry.date, style: .time)
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }
        }
    }
}
</code></pre>
<p>⚙️ Update Widget Config</p>
<pre><code class="language-swift" data-line="">struct AppWidget: Widget {
    let kind: String = &quot;AppWidget&quot;

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            let backgroundColor = entry.color.opacity(0.25)

            if #available(iOS 17.0, *) {
                AppWidgetEntryView(entry: entry)
                    .containerBackground(backgroundColor, for: .widget)
            } else {
                AppWidgetEntryView(entry: entry)
                    .padding()
                    .background(backgroundColor)
            }
        }
        .configurationDisplayName(&quot;Motivational Widget&quot;)
        .description(&quot;This Widget Will Keep You Motivated&quot;)
    }
}
</code></pre>
<p>🧪 Preview It</p>
<pre><code class="language-swift" data-line="">#Preview(&quot;Small Widget&quot;, as: .systemSmall) {
    AppWidget()
} timeline: {
    SimpleEntry(date: .now, message: &quot;Keep going 💪&quot;, color: .orange)
    SimpleEntry(date: .now, message: &quot;Stay focused 🎯&quot;, color: .purple)
}
</code></pre>
<h2 data-start="8790" data-end="8817">📱 Test on a Real Device</h2>
<ol data-start="8819" data-end="9001">
<li data-start="8819" data-end="8868">
<p data-start="8822" data-end="8868">Run your <strong data-start="8831" data-end="8850">main app target</strong> on a real device.</p>
</li>
<li data-start="8869" data-end="8940">
<p data-start="8872" data-end="8940">Long-press the Home Screen → Tap &#8220;+&#8221; → Search for your widget → Add.</p>
</li>
<li data-start="8941" data-end="9001">
<p data-start="8944" data-end="9001">Optionally tap and <strong data-start="8963" data-end="8982">edit the widget</strong> for configuration.</p>
</li>
</ol>
<p data-start="9003" data-end="9090"><strong data-start="9003" data-end="9011">Note</strong>: App Groups aren’t required if your widget shows static or internal data only.</p>
<h2 data-start="9097" data-end="9113">✅ Final Notes</h2>
<ul data-start="9115" data-end="9282">
<li data-start="9115" data-end="9176">
<p data-start="9117" data-end="9176">Code is tested on Xcode 16.2 and iOS 18.2 (as of June 2025)</p>
</li>
<li data-start="9177" data-end="9231">
<p data-start="9179" data-end="9231">Always check compatibility with newer Xcode versions</p>
</li>
<li data-start="9232" data-end="9282">
<p data-start="9234" data-end="9282">If you run into issues, let us know via comments</p>
</li>
</ul>
<p><a href="https://appmakers.gumroad.com/l/swiftui-widget-basic">DOWNLOAD SOURCE CODE FOR THIS TUTORIAL</a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>The post <a href="https://appmakers.dev/build-your-first-widget-in-swiftui-a-guide-with-source-code/">Build Your First Widget in SwiftUI — A Guide with Source Code</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>WWDC 2025 Keynote Recap: All the Biggest Announcements from iOS 26 to Apple Intelligence</title>
		<link>https://appmakers.dev/wwdc-2025-keynote-recap/</link>
		
		<dc:creator><![CDATA[AppMakers]]></dc:creator>
		<pubDate>Mon, 09 Jun 2025 20:37:20 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[WWDC 2025]]></category>
		<category><![CDATA[WWDC]]></category>
		<category><![CDATA[WWDC25]]></category>
		<guid isPermaLink="false">https://appmakers.dev/?p=1981</guid>

					<description><![CDATA[<p>Apple just wrapped up its WWDC 2025 keynote, and it was one of the most feature-packed presentations in years. From a dramatic intro featuring Craig Federighi in an F1 car to the reveal of a fully redesigned UI system and systemwide AI integration, WWDC 25 laid the foundation for Apple’s next chapter. Whether you&#8217;re a&#8230;</p>
<p>The post <a href="https://appmakers.dev/wwdc-2025-keynote-recap/">WWDC 2025 Keynote Recap: All the Biggest Announcements from iOS 26 to Apple Intelligence</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p data-start="437" data-end="747">Apple just wrapped up its <strong data-start="463" data-end="484">WWDC 2025 keynote</strong>, and it was one of the most feature-packed presentations in years. From a dramatic intro featuring Craig Federighi in an F1 car to the reveal of a fully redesigned UI system and systemwide AI integration, <strong data-start="690" data-end="701">WWDC 25</strong> laid the foundation for Apple’s next chapter.</p>
<p data-start="749" data-end="1004">Whether you&#8217;re a developer, tech enthusiast, or just want to know what&#8217;s coming to your devices later this year, this article walks you through <strong data-start="893" data-end="950">every major WWDC 2025 keynote announcement — in order</strong>, with clear, quick summaries for each product update.</p>
<h2 data-start="1188" data-end="1239">🤖 Apple Intelligence: On-Device AI for Everyone</h2>
<p data-start="1241" data-end="1348">Apple unveiled <strong data-start="1256" data-end="1278">Apple Intelligence</strong>, its new on-device AI system that works across iPhone, iPad, and Mac:</p>
<ul data-start="1350" data-end="1667">
<li data-start="1350" data-end="1435">
<p data-start="1352" data-end="1435"><strong data-start="1352" data-end="1369">Smart replies</strong>, <strong data-start="1371" data-end="1382">Genmoji</strong>, and <strong data-start="1388" data-end="1408">Image Playground</strong> built directly into apps</p>
</li>
<li data-start="1436" data-end="1508">
<p data-start="1438" data-end="1508">Visual lookups and content summaries through <strong data-start="1483" data-end="1506">Visual Intelligence</strong></p>
</li>
<li data-start="1509" data-end="1590">
<p data-start="1511" data-end="1590">New <strong data-start="1515" data-end="1539">Foundation Model API</strong> lets developers use Apple’s AI in their own apps</p>
</li>
</ul>
<h2 data-start="1674" data-end="1721">✨ The New Look: Liquid Glass Design Language</h2>
<p data-start="1723" data-end="1858">One of the standout updates from the WWDC 2025 keynote was the debut of <strong data-start="1795" data-end="1811">Liquid Glass</strong> — Apple’s first major UI redesign since iOS 7:</p>
<ul data-start="1860" data-end="2054">
<li data-start="1860" data-end="1920">
<p data-start="1862" data-end="1920">Fluid, translucent layers that adapt to light and motion</p>
</li>
<li data-start="1921" data-end="1995">
<p data-start="1923" data-end="1995">New <strong data-start="1927" data-end="1939">tab bars</strong>, <strong data-start="1941" data-end="1959">animated icons</strong>, and <strong data-start="1965" data-end="1993">responsive UI components</strong></p>
</li>
<li data-start="1996" data-end="2054">
<p data-start="1998" data-end="2054">Customizable widget styles and multiple new icon looks</p>
</li>
</ul>
<p data-start="2056" data-end="2157">This redesign rolls out across <strong data-start="2087" data-end="2097">iOS 26</strong>, <strong data-start="2099" data-end="2112">iPadOS 26</strong>, <strong data-start="2114" data-end="2129">macOS Tahoe</strong>, <strong data-start="2131" data-end="2146">visionOS 26</strong>, and more.</p>
<h2 data-start="2164" data-end="2210">📱 iOS 26: Smarter, Sleeker, and AI-Powered</h2>
<p data-start="2212" data-end="2290">Apple is skipping version 19 and jumping straight to <strong data-start="2265" data-end="2275">iOS 26</strong>, which brings:</p>
<ul data-start="2292" data-end="2710">
<li data-start="2292" data-end="2352">
<p data-start="2294" data-end="2352">Redesigned <strong data-start="2305" data-end="2320">lock screen</strong> with dynamic 3D time displays</p>
</li>
<li data-start="2353" data-end="2422">
<p data-start="2355" data-end="2422">New <strong data-start="2359" data-end="2373">Camera app</strong> UI and <strong data-start="2381" data-end="2391">Photos</strong> with spatial visual memories</p>
</li>
<li data-start="2423" data-end="2482">
<p data-start="2425" data-end="2482">Safari gets an edge-to-edge layout and floating tab bar</p>
</li>
<li data-start="2483" data-end="2536">
<p data-start="2485" data-end="2536">FaceTime, Phone, and Messages see major redesigns</p>
</li>
<li data-start="2537" data-end="2582">
<p data-start="2539" data-end="2582">Genmoji upgrades and smart emoji creation</p>
</li>
<li data-start="2583" data-end="2640">
<p data-start="2585" data-end="2640"><strong data-start="2585" data-end="2605">Live translation</strong> in Messages, FaceTime, and Phone</p>
</li>
<li data-start="2641" data-end="2710">
<p data-start="2643" data-end="2710">Visual Intelligence adds tap-to-search and contextual suggestions</p>
</li>
</ul>
<h2 data-start="2717" data-end="2754">🎵 Apple Music &amp; Maps Improvements</h2>
<ul data-start="2756" data-end="2922">
<li data-start="2756" data-end="2808">
<p data-start="2758" data-end="2808"><strong data-start="2758" data-end="2769">AutoMix</strong>: DJ-style transitions between tracks</p>
</li>
<li data-start="2809" data-end="2853">
<p data-start="2811" data-end="2853">Translated lyrics and pronunciation help</p>
</li>
<li data-start="2854" data-end="2922">
<p data-start="2856" data-end="2922">New Maps features like visited place history and smarter routing</p>
</li>
</ul>
<h2 data-start="2929" data-end="2962">💳 Wallet + Apple Pay Upgrades</h2>
<ul data-start="2964" data-end="3112">
<li data-start="2964" data-end="3040">
<p data-start="2966" data-end="3040">Support for <strong data-start="2978" data-end="2993">digital IDs</strong>, in-person rewards, and installment payments</p>
</li>
<li data-start="3041" data-end="3112">
<p data-start="3043" data-end="3112">AI-powered <strong data-start="3054" data-end="3072">order tracking</strong> and real-time boarding info in Wallet</p>
</li>
</ul>
<h2 data-start="3119" data-end="3142">🎮 All-New Games App</h2>
<p data-start="3144" data-end="3188">A new hub for Apple gaming across platforms:</p>
<ul data-start="3190" data-end="3331">
<li data-start="3190" data-end="3234">
<p data-start="3192" data-end="3234"><strong data-start="3192" data-end="3209">Play Together</strong> multiplayer challenges</p>
</li>
<li data-start="3235" data-end="3263">
<p data-start="3237" data-end="3263">Apple Arcade integration</p>
</li>
<li data-start="3264" data-end="3331">
<p data-start="3266" data-end="3331">Controller support and synced progress on iPhone, iPad, and Mac</p>
</li>
</ul>
<h2 data-start="3338" data-end="3381">⌚ watchOS 26: Personalized and Proactive</h2>
<p data-start="3383" data-end="3413">Apple Watch gets smarter with:</p>
<ul data-start="3415" data-end="3633">
<li data-start="3415" data-end="3457">
<p data-start="3417" data-end="3457">Liquid Glass UI for the smaller screen</p>
</li>
<li data-start="3458" data-end="3488">
<p data-start="3460" data-end="3488"><strong data-start="3460" data-end="3486">Workout Buddy AI coach</strong></p>
</li>
<li data-start="3489" data-end="3539">
<p data-start="3491" data-end="3539">Wrist Flick gesture for hands-free interaction</p>
</li>
<li data-start="3540" data-end="3590">
<p data-start="3542" data-end="3590">Notes app and improved Smart Stack predictions</p>
</li>
<li data-start="3591" data-end="3633">
<p data-start="3593" data-end="3633">Live Translation directly on the watch</p>
</li>
</ul>
<h2 data-start="3640" data-end="3688">📺 tvOS 26: Shared Experiences and Smarter UI</h2>
<ul data-start="3690" data-end="3857">
<li data-start="3690" data-end="3726">
<p data-start="3692" data-end="3726">New design language for Apple TV</p>
</li>
<li data-start="3727" data-end="3751">
<p data-start="3729" data-end="3751">Auto-profile loading</p>
</li>
<li data-start="3752" data-end="3804">
<p data-start="3754" data-end="3804">Shared music queue and real-time emoji reactions</p>
</li>
<li data-start="3805" data-end="3857">
<p data-start="3807" data-end="3857">iPhone karaoke mic support with Apple Music Sing</p>
</li>
</ul>
<h2 data-start="3864" data-end="3910">💻 macOS Tahoe: Power Meets Personalization</h2>
<p data-start="3912" data-end="3944">macOS 26, aka <strong data-start="3926" data-end="3935">Tahoe</strong>, brings:</p>
<ul data-start="3946" data-end="4264">
<li data-start="3946" data-end="3996">
<p data-start="3948" data-end="3996">Liquid Glass across Finder, Menu Bar, and Dock</p>
</li>
<li data-start="3997" data-end="4042">
<p data-start="3999" data-end="4042">Custom folder icons with colors and emoji</p>
</li>
<li data-start="4043" data-end="4085">
<p data-start="4045" data-end="4085">iPhone-style Phone app and Hold Assist</p>
</li>
<li data-start="4086" data-end="4143">
<p data-start="4088" data-end="4143"><strong data-start="4088" data-end="4101">Spotlight</strong> overhaul: Quick Keys, clipboard history</p>
</li>
<li data-start="4144" data-end="4206">
<p data-start="4146" data-end="4206">Smart automations using <strong data-start="4170" data-end="4204">Apple Intelligence + Shortcuts</strong></p>
</li>
<li data-start="4207" data-end="4264">
<p data-start="4209" data-end="4264">New gaming capabilities with Metal 4 and Game Overlay</p>
</li>
</ul>
<h2 data-start="4271" data-end="4315">🥽 visionOS 26: Spatial Becomes Practical</h2>
<p data-start="4317" data-end="4353">Updates to Apple Vision Pro include:</p>
<ul data-start="4355" data-end="4596">
<li data-start="4355" data-end="4395">
<p data-start="4357" data-end="4395">Persistent widgets and floating apps</p>
</li>
<li data-start="4396" data-end="4438">
<p data-start="4398" data-end="4438">Spatial Scenes from your photo library</p>
</li>
<li data-start="4439" data-end="4479">
<p data-start="4441" data-end="4479">Shared movie watching and workspaces</p>
</li>
<li data-start="4480" data-end="4543">
<p data-start="4482" data-end="4543">Stylus support (Logitech Muse) and PSVR2 controller support</p>
</li>
<li data-start="4544" data-end="4596">
<p data-start="4546" data-end="4596">Adobe Premiere support for spatial video editing</p>
</li>
</ul>
<h2 data-start="4603" data-end="4643">📝 iPadOS 26: Full Multitasking Power</h2>
<p data-start="4645" data-end="4695">Apple calls it the <strong data-start="4664" data-end="4694">biggest iPadOS update ever</strong>:</p>
<ul data-start="4697" data-end="5043">
<li data-start="4697" data-end="4761">
<p data-start="4699" data-end="4761"><strong data-start="4699" data-end="4720">Resizable windows</strong>, Exposé view, tiling, minimize/restore</p>
</li>
<li data-start="4762" data-end="4796">
<p data-start="4764" data-end="4796"><strong data-start="4764" data-end="4786">Mac-style Menu Bar</strong> on iPad</p>
</li>
<li data-start="4797" data-end="4850">
<p data-start="4799" data-end="4850">Better Files app with list views and Dock folders</p>
</li>
<li data-start="4851" data-end="4896">
<p data-start="4853" data-end="4896"><strong data-start="4853" data-end="4868">Preview app</strong> for PDFs and image markup</p>
</li>
<li data-start="4897" data-end="4949">
<p data-start="4899" data-end="4949">High-quality screen/audio recording with AirPods</p>
</li>
<li data-start="4950" data-end="4989">
<p data-start="4952" data-end="4989">Background Tasks as Live Activities</p>
</li>
<li data-start="4990" data-end="5043">
<p data-start="4992" data-end="5043">New tools for creators and productivity workflows</p>
</li>
</ul>
<h2 data-start="5050" data-end="5089">🔧 Developer Tools and Xcode Updates</h2>
<ul data-start="5091" data-end="5329">
<li data-start="5091" data-end="5145">
<p data-start="5093" data-end="5145"><strong data-start="5093" data-end="5117">Foundation Model API</strong> for private, on-device AI</p>
</li>
<li data-start="5146" data-end="5179">
<p data-start="5148" data-end="5179">Expanded SwiftUI capabilities</p>
</li>
<li data-start="5180" data-end="5230">
<p data-start="5182" data-end="5230"><strong data-start="5182" data-end="5197">App Intents</strong> for smarter system integration</p>
</li>
<li data-start="5231" data-end="5278">
<p data-start="5233" data-end="5278"><strong data-start="5233" data-end="5250">Icon Composer</strong> for dynamic icon creation</p>
</li>
<li data-start="5279" data-end="5329">
<p data-start="5281" data-end="5329">ChatGPT-powered code assistant in <strong data-start="5315" data-end="5327">Xcode 16</strong></p>
</li>
</ul>
<h2 data-start="5336" data-end="5358">🗓 Release Schedule</h2>
<ul data-start="5360" data-end="5503">
<li data-start="5360" data-end="5394">
<p data-start="5362" data-end="5394">Developer betas: Available now</p>
</li>
<li data-start="5433" data-end="5503">
<p data-start="5435" data-end="5503">Official releases: Fall 2025, with all OS versions jumping to <strong data-start="5497" data-end="5503">26</strong></p>
</li>
</ul>
<h2 data-start="5510" data-end="5548">🧠 Final Thoughts: A New Era Begins</h2>
<p data-start="5550" data-end="5904">The <strong data-start="5554" data-end="5575">WWDC 2025 keynote</strong> was more than just feature updates — it marked a dramatic shift in how Apple sees its platforms evolving. With <strong data-start="5687" data-end="5709">Apple Intelligence</strong> woven throughout every device, a bold new <strong data-start="5752" data-end="5778">Liquid Glass interface</strong>, and the power tools developers have been asking for, this year’s WWDC sets Apple up for a smarter, more connected ecosystem.</p>
<p data-start="5550" data-end="5904"><a href="https://www.youtube.com/watch?v=0_DjDdfqtUE">Watch the official WWDC 2025 Keynote Video here </a></p>
<p>The post <a href="https://appmakers.dev/wwdc-2025-keynote-recap/">WWDC 2025 Keynote Recap: All the Biggest Announcements from iOS 26 to Apple Intelligence</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to upload your Xcode Project to Github &#8211; Tutorial</title>
		<link>https://appmakers.dev/how-to-upload-your-xcode-project-to-github-tutorial/</link>
		
		<dc:creator><![CDATA[AppMakers]]></dc:creator>
		<pubDate>Thu, 17 Oct 2024 11:35:54 +0000</pubDate>
				<category><![CDATA[iOS Development]]></category>
		<category><![CDATA[Xcode Tutorials]]></category>
		<guid isPermaLink="false">https://appmakers.dev/?p=1779</guid>

					<description><![CDATA[<p>In this article, we will walk you through the process of setting up GitHub in Xcode and uploading your SwiftUI project to your GitHub account. The steps will include configuring GitHub in Xcode, creating a Git repository, and pushing code updates. Let&#8217;s dive in! Step 1: Create a New Xcode Project Open Xcode and create&#8230;</p>
<p>The post <a href="https://appmakers.dev/how-to-upload-your-xcode-project-to-github-tutorial/">How to upload your Xcode Project to Github &#8211; Tutorial</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this article, we will walk you through the process of setting up GitHub in Xcode and uploading your SwiftUI project to your GitHub account. The steps will include configuring GitHub in Xcode, creating a Git repository, and pushing code updates. Let&#8217;s dive in!</p>
<h4>Step 1: Create a New Xcode Project</h4>
<ol>
<li>Open Xcode and create a new SwiftUI project.</li>
<li>Name your project. In this example, we&#8217;ll call it &#8220;Xcode To Github Demo App.&#8221;</li>
</ol>
<h4>Step 2: Add Your GitHub Account to Xcode</h4>
<ol>
<li>In Xcode, navigate to <strong>Xcode &gt; Settings</strong> (or <strong>Preferences</strong>, depending on your macOS version).</li>
<li>Go to the <strong>Accounts</strong> tab.</li>
<li>Click the <strong>+</strong> button to add a new account, and select <strong>GitHub</strong>.</li>
<li>Enter your GitHub username.</li>
<li>You&#8217;ll need a personal access token to authenticate. Let’s generate one.</li>
</ol>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-1781" src="https://appmakers.dev/wp-content/uploads/2024/10/Step-1-Settings-add-Github-Account.jpg" alt="" width="600" height="423" srcset="https://appmakers.dev/wp-content/uploads/2024/10/Step-1-Settings-add-Github-Account.jpg 1884w, https://appmakers.dev/wp-content/uploads/2024/10/Step-1-Settings-add-Github-Account-768x541.jpg 768w, https://appmakers.dev/wp-content/uploads/2024/10/Step-1-Settings-add-Github-Account-1536x1083.jpg 1536w" sizes="auto, (max-width: 600px) 100vw, 600px" /></p>
<h4>Step 3: Generate a Personal Access Token on GitHub</h4>
<ol>
<li>Log in to your GitHub account, tap on your profile icon and go to <strong>Settings</strong>.</li>
<li>Scroll down and select <strong>Developer settings </strong>(on the left).</li>
<li>In the left-hand menu, click <strong>Personal access tokens</strong> &gt; <strong>Tokens (classic)</strong>.</li>
<li>Click <strong>Generate new token</strong>, and confirm by entering your GitHub password.</li>
<li>Name your token (e.g., &#8220;Xcode&#8221;), and set an expiration date or choose <strong>No expiration</strong>.</li>
<li>Check all the scopes to grant full access, then click <strong>Generate token</strong>.</li>
<li>Copy the generated token.</li>
</ol>
<h4>Step 4: Link the Token with Xcode</h4>
<p><span id="more-1779"></span></p>
<ol>
<li>Go back to Xcode, paste the token in the <strong>Token</strong> field, and click <strong>Sign In</strong>.</li>
<li>Now your GitHub account is linked to Xcode.</li>
</ol>
<h4>Step 5: Set Up Source Control in Xcode</h4>
<ol>
<li>In Xcode, go to <strong>Settings &gt; Source Control &gt; Git</strong>.</li>
<li>Set up your <strong>Author Name</strong> and <strong>Email</strong> (use your GitHub username and the email associated with your GitHub account).</li>
</ol>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-1782" src="https://appmakers.dev/wp-content/uploads/2024/10/Step-5-Xcode-Source-Control-Git-in-Settings.jpg" alt="" width="601" height="396" srcset="https://appmakers.dev/wp-content/uploads/2024/10/Step-5-Xcode-Source-Control-Git-in-Settings.jpg 1884w, https://appmakers.dev/wp-content/uploads/2024/10/Step-5-Xcode-Source-Control-Git-in-Settings-768x506.jpg 768w, https://appmakers.dev/wp-content/uploads/2024/10/Step-5-Xcode-Source-Control-Git-in-Settings-1536x1013.jpg 1536w" sizes="auto, (max-width: 601px) 100vw, 601px" /></p>
<h4>Step 6: Create a New Git Repository and Push Project to Github</h4>
<ol>
<li>Close the <strong>Settings</strong> window.</li>
<li>Tap Command+2 to open Navigator&#8217;s <strong>Source Control </strong>and select <strong>Repositories</strong>.</li>
<li>Tap on the <strong>Xcode To Github Demo App</strong> in repository and tap <strong>&#8220;Xcode To Github Demo App&#8221;</strong> <strong>Remote</strong></li>
<li>Choose the Github Account, Set repository name if needed, Set Visibility (Public or Private), write Description if needed</li>
<li>Tap <strong>Create </strong></li>
<li>Optional: If you don&#8217;t see Repository in your Navigator you can try to tap <strong>Integrate &gt; New Git Repository </strong>to create one and after that follow the steps 1-5 of Step 6</li>
</ol>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-1785" src="https://appmakers.dev/wp-content/uploads/2024/10/Step-6-Create-New-Git-Repository.jpg" alt="" width="599" height="536" srcset="https://appmakers.dev/wp-content/uploads/2024/10/Step-6-Create-New-Git-Repository.jpg 1184w, https://appmakers.dev/wp-content/uploads/2024/10/Step-6-Create-New-Git-Repository-768x686.jpg 768w" sizes="auto, (max-width: 599px) 100vw, 599px" /></p>
<h4>Step 7: Check repository on Github</h4>
<ol>
<li>Go Github &gt; Your Repositories and check if the new repository appeared</li>
</ol>
<h4>Step 8: Make Changes and Commit Them</h4>
<ol>
<li>Let&#8217;s make a simple change in the project:
<ul>
<li>For example, update the text in <strong>ContentView.swift</strong> from &#8220;Hello, World!&#8221; to &#8220;Hello Github&#8221;</li>
</ul>
</li>
<li>Go to <strong>Source Control &gt; Commit</strong>, and you’ll see the change highlighted.</li>
<li>Add a commit message (e.g., &#8220;<span style="letter-spacing: 0px;">Changed ContentView Message to Hello Github</span>&#8220;), and click <strong>Commit</strong>.</li>
<li>If it asks to Stage, tap Stage all and commit (You should stage changes before committing)</li>
</ol>
<h4>Step 9: Push the Commit to GitHub</h4>
<ol>
<li>After committing the changes, go to <strong>Source Control &gt; Push</strong>.</li>
<li>Select the <strong>origin</strong> (by default, it&#8217;s the main branch).</li>
<li>Leave include tags unchecked, we will discuss this checkbox later</li>
<li>Click <strong>Push</strong>, and your changes will be uploaded to GitHub.</li>
</ol>
<h4>Step 10: Verify the Changes on GitHub</h4>
<ol>
<li>Go to your GitHub repository and refresh the page.</li>
<li>You should see the recent commits and changes in the project files.</li>
<li>You should check Activity section of your project on Github to see the latest commit</li>
</ol>
<h3>How to Tag Your commit in Xcode and Provide a Version (e.g., 1.0.0) for your Commit</h3>
<p>Tagging helps mark specific points in your project history, such as a release version.</p>
<ol>
<li>Go to <strong>Source Control &gt; Branches</strong>.</li>
<li>Right click on main and select Tag &#8220;main&#8221;</li>
<li>Add version number, for example1.0.0 and a message<br />
<img loading="lazy" decoding="async" class="alignnone wp-image-1786" src="https://appmakers.dev/wp-content/uploads/2024/10/Tag-Xcode-Commit-to-Github.jpg" alt="" width="412" height="233" srcset="https://appmakers.dev/wp-content/uploads/2024/10/Tag-Xcode-Commit-to-Github.jpg 1184w, https://appmakers.dev/wp-content/uploads/2024/10/Tag-Xcode-Commit-to-Github-768x435.jpg 768w" sizes="auto, (max-width: 412px) 100vw, 412px" /></li>
<li>Make some changes into your project</li>
<li>Go to Integrate &gt; Push and check include tags</li>
<li>Go to Github &gt; Releases &gt; check tags</li>
</ol>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-1789" src="https://appmakers.dev/wp-content/uploads/2024/10/Tag-on-Github.jpg" alt="" width="585" height="122" srcset="https://appmakers.dev/wp-content/uploads/2024/10/Tag-on-Github.jpg 2272w, https://appmakers.dev/wp-content/uploads/2024/10/Tag-on-Github-768x160.jpg 768w, https://appmakers.dev/wp-content/uploads/2024/10/Tag-on-Github-1536x320.jpg 1536w, https://appmakers.dev/wp-content/uploads/2024/10/Tag-on-Github-2048x427.jpg 2048w" sizes="auto, (max-width: 585px) 100vw, 585px" /></p>
<h3>How to Fetch changes from Remote</h3>
<ol>
<li>Go to Github into your Project repository and tap Create Readme file there</li>
<li>Fill in Readme file with some text, for example:
<pre><code class="language-markdown" data-line=""># README

Demo App to show how to Connect Xcode Project to Github

## Overview

Learn Daily

### Section header

Some Section Text here
</code></pre>
</li>
<li>Now go to Xcode and tap Pull to get changes from Github.</li>
</ol>
<h3></h3>
<h3>Understanding Staging, Amending, and Committing Changes</h3>
<p>Xcode uses Git&#8217;s staging area to manage changes, allowing you to control exactly what goes into each commit. Here’s how to work with staging and amending:</p>
<h4>What is Staging?</h4>
<p>Staging means preparing specific changes to be included in your next commit. In Xcode:</p>
<ul>
<li><strong>Staged Changes</strong>: These are the changes you have selected to commit. They will be included in the next commit you make.</li>
<li><strong>Unstaged Changes</strong>: These changes are not yet prepared for committing. You can choose to stage them by checking the boxes next to the file names in the commit window.</li>
</ul>
<h4>How to Stage Changes in Xcode:</h4>
<ol>
<li><strong>View the Changes</strong>: Go to <strong>Source Control &gt; Commit</strong> to see the list of changed files.</li>
<li><strong>Stage the Files</strong>: Check the box next to each file you want to include in your commit.</li>
<li><strong>Unstage if Necessary</strong>: Uncheck any files you don&#8217;t want to commit yet.</li>
</ol>
<h4>Amending a Commit</h4>
<p>Sometimes you need to make small changes to the last commit without creating a new commit. Here&#8217;s how to amend in Xcode:</p>
<ol>
<li><strong>Make the Desired Changes</strong>: Modify the files you want to update.</li>
<li><strong>Go to the Commit Window</strong>: <strong>Source Control &gt; Commit</strong>.</li>
<li><strong>Select &#8220;Amend Previous Commit&#8221;</strong>:
<ul>
<li>At the bottom of the commit window, you’ll see an option labeled <strong>&#8220;Amend Previous Commit.&#8221;</strong></li>
<li>Check this box to modify the last commit instead of creating a new one.</li>
<li>Update the commit message if necessary, and click <strong>Commit</strong>.</li>
</ul>
</li>
</ol>
<h4>Example Use Cases:</h4>
<ul>
<li><strong>Staging</strong>: Useful for breaking larger changes into smaller, logical commits.</li>
<li><strong>Amending</strong>: Helps fix mistakes in the last commit, such as forgetting a file or making a typo in the commit message.</li>
</ul>
<p>The post <a href="https://appmakers.dev/how-to-upload-your-xcode-project-to-github-tutorial/">How to upload your Xcode Project to Github &#8211; Tutorial</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Learn how to work with Xcode Previews in SwiftData App</title>
		<link>https://appmakers.dev/learn-how-to-work-with-xcode-previews-in-swiftdata-app/</link>
		
		<dc:creator><![CDATA[AppMakers]]></dc:creator>
		<pubDate>Wed, 16 Oct 2024 11:30:05 +0000</pubDate>
				<category><![CDATA[iOS Development]]></category>
		<category><![CDATA[SwiftData]]></category>
		<category><![CDATA[SwiftUI]]></category>
		<category><![CDATA[SwiftUI Data and Storage]]></category>
		<category><![CDATA[SwiftUI State Management and Data Flow]]></category>
		<category><![CDATA[SwiftUI Tutorials]]></category>
		<guid isPermaLink="false">https://appmakers.dev/?p=1776</guid>

					<description><![CDATA[<p>Learn how to work with Xcode Previews in SwiftData App. SwiftData in combination with SwiftUI allows you to quickly prototype and develop apps by providing easy-to-use, in-memory storage for model data. In this tutorial, we’ll walk through how to create sample recipe data using ModelContainer and display that data in SwiftUI views with previews. Step&#8230;</p>
<p>The post <a href="https://appmakers.dev/learn-how-to-work-with-xcode-previews-in-swiftdata-app/">Learn how to work with Xcode Previews in SwiftData App</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><strong>Learn how to work with Xcode Previews in SwiftData App</strong>. SwiftData in combination with SwiftUI allows you to quickly prototype and develop apps by providing easy-to-use, in-memory storage for model data. In this tutorial, we’ll walk through how to create sample recipe data using <code class="" data-line="">ModelContainer</code> and display that data in SwiftUI views with previews.</p>
<h3>Step 1: Defining the <code class="" data-line="">Recipe</code> Model</h3>
<p>Setup a <code class="" data-line="">Recipe</code> model that represents a dish with a name, cooking time, and ingredients.</p>
<pre><code class="language-swift" data-line="">import Foundation
import SwiftData

@Model
class Recipe {

    @Attribute(.unique) var id: UUID
    var name: String?
    var cookingTime: Int // in minutes
    var ingredients: [String]

    init(id: UUID = UUID(), name: String? = nil, cookingTime: Int, ingredients: [String]) {
        self.id = id
        self.name = name
        self.cookingTime = cookingTime
        self.ingredients = ingredients
    }
}
</code></pre>
<p>This model defines each recipe with a unique ID, name, cooking time, and a list of ingredients. With this setup, you can now store recipes in SwiftData and use them in your app.</p>
<h3>Step 2: Creating Sample Data for Previews</h3>
<p>Now, let’s generate sample data using <code class="" data-line="">ModelContainer</code>. You’ve written a method to insert sample recipes into a <code class="" data-line="">ModelContainer</code> for use in previews.</p>
<pre><code class="language-swift" data-line="">import Foundation
import SwiftData

let sampleRecipes = [
    Recipe(name: &quot;Spaghetti Bolognese&quot;, cookingTime: 45, ingredients: [&quot;Spaghetti&quot;, &quot;Minced Beef&quot;, &quot;Tomato Sauce&quot;]),
    Recipe(name: &quot;Grilled Cheese Sandwich&quot;, cookingTime: 10, ingredients: [&quot;Bread&quot;, &quot;Cheese&quot;, &quot;Butter&quot;]),
    Recipe(name: &quot;Beef Wellington&quot;, cookingTime: 120, ingredients: [&quot;Beef Tenderloin&quot;, &quot;Puff Pastry&quot;, &quot;Mushrooms&quot;, &quot;Dijon Mustard&quot;])
]

extension Recipe {
    @MainActor static func makeSampleRecipes(in container: ModelContainer) {
        
        let context = container.mainContext
        
        // Check if there are any existing recipes in the database
           let existingRecipesCount = (try? context.fetch(FetchDescriptor()))?.count ?? 0
           guard existingRecipesCount == 0 else {
               // If there are existing recipes, do not create new ones
               return
           }
           
           // Sample data to create
           let recipes = [
               Recipe(name: &quot;Spaghetti Bolognese&quot;, cookingTime: 45, ingredients: [&quot;Spaghetti&quot;, &quot;Minced Beef&quot;, &quot;Tomato Sauce&quot;]),
               Recipe(name: &quot;Grilled Cheese Sandwich&quot;, cookingTime: 10, ingredients: [&quot;Bread&quot;, &quot;Cheese&quot;, &quot;Butter&quot;]),
               Recipe(name: &quot;Beef Wellington&quot;, cookingTime: 120, ingredients: [&quot;Beef Tenderloin&quot;, &quot;Puff Pastry&quot;, &quot;Mushrooms&quot;, &quot;Dijon Mustard&quot;])
           ]
           
           // Insert the sample recipes into the context
           for recipe in recipes {
               context.insert(recipe)
           }
           
           // Save the context to persist the new data
           try? context.save()
        
    }
}

</code></pre>
<p>This method defines three recipes and inserts them into the <code class="" data-line="">ModelContainer</code>. The <code class="" data-line="">@MainActor</code> annotation ensures this method runs on the main thread, which is essential for interacting with SwiftData.</p>
<h3>Step 3: Implementing the <code class="" data-line="">RecipeSampleData</code> for Previews</h3>
<p><span id="more-1776"></span><br />
The <code class="" data-line="">RecipeSampleData</code> structure serves as a <code class="" data-line="">PreviewModifier</code> to create in-memory sample data. This makes it easy to display recipes in SwiftUI previews.</p>
<pre><code class="language-swift" data-line="">import SwiftUI
import SwiftData

struct RecipeSampleData: PreviewModifier {
    static func makeSharedContext() throws -&gt; ModelContainer {
        let config = ModelConfiguration(isStoredInMemoryOnly: true)
        let container = try ModelContainer(for: Recipe.self, configurations: config)
        Recipe.makeSampleRecipes(in: container) // Load sample recipes
        return container
    }
    
    func body(content: Content, context: ModelContainer) -&gt; some View {
        content.modelContainer(context)
    }
}

extension PreviewTrait where T == Preview.ViewTraits {
    @MainActor static var sampleRecipeData: Self = .modifier(RecipeSampleData())
}
</code></pre>
<p>This modifier creates a <code class="" data-line="">ModelContainer</code> configured for in-memory storage. The <code class="" data-line="">makeSampleRecipes</code> method loads sample recipes into the container, and the modifier applies this data to any view using the <code class="" data-line="">.modelContainer()</code> modifier.</p>
<h3>Step 4: Creating Recipe Views with Sample Data</h3>
<p>Now let’s integrate this sample data into a few SwiftUI views.</p>
<h4>Recipe List View</h4>
<p>The <code class="" data-line="">RecipeListView</code> displays a list of recipes loaded from SwiftData. The <code class="" data-line="">@Query</code> property wrapper retrieves the recipes, and the list is built dynamically.</p>
<pre><code class="language-swift" data-line="">import SwiftUI
import SwiftData

struct RecipeListView: View {
    @Query private var recipies: [Recipe]
    @Environment(\.modelContext) private var context
    
    var body: some View {
       
        List {
            ForEach(recipies) { recipe in
              
                VStack(alignment: .leading) {
                    Text(recipe.name ?? &quot;&quot;)
                           .font(.headline)
                       Text(&quot;Cooking Time: \(recipe.cookingTime) mins&quot;)
                           .font(.subheadline)
                   }
            }
        } .task {
            
               Recipe.makeSampleRecipes(in: context.container)
        }
    }
}

#Preview(traits: .sampleRecipeData) {
    RecipeListView()
}
</code></pre>
<p>In this example, the <code class="" data-line="">@Query</code> property wrapper retrieves all <code class="" data-line="">Recipe</code> objects from the <code class="" data-line="">ModelContainer</code>, which are then displayed in a <code class="" data-line="">List</code> using SwiftUI. The preview uses <code class="" data-line="">.sampleRecipeData</code> to load in-memory recipes for testing the UI.</p>
<h4>Recipe Detail View</h4>
<p>For more detailed recipe information, the <code class="" data-line="">RecipeDetailView</code> displays the name, cooking time, and ingredients of a single recipe. This view doesn’t query for data but accepts a <code class="" data-line="">Recipe</code> object as a parameter.</p>
<pre><code class="language-swift" data-line="">import SwiftUI
import SwiftData

struct RecipeDetailView: View {
    let recipe: Recipe

    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            Text(recipe.name ?? &quot;No Name&quot;)
                .font(.largeTitle)
            Text(&quot;Cooking Time: \(recipe.cookingTime) mins&quot;)
                .padding(.bottom)
            Text(&quot;Ingredients:&quot;)
            ForEach(recipe.ingredients, id: \.self) { ingredient in
                Text(ingredient)
            }
        }
        .padding()
    }
}

#Preview(traits: .sampleRecipeData) {
    @Previewable @Query var recipes: [Recipe]  // Query sample recipes
    RecipeDetailView(recipe: recipes.first!)
}
</code></pre>
<p>In this view, the recipe&#8217;s details are displayed, including the name, cooking time, and ingredients. The preview fetches the first recipe from the sample data.</p>
<h3>Step 5</h3>
<p>Now let&#8217;s connect our ListView with a DetailView using a NavigationLink inside a NavigationStack</p>
<pre><code class="language-swift" data-line="">import SwiftUI
import SwiftData

struct RecipeListView: View {
    @Query private var recipies: [Recipe]
    @Environment(\.modelContext) private var context
    
    var body: some View {
       
        NavigationStack {
            List {
                ForEach(recipies) { recipe in
                    NavigationLink(destination: RecipeDetailView(recipe: recipe)) {
                        
                        // Recipe Row
                        VStack(alignment: .leading) {
                            Text(recipe.name ?? &quot;&quot;)
                                .font(.headline)
                            Text(&quot;Cooking Time: \(recipe.cookingTime) mins&quot;)
                                .font(.subheadline)
                        }
                    }
                }
            } .task {
                
                Recipe.makeSampleRecipes(in: context.container)
                
            }
        }
    }
}

#Preview(traits: .sampleRecipeData) {
    RecipeListView()
}</code></pre>
<h3>Key Differences Between <code class="" data-line="">Preview</code> and <code class="" data-line="">@Previewable</code></h3>
<ol>
<li><strong><code class="" data-line="">Preview</code> with Traits (<code class="" data-line="">.sampleRecipeData</code>)</strong>:
<ul>
<li>Best for views that query data using SwiftData.</li>
<li>Automatically loads sample data into the view’s query and binds it to the UI.</li>
<li>No need to manually pass data; the query handles it for you.</li>
</ul>
</li>
<li><strong><code class="" data-line="">@Previewable</code></strong>:
<ul>
<li>Best for views that rely on models passed in as parameters (e.g., detail views).</li>
<li>Allows you to create sample data and pass it directly to the view.</li>
<li>You have full control over what specific data is provided for the preview.</li>
</ul>
</li>
</ol>
<h3>Conclusion</h3>
<p>By using <code class="" data-line="">SampleData</code> and the <code class="" data-line="">@Previewable</code> macro, you can easily preview recipe data within your SwiftUI views. Whether you’re working with data that relies on queries or views that require individual models, SwiftData provides an efficient way to prototype and test your app in Xcode.</p>
<p>The post <a href="https://appmakers.dev/learn-how-to-work-with-xcode-previews-in-swiftdata-app/">Learn how to work with Xcode Previews in SwiftData App</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to display sample SwiftData in SwiftUI with PreviewModifier</title>
		<link>https://appmakers.dev/how-to-display-sample-swiftdata-in-swiftui-with-previewmodifier/</link>
		
		<dc:creator><![CDATA[AppMakers]]></dc:creator>
		<pubDate>Sun, 13 Oct 2024 20:28:51 +0000</pubDate>
				<category><![CDATA[SwiftData]]></category>
		<category><![CDATA[SwiftUI]]></category>
		<category><![CDATA[SwiftUI Data and Storage]]></category>
		<category><![CDATA[SwiftUI Tutorials]]></category>
		<guid isPermaLink="false">https://appmakers.dev/?p=1765</guid>

					<description><![CDATA[<p>In this tutorial, we will explore how to display sample SwiftData in SwiftUI with PreviewModifier Step 1: Define the Entity First, we need to define a Task entity that we will use to store our task data in SwiftData. import Foundation import SwiftData @Model class Task { @Attribute(.unique) var id: UUID var title: String? var isCompleted:&#8230;</p>
<p>The post <a href="https://appmakers.dev/how-to-display-sample-swiftdata-in-swiftui-with-previewmodifier/">How to display sample SwiftData in SwiftUI with PreviewModifier</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this tutorial, we will explore how to display sample SwiftData in SwiftUI with PreviewModifier</p>
<h2>Step 1: Define the Entity</h2>
<p>First, we need to define a <code class="" data-line="">Task</code> entity that we will use to store our task data in SwiftData.</p>
<pre><code class="language-swift" data-line="">import Foundation
import SwiftData

@Model
class Task {
    @Attribute(.unique) var id: UUID
    var title: String?
    var isCompleted: Bool

    init(id: UUID = UUID(), title: String? = nil, isCompleted: Bool = false) {
        self.id = id
        self.title = title
        self.isCompleted = isCompleted
    }
}
</code></pre>
<p>In this code, we define the <code class="" data-line="">Task</code> model with an <code class="" data-line="">id</code>, <code class="" data-line="">title</code>, and <code class="" data-line="">isCompleted</code> property. The <code class="" data-line="">@Model</code> attribute is used to make this class a SwiftData model.</p>
<h2>Step 2: Create the Task List View</h2>
<p>Next, we&#8217;ll create a SwiftUI view that displays a list of tasks, each with a toggle for marking them as completed or not.</p>
<pre><code class="language-swift" data-line="">import SwiftUI
import SwiftData

struct TaskListView: View {
    @Query(sort: \Task.title) private var tasks: [Task]
    @Environment(\.modelContext) private var context
    
    var body: some View {
        List {
            ForEach(tasks) { task in
                HStack {
                    Text(task.title ?? &quot;&quot;)
                        .font(.title2)
                        .foregroundColor(task.isCompleted ? .green : .black)
                    
                    Spacer()
                    
                    Toggle(&quot;&quot;, isOn: Bindable(task).isCompleted)
                   
                }
            }
            .onDelete(perform: deleteTask)
        }
        .task {
            
            for task in sampleTasks {
                context.insert(task)
            }
            
        }
        .navigationTitle(&quot;Tasks&quot;)
    }
    
    private func updateTaskCompletion(_ task: Task, newValue: Bool) {
        task.isCompleted = newValue
        try? context.save()
    }
    
    private func deleteTask(at offsets: IndexSet) {
        for index in offsets {
            context.delete(tasks[index])
        }
        try? context.save()
    }
}
</code></pre>
<p>In this view, each task can be marked as completed by toggling a switch, and we handle saving this state with <strong>SwiftData</strong>.</p>
<h2>Step 3: Preview with SwiftData Context</h2>
<p>To make the preview functional, we need to set up a SwiftData context. We’ll use the <code class="" data-line="">PreviewModifier</code> protocol to create a shared context that holds some sample data.<span id="more-1765"></span></p>
<pre><code class="language-swift" data-line="">import Foundation
import SwiftUI
import SwiftData

let sampleTasks = [
    Task(title: &quot;Buy Groceries&quot;),
    Task(title: &quot;Walk the Dog&quot;, isCompleted: true),
    Task(title: &quot;Complete SwiftUI Project&quot;)
]

struct SampleTaskData: PreviewModifier {
    static func makeSharedContext() throws -&gt; ModelContainer {
        let container = try ModelContainer(for: Task.self, configurations: ModelConfiguration(isStoredInMemoryOnly: true))

        for task in sampleTasks {
            container.mainContext.insert(task)
        }
        
        return container
    }

    func body(content: Content, context: ModelContainer) -&gt; some View {
        content.modelContainer(context)
    }
}

extension PreviewTrait where T == Preview.ViewTraits {
    static var sampleTaskData: Self = .modifier(SampleTaskData())
}
</code></pre>
<p>In this example, the <code class="" data-line="">SampleTaskData</code> struct conforms to <code class="" data-line="">PreviewModifier</code>, providing a shared SwiftData context with in-memory tasks for the preview.</p>
<h2>Step 4: Add a Preview #Preview(traits:</h2>
<p>Now, let&#8217;s create a dynamic preview</p>
<pre><code class="language-swift" data-line="">#Preview(traits: .sampleTaskData) {
    TaskListView()
}</code></pre>
<h2>Step 5. Add <code class="" data-line="">@Previewable</code> to Preview</h2>
<p>Now, we&#8217;ll use the <code class="" data-line="">@Previewable</code> attribute inside the <code class="" data-line="">#Preview</code> macro to interact with the <code class="" data-line="">Task</code> completion status dynamically.</p>
<pre><code class="language-swift" data-line="">#Preview(&quot;Dynamic Task Preview&quot;) {
    @Previewable @State var isTaskCompleted = false
    let sampleTask = Task(title: &quot;Complete SwiftUI Project&quot;, isCompleted: isTaskCompleted)
    
    return HStack {
        Text(sampleTask.title ?? &quot;&quot;)
            .font(.title2)
            .foregroundColor(sampleTask.isCompleted ? .green : .black)
        
        Spacer()
        
        Toggle(&quot;&quot;, isOn: $isTaskCompleted)
    }
}</code></pre>
<p>In this preview:</p>
<ul>
<li>The <code class="" data-line="">@Previewable</code> attribute tags the <code class="" data-line="">isTaskCompleted</code> state variable.</li>
<li>This allows you to toggle the state of <code class="" data-line="">isTaskCompleted</code> directly in the Xcode preview and see real-time changes.</li>
<li>The task’s completion status will update dynamically as you interact with the toggle in the preview.</li>
</ul>
<p>This tutorial demonstrated how to display sample SwiftData in SwiftUI with PreviewModifier and @Previewable</p>
<p>The post <a href="https://appmakers.dev/how-to-display-sample-swiftdata-in-swiftui-with-previewmodifier/">How to display sample SwiftData in SwiftUI with PreviewModifier</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Structs vs. Classes in SwiftUI: When to Use Each and why we use Classes in SwiftData</title>
		<link>https://appmakers.dev/structs-vs-classes-in-swiftui-swiftdata/</link>
		
		<dc:creator><![CDATA[AppMakers]]></dc:creator>
		<pubDate>Sun, 13 Oct 2024 13:29:14 +0000</pubDate>
				<category><![CDATA[Export Free]]></category>
		<category><![CDATA[iOS Development]]></category>
		<category><![CDATA[Swift]]></category>
		<category><![CDATA[SwiftUI]]></category>
		<guid isPermaLink="false">https://appmakers.dev/?p=1756</guid>

					<description><![CDATA[<p>In SwiftUI development, a common question arises: Should you use structs or classes for your models? While Swift is optimized for value types (structs), there are certain scenarios where using reference types (classes) becomes necessary, particularly when you work with data persistence frameworks like SwiftData. This article will break down the key differences between structs&#8230;</p>
<p>The post <a href="https://appmakers.dev/structs-vs-classes-in-swiftui-swiftdata/">Structs vs. Classes in SwiftUI: When to Use Each and why we use Classes in SwiftData</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In SwiftUI development, a common question arises: <strong>Should you use structs or classes for your models?</strong> While Swift is optimized for value types (structs), there are certain scenarios where using reference types (classes) becomes necessary, particularly when you work with data persistence frameworks like <strong>SwiftData</strong>.</p>
<p>This article will break down the key differences between structs and classes in modern SwiftUI development and how SwiftData influences these choices.</p>
<h3>The Basics: Structs vs. Classes</h3>
<h4>Structs</h4>
<ul>
<li><strong>Value types</strong>: Structs are copied when passed or assigned to new variables.</li>
<li><strong>Immutable by default</strong>: Changes to a struct instance do not affect other copies.</li>
<li><strong>No ARC (Automatic Reference Counting)</strong>: Structs are more lightweight, and Swift can optimize them for better performance.</li>
<li><strong>Better for simple data</strong>: Ideal for models that represent small, self-contained pieces of data.</li>
</ul>
<h4>Classes</h4>
<ul>
<li><strong>Reference types</strong>: Classes are passed by reference, meaning changes made to one instance affect all references to it.</li>
<li><strong>Mutable by nature</strong>: Changes can propagate across references, which is useful when you need shared state.</li>
<li><strong>Managed by ARC</strong>: Classes come with ARC, which tracks and manages the lifecycle of objects.</li>
<li><strong>Better for shared or complex data</strong>: Ideal for cases where objects need to be shared across different parts of your app or involve relationships.</li>
</ul>
<h3>SwiftUI: Using Structs for Models</h3>
<p>In most SwiftUI applications, <strong>structs</strong> are the default choice for models. Since SwiftUI is designed around declarative programming principles, structs’ value semantics align perfectly with SwiftUI’s philosophy.</p>
<p>Here’s an example of using a struct for a simple <code class="" data-line="">Person</code> model:</p>
<pre><code class="language-swift" data-line="">struct Person {
    var name: String
    var age: Int
}
</code></pre>
<h4>Why Use Structs in SwiftUI?</h4>
<ol>
<li><strong>Performance</strong>: Structs are faster and more efficient due to their value semantics.</li>
<li><strong>Predictability</strong>: Since structs are copied when passed, each instance is independent, which makes it easier to reason about your code.</li>
<li><strong>Concurrency Safety</strong>: Structs’ immutability (unless explicitly mutable) helps avoid issues when working with concurrency.</li>
</ol>
<p>In simple terms, <strong>structs</strong> are great for SwiftUI models when you:</p>
<ul>
<li>Don’t need shared state between views or components.</li>
<li>Are modeling simple data that doesn’t rely on persistence frameworks like SwiftData.</li>
</ul>
<h3>SwiftData and the Case for Classes</h3>
<p>While structs are great for lightweight models, the need for <strong>classes</strong> becomes apparent when working with <strong>SwiftData</strong> (or other persistence frameworks, like Core Data). SwiftData requires <strong>reference semantics</strong>, making <strong>classes</strong> necessary for models to ensure data consistency and lifecycle management.</p>
<p>Here’s an example of a <code class="" data-line="">Person</code> model in SwiftData:</p>
<pre><code class="language-swift" data-line="">import SwiftData

@Model
class Person {
    var name: String
    var age: Int
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}
</code></pre>
<h4>Why Use Classes with SwiftData?</h4>
<ol>
<li><strong>Reference Semantics</strong>: SwiftData needs objects to be shared across multiple components. If you update the <code class="" data-line="">Person</code> class in one part of the app, the changes will automatically reflect everywhere it is referenced.</li>
<li><strong>Persistence</strong>: SwiftData (and Core Data) manages object graphs, relationships, and persistence through reference types.</li>
<li><strong>Complex Relationships</strong>: If your model has relationships (e.g., a <code class="" data-line="">Person</code> having a list of <code class="" data-line="">friends</code>), classes are better suited to managing these references without duplicating data.</li>
</ol>
<p>Thus, <strong>classes</strong> are essential when:</p>
<ul>
<li>You&#8217;re using <strong>SwiftData</strong> or other persistence frameworks that need <strong>managed object contexts</strong>.</li>
<li>Your data is <strong>shared</strong> across multiple parts of the app, and you want to observe and react to changes.</li>
<li>You&#8217;re modeling <strong>complex relationships</strong> between objects.</li>
</ul>
<h3>When to Use Structs vs. Classes: A Recap</h3>
<table>
<thead>
<tr>
<th><strong>Scenario</strong></th>
<th><strong>Use Structs</strong></th>
<th><strong>Use Classes</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>Simple data models</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Immutable data</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Lightweight, performance-sensitive</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Need shared, mutable state</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>Using SwiftData or Core Data</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>Data with complex relationships</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>Concurrency safety</td>
<td>Yes</td>
<td>No</td>
</tr>
</tbody>
</table>
<h3>Final Thoughts</h3>
<p>In modern SwiftUI development (2024 and beyond), <strong>structs</strong> are the default choice for most models due to their performance and value semantics. However, when working with frameworks like <strong>SwiftData</strong>—where persistence, shared state, and reference management are essential—<strong>classes</strong> become a necessity.</p>
<p>To summarize:</p>
<ul>
<li>Use <strong>structs</strong> for lightweight, simple, and self-contained models that don’t require shared state.</li>
<li>Use <strong>classes</strong> when working with <strong>SwiftData</strong> or any scenario where reference semantics and persistence are required.</li>
</ul>
<p>For more about <a href="https://appmakers.dev/swift-classes-and-structs/">Classes and Structs read this Article</a></p>
<p>Understanding when to use structs vs. classes will help you design more efficient and scalable SwiftUI applications. Happy coding!</p>
<p>The post <a href="https://appmakers.dev/structs-vs-classes-in-swiftui-swiftdata/">Structs vs. Classes in SwiftUI: When to Use Each and why we use Classes in SwiftData</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>SwiftUI vs UIKit &#8211; Declarative vs. Imperative Programming</title>
		<link>https://appmakers.dev/swiftui-vs-uikit-declarative-vs-imperative-programming/</link>
		
		<dc:creator><![CDATA[AppMakers]]></dc:creator>
		<pubDate>Sat, 12 Oct 2024 09:23:52 +0000</pubDate>
				<category><![CDATA[App Architecture and Design Patterns]]></category>
		<category><![CDATA[Export Free]]></category>
		<category><![CDATA[iOS Development]]></category>
		<category><![CDATA[SwiftUI]]></category>
		<guid isPermaLink="false">https://appmakers.dev/?p=1746</guid>

					<description><![CDATA[<p>In the world of iOS development, the introduction of SwiftUI brought a significant paradigm shift. SwiftUI, with its declarative nature, presents a contrasting approach to the older, imperative style of UIKit. Understanding the differences between these two frameworks is crucial for iOS developers. In this blog post, we will explore the main differences between declarative&#8230;</p>
<p>The post <a href="https://appmakers.dev/swiftui-vs-uikit-declarative-vs-imperative-programming/">SwiftUI vs UIKit &#8211; Declarative vs. Imperative Programming</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In the world of iOS development, the introduction of SwiftUI brought a significant paradigm shift. SwiftUI, with its declarative nature, presents a contrasting approach to the older, imperative style of UIKit. Understanding the differences between these two frameworks is crucial for iOS developers. In this blog post, we will explore the main differences between declarative and imperative programming concepts as they apply to SwiftUI and UIKit, and how views are updated in both scenarios.</p>
<h2>1. What is Declarative Programming (SwiftUI)?</h2>
<p>SwiftUI is Apple&#8217;s framework introduced in 2019 for developing user interfaces in a declarative way. In declarative UI, you describe <strong>what</strong> the UI should look like, not <strong>how</strong> to create it. You declare your user interface and its behavior in a way that is much closer to natural language, using SwiftUI&#8217;s body property.</p>
<h3>Key Characteristics of SwiftUI:</h3>
<ul>
<li><strong>Less Code</strong>: SwiftUI requires fewer lines of code to achieve the same result as UIKit.</li>
<li><strong>Data-driven</strong>: The UI components are a function of the state. When the state changes, the UI updates automatically.</li>
<li><strong>Consistency Across Platforms</strong>: SwiftUI works across all Apple platforms, providing a unified development experience.</li>
<li><strong>Live Preview</strong>: With SwiftUI, you can see live previews of your UI as you code.</li>
</ul>
<pre><code class="language-swift" data-line="">import SwiftUI

struct ContentView: View {
    @State private var isButtonPressed = false

    var body: some View {
        Button(action: {
            self.isButtonPressed.toggle()
        }) {
            Text(isButtonPressed ? &quot;Pressed!&quot; : &quot;Press Me&quot;)
        }
    }
}
</code></pre>
<p>In this SwiftUI code, we describe a <code class="" data-line="">Button</code> and its behavior. The UI automatically updates when <code class="" data-line="">isButtonPressed</code> changes, without any need for explicit UI manipulation code.</p>
<h2>2. What is Imperative Programming (UIKit)?</h2>
<p>UIKit, the traditional framework used in iOS development, is imperative. This means you instruct the program <strong>how</strong> to perform operations to achieve the desired UI. You manually update the UI based on the state of the application, often leading to more boilerplate code.</p>
<h3>Key Characteristics of UIKit:</h3>
<ul>
<li><strong>Detailed Control</strong>: UIKit gives you granular control over UI elements and their behaviors.</li>
<li><strong>Familiarity and Maturity</strong>: Being older, UIKit has a vast community, resources, and a proven track record.</li>
<li><strong>Manual Updates</strong>: Changes in the UI need to be manually handled, requiring more lines of code and effort.</li>
</ul>
<pre><code class="language-swift" data-line="">import UIKit

class ViewController: UIViewController {
    private var isButtonPressed = false
    private let button = UIButton()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupButton()
    }

    private func setupButton() {
        button.setTitle(&quot;Press Me&quot;, for: .normal)
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
        // additional code to layout the button
    }

    @objc private func buttonTapped() {
        isButtonPressed.toggle()
        updateButtonTitle()
    }

    private func updateButtonTitle() {
        button.setTitle(isButtonPressed ? &quot;Pressed!&quot; : &quot;Press Me&quot;, for: .normal)
    }
}
</code></pre>
<p>In the UIKit example, we manually manage the state and update the UI (button title) based on the user interaction.</p>
<h2>3. SwiftUI vs UIKit &#8211; Main Differences</h2>
<h3>Declarative vs. Imperative:</h3>
<ul>
<li><strong>SwiftUI</strong>: You declare the UI elements and their dependencies on data (datasource). The framework takes care of the rest.</li>
<li><strong>UIKit</strong>: You explicitly create and manage UI elements and their lifecycle.</li>
</ul>
<h3>State Management and UI Updates:</h3>
<ul>
<li><strong>SwiftUI</strong>: The view is a function of the state. Any changes in the state lead to a re-render of the UI.</li>
<li><strong>UIKit</strong>: You have to manually listen to changes and update the UI accordingly.</li>
</ul>
<h3>Code Conciseness and Readability:</h3>
<ul>
<li><strong>SwiftUI</strong>: Less and more readable code. Easier for beginners and reduces the chance of bugs.</li>
<li><strong>UIKit</strong>: More verbose, offering finer control but at the cost of more code.</li>
</ul>
<h2>4. How Views Update in SwiftUI and UIKit</h2>
<h3>SwiftUI:</h3>
<p>In SwiftUI, the view automatically updates when the state changes. SwiftUI&#8217;s view is a struct, which is a value type, ensuring a single source of truth. When the underlying data changes, SwiftUI intelligently re-renders the view to reflect those changes, making the data flow seamless and straightforward.</p>
<h3>UIKit:</h3>
<p>In UIKit, updating the view is a manual process. When the data changes, you need to write additional code to update the UI elements. This approach gives you more control but requires a deeper understanding of the view lifecycle and state management.</p>
<h2>Conclusion</h2>
<p>In summary, SwiftUI&#8217;s declarative nature offers a modern, efficient, and streamlined approach to UI development in iOS, ideal for rapid development and reducing boilerplate code. UIKit, with its imperative approach, provides detailed control and is backed by years of community support and resources. Both have their place in iOS development, and the choice largely depends on the project requirements and developer preference.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>The post <a href="https://appmakers.dev/swiftui-vs-uikit-declarative-vs-imperative-programming/">SwiftUI vs UIKit &#8211; Declarative vs. Imperative Programming</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>SwiftData Tutorial &#8211; How to Implement SwiftData in SwiftUI App</title>
		<link>https://appmakers.dev/swiftdata-tutorial/</link>
		
		<dc:creator><![CDATA[AppMakers]]></dc:creator>
		<pubDate>Sat, 12 Oct 2024 03:46:05 +0000</pubDate>
				<category><![CDATA[SwiftData]]></category>
		<category><![CDATA[SwiftUI]]></category>
		<category><![CDATA[SwiftUI Data and Storage]]></category>
		<category><![CDATA[SwiftUI Tutorials]]></category>
		<guid isPermaLink="false">https://uiexamples.com/?p=572</guid>

					<description><![CDATA[<p>SwiftData offers a seamless way to manage and persist data with minimal effort. In this article, we&#8217;ll explore how to implement a simple SwiftData model, set up persistent storage, and manipulate data within SwiftUI views. Let&#8217;s start our SwiftData Tutorial. What is SwiftData? SwiftData is a data management framework introduced by Apple, designed to integrate&#8230;</p>
<p>The post <a href="https://appmakers.dev/swiftdata-tutorial/">SwiftData Tutorial &#8211; How to Implement SwiftData in SwiftUI App</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>SwiftData offers a seamless way to manage and persist data with minimal effort. In this article, we&#8217;ll explore how to implement a simple SwiftData model, set up persistent storage, and manipulate data within SwiftUI views. Let&#8217;s start our SwiftData Tutorial.</p>
<h2>What is SwiftData?</h2>
<p>SwiftData is a data management framework introduced by Apple, designed to integrate seamlessly with Swift and SwiftUI. It provides a simple yet powerful way to manage and persist data in iOS and macOS apps without needing extensive setup. By leveraging the <code class="" data-line="">@Model</code> macro, developers can define Swift classes as persistent data models, allowing the framework to automatically handle database schemas, change tracking, and data synchronization. SwiftData also supports key features like iCloud syncing, in-memory storage for testing, and relationship management between models, making it an ideal tool for modern app development. Its deep integration with SwiftUI ensures that any changes to your data automatically trigger UI updates, simplifying the development process and enhancing the performance of data-driven apps.</p>
<h3>Step 1: Setting Up Your SwiftData Model</h3>
<p>First, let’s create a model representing something simple. In our case, we&#8217;ll model a <strong>Book</strong>. We&#8217;ll define properties such as the book&#8217;s title, author, and genre. You can add more attributes as needed.</p>
<h4>1.1 Create the Model File</h4>
<ul>
<li>Open Xcodea and. Create a new Swift file called <code class="" data-line="">Book.swift</code>.</li>
<li>Import <code class="" data-line="">SwiftData</code>.</li>
<li>Define your model class with the <code class="" data-line="">@Model</code> macro. This macro ensures that your class is recognized by SwiftData for persistence.</li>
</ul>
<pre><code class="language-swift" data-line="">import SwiftData

@Model
class Book {
    var title: String
    var author: String
    var genre: String?
    
    init(title: String, author: String, genre: String? = nil) {
        self.title = title
        self.author = author
        self.genre = genre
    }
}
</code></pre>
<p><strong>Note</strong>: Optionals are important in SwiftData because non-optional properties must always have a value. If you’re planning future migrations, use optionals (<code class="" data-line="">?</code>) for fields that could be nil.</p>
<h3>Step 2: Setting Up the Main App and Model Container</h3>
<p>Before we can persist and manipulate <code class="" data-line="">Book</code> instances, we need to configure the model container in our main app file.</p>
<h4>2.1 Set Up Model Container</h4>
<ol>
<li>In your main <code class="" data-line="">App</code> file, import <code class="" data-line="">SwiftData</code>.</li>
<li>Use the <code class="" data-line="">.modelContainer</code> modifier to declare the models that should be persisted across app launches.</li>
</ol>
<pre><code class="language-swift" data-line="">import SwiftUI
import SwiftData

@main
struct BookApp: App {
    var body: some Scene {
        WindowGroup {
            MainView().modelContainer(for: [Book.self])
        }
    }
}
</code></pre>
<p>This setup creates a default model container that stores data persistently. If you need to use a different storage method (e.g., in-memory), you can customize it, but for this example, we&#8217;ll stick with the default.</p>
<h3>Step 3: Creating a View to Display and Modify Data</h3>
<p>Now that we have our <code class="" data-line="">Book</code> model and the model container set up, we can create a SwiftUI view to display and modify the data.</p>
<h4>3.1 Fetching Data Using <code class="" data-line="">@Query</code></h4>
<p><span id="more-572"></span></p>
<p>SwiftData simplifies fetching data with the <code class="" data-line="">@Query</code> property wrapper, allowing us to query models and automatically update the UI when data changes.</p>
<pre><code class="language-swift" data-line="">import SwiftUI
import SwiftData

struct MainView: View {
    @Query(sort: \Book.title, order: .forward) private var books: [Book]
    @Environment(\.modelContext) private var context
    
    @State private var newBookTitle = &quot;&quot;
    @State private var newBookAuthor = &quot;&quot;
    @State private var newBookGenre = &quot;&quot;
    
    var body: some View {
        NavigationStack {
            VStack {
                // List of books
                List(books) { book in
                    HStack {
                        Text(book.title)
                        Spacer()
                        Text(book.author)
                    }
                }
                
                // Form to add a new book
                VStack {
                    TextField(&quot;Title&quot;, text: $newBookTitle)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .padding()
                    TextField(&quot;Author&quot;, text: $newBookAuthor)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .padding()
                    TextField(&quot;Genre&quot;, text: $newBookGenre)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .padding()
                    
                    Button(&quot;Add Book&quot;) {
                        addNewBook()
                    }
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(8)
                }
            }
            .navigationTitle(&quot;Books&quot;)
        }
    }
    
    // Function to add a new book
    private func addNewBook() {
        let newBook = Book(title: newBookTitle, author: newBookAuthor, genre: newBookGenre.isEmpty ? nil : newBookGenre)
        context.insert(newBook)
        
        do {
            try context.save()
        } catch {
            print(&quot;Failed to save book: \(error.localizedDescription)&quot;)
        }
        
        // Reset form fields
        newBookTitle = &quot;&quot;
        newBookAuthor = &quot;&quot;
        newBookGenre = &quot;&quot;
    }
}
</code></pre>
<p>Here’s what’s happening:</p>
<ul>
<li><strong>Fetching Data</strong>: The <code class="" data-line="">@Query</code> property fetches all <code class="" data-line="">Book</code> instances, sorted by title.</li>
<li><strong>Environment Model Context</strong>: The <code class="" data-line="">@Environment(\.modelContext)</code> provides access to the current model context for saving or deleting data.</li>
<li><strong>Adding a New Book</strong>: The <code class="" data-line="">addNewBook</code> function inserts a new <code class="" data-line="">Book</code> into the context and saves the changes.</li>
</ul>
<h3>Step 4: Previewing and Working with In-Memory Storage</h3>
<p>For previews and testing, we can use an in-memory container. This prevents saving the data permanently and resets it between preview runs.</p>
<pre><code class="language-swift" data-line="">#Preview {
    MainView().modelContainer(for: [Book.self], inMemory: true)
}
</code></pre>
<p>Using in-memory storage is particularly useful when testing or running previews, as it ensures that each run starts with a clean state.</p>
<h3>Step 5: Deleting a Book</h3>
<p>You can enable deletion of items in the list by adding a swipe-to-delete action. Add this to the <code class="" data-line="">List</code> view:</p>
<pre><code class="language-swift" data-line="">List {
    ForEach(books) { book in
        HStack {
            Text(book.title)
            Spacer()
            Text(book.author)
        }
    }
    .onDelete(perform: deleteBook)
}
</code></pre>
<p>Then, define the <code class="" data-line="">deleteBook</code> function:</p>
<pre><code class="language-swift" data-line="">private func deleteBook(at offsets: IndexSet) {
    for index in offsets {
        context.delete(books[index])
    }
    
    do {
        try context.save()
    } catch {
        print(&quot;Failed to delete book: \(error.localizedDescription)&quot;)
    }
}
</code></pre>
<p>This function removes the selected <code class="" data-line="">Book</code> from the context and saves the change.</p>
<h2>Conclusion</h2>
<p>In this article, we&#8217;ve covered how to:</p>
<ul>
<li>Set up a simple model with SwiftData.</li>
<li>Create a model container to persist data.</li>
<li>Fetch and display data using <code class="" data-line="">@Query</code>.</li>
<li>Add, delete, and persist data within a SwiftUI view.</li>
</ul>
<p>SwiftData is powerful yet straightforward, making data management in SwiftUI apps easier and more efficient. You can further extend this example by adding relationships, more complex attributes, or custom storage configurations. Happy coding!</p>
<p>The post <a href="https://appmakers.dev/swiftdata-tutorial/">SwiftData Tutorial &#8211; How to Implement SwiftData in SwiftUI App</a> appeared first on <a href="https://appmakers.dev">AppMakers.Dev</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
