<?xml version="1.0" encoding="UTF-8"?><feed
	xmlns="http://www.w3.org/2005/Atom"
	xmlns:thr="http://purl.org/syndication/thread/1.0"
	xml:lang="en"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" >
	<title type="text">Designed by Alan in Caledonia!</title>
	<subtitle type="text">Alan Francis</subtitle>

	<updated>2023-07-23T16:10:59Z</updated>

	<link rel="alternate" type="text/html" href="https://alancfrancis.com" />
	<id>http://alancfrancis.com/feed/atom/</id>
	<link rel="self" type="application/atom+xml" href="https://alancfrancis.com/feed/atom/" />

	<generator uri="http://wordpress.com/">WordPress.com</generator>
<link rel="search" type="application/opensearchdescription+xml" href="https://alancfrancis.com/osd.xml" title="Designed by Alan in Caledonia!" />
<link rel="search" type="application/opensearchdescription+xml" href="https://s1.wp.com/opensearch.xml" title="WordPress.com" />
	<link rel='hub' href='https://alancfrancis.com/?pushpress=hub' />
	<entry>
		<author>
			<name>alancfrancis</name>
							<uri>https://alancfrancis.wordpress.com</uri>
						</author>

		<title type="html"><![CDATA[Part 10: Roundup]]></title>
		<link rel="alternate" type="text/html" href="https://alancfrancis.com/2023/07/23/part-10-roundup/" />

		<id>http://alancfrancis.com/?p=2983</id>
		<updated>2023-07-23T16:10:59Z</updated>
		<published>2023-07-23T16:01:47Z</published>
		<category scheme="https://alancfrancis.com" term="Uncategorized" />
		<summary type="html"><![CDATA[So I&#8217;m done. The point of these articles was for me to figure out how much code could really be shared between Mac, iOS, tvOS and watch (and even in part 8b, visionOS) and the answer is: all of it. Here&#8217;s the final project structure as of Part 9. We have a shared Model folder [&#8230;]]]></summary>

					<content type="html" xml:base="https://alancfrancis.com/2023/07/23/part-10-roundup/"><![CDATA[
<p>So I&#8217;m done.  The point of these articles was for me to figure out how much code could really be shared between Mac, iOS, tvOS and watch (and even in part 8b, visionOS) and the answer is:  all of it.</p>



<p>Here&#8217;s the final project structure as of Part 9.</p>



<hr class="wp-block-separator has-alpha-channel-opacity" />



<div class="wp-block-jetpack-layout-grid column1-desktop-grid__span-6 column1-desktop-grid__row-1 column2-desktop-grid__span-6 column2-desktop-grid__start-7 column2-desktop-grid__row-1 column1-tablet-grid__span-4 column1-tablet-grid__row-1 column2-tablet-grid__span-4 column2-tablet-grid__start-5 column2-tablet-grid__row-1 column1-mobile-grid__span-4 column1-mobile-grid__row-1 column2-mobile-grid__span-4 column2-mobile-grid__row-2">
<div class="wp-block-jetpack-layout-grid-column wp-block-jetpack-layout-grid__padding-none">
<figure class="wp-block-image size-large"><img width="601" height="1024" data-attachment-id="2991" data-permalink="https://alancfrancis.com/2023/07/23/part-10-roundup/screenshot-2023-07-23-at-16-49-13/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.13.png" data-orig-size="798,1360" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-23-at-16.49.13" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.13.png?w=176" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.13.png?w=601" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.13.png?w=601" alt="" class="wp-image-2991" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.13.png?w=601 601w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.13.png?w=88 88w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.13.png?w=176 176w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.13.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.13.png 798w" sizes="(max-width: 601px) 100vw, 601px" /></figure>
</div>



<div class="wp-block-jetpack-layout-grid-column wp-block-jetpack-layout-grid__padding-none is-vertically-aligned-top">
<p>We have a shared Model folder containing the CoreData/CloudKit model and persistence classes.</p>



<p>We have an <code>Apps/AppShared</code> folder containing the <code>App</code> and its <code>ContentView</code>.  The only reason the <code>ListOfThingsView</code> was pulled out was because I made a decision to keep interactivity only available on iOS due to expediency and my own lack of experience.  There&#8217;s no real reason to split these views and so it could have been in <code>AppShared</code> too.</p>



<p>That leaves the<code> Apps/JustOneThing</code> and <code>Apps/JustOneThingWatch</code> folder &#8211; one for each target containing just configuration information &#8211; The <code>Info.plist</code> and per target <code>entitlements</code>.</p>
</div>
</div>



<div class="wp-block-jetpack-layout-grid column1-desktop-grid__span-6 column1-desktop-grid__row-1 column2-desktop-grid__span-6 column2-desktop-grid__start-7 column2-desktop-grid__row-1 column1-tablet-grid__span-4 column1-tablet-grid__row-1 column2-tablet-grid__span-4 column2-tablet-grid__start-5 column2-tablet-grid__row-1 column1-mobile-grid__span-4 column1-mobile-grid__row-1 column2-mobile-grid__span-4 column2-mobile-grid__row-2">
<div class="wp-block-jetpack-layout-grid-column wp-block-jetpack-layout-grid__padding-none is-vertically-aligned-center">
<p>On the Widget side, we have our <code>Widgets/WidgetShared</code> folder that contains our <code>System</code> and <code>Accessory</code> widgets, each of which can be used on multiple platforms, along with the widget bundle that collects them.  A single TimelineProvider is there too, and all the assets.  In the case of the Widgets (unlike the apps) we&#8217;re able to share the <code>Info.plist</code>.  This folder also contains the <code>Intent Definition</code> file.</p>



<p>Each of the target specific folders for Mac, Phone and Watch widgets only contains the platform&#8217;s <code>entitlements</code> file.</p>
</div>



<div class="wp-block-jetpack-layout-grid-column wp-block-jetpack-layout-grid__padding-none is-vertically-aligned-top">
<figure class="wp-block-image size-large"><img width="646" height="1023" data-attachment-id="2993" data-permalink="https://alancfrancis.com/2023/07/23/part-10-roundup/screenshot-2023-07-23-at-16-49-22/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.22.png" data-orig-size="798,1264" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-23-at-16.49.22" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.22.png?w=189" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.22.png?w=646" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.22.png?w=646" alt="" class="wp-image-2993" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.22.png?w=646 646w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.22.png?w=95 95w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.22.png?w=189 189w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.22.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.49.22.png 798w" sizes="(max-width: 646px) 100vw, 646px" /></figure>
</div>
</div>



<hr class="wp-block-separator has-alpha-channel-opacity" />



<p>I&#8217;ve been at pains to point out throughout that this is not really a full, complicated project.  It&#8217;s still pretty close the templates Xcode generates, just coalesced into a single project.  Xcode templates showed us how to use a CloudKit data store in a SwiftUI app.  Xcode templates showed us how to make a Multiplatform app.  Xcode templates showed us how to create configurable widgets for all three platforms.  </p>



<p>It&#8217;s been fun to try and pull them all together and figure out where they overlap and where they differ.   The end result, I hope, make it clear where we can save time (and maybe bugs) by changing code once, instead of multiple, repeated places.</p>



<p></p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://alancfrancis.com/2023/07/23/part-10-roundup/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://alancfrancis.com/2023/07/23/part-10-roundup/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>alancfrancis</name>
							<uri>https://alancfrancis.wordpress.com</uri>
						</author>

		<title type="html"><![CDATA[Part 9: Going Live]]></title>
		<link rel="alternate" type="text/html" href="https://alancfrancis.com/2023/07/23/part-9-going-live/" />

		<id>http://alancfrancis.com/?p=2963</id>
		<updated>2023-07-23T16:09:11Z</updated>
		<published>2023-07-23T15:01:43Z</published>
		<category scheme="https://alancfrancis.com" term="Uncategorized" />
		<summary type="html"><![CDATA[So this is the last part of this little series. In this part I swap in the CoreData/CloudKit store and display random things from there in the widgets. Usual disclaimers apply, this is absolutely not production code, its purely a hacked together experiment to see what I need, don&#8217;t need, can combine or needs to [&#8230;]]]></summary>

					<content type="html" xml:base="https://alancfrancis.com/2023/07/23/part-9-going-live/"><![CDATA[
<p>So this is the last part of this little series.   In this part I swap in the CoreData/CloudKit store and display random things from there in the widgets.</p>



<p>Usual disclaimers apply, this is absolutely not production code, its purely a hacked together experiment to see what I need, don&#8217;t need, can combine or needs to stay distinct <img src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>So for this last commit we need to make a new <code>ThingDataStore</code> to provide a set of <code>shuffledThings</code>.  I added this about <code>ThingDataStore</code> in <code>JustOneThingProvider.swift</code></p>



<figure class="wp-block-image size-large"><img width="1024" height="512" data-attachment-id="2966" data-permalink="https://alancfrancis.com/2023/07/23/part-9-going-live/screenshot-2023-07-23-at-15-44-29/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.44.29.png" data-orig-size="1532,766" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-23-at-15.44.29" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.44.29.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.44.29.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.44.29.png?w=1024" alt="" class="wp-image-2966" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.44.29.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.44.29.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.44.29.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.44.29.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.44.29.png 1532w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>All it does is pull all the <code>PersistentThings</code> from the database and provide a way to return them shuffled.  You&#8217;ll notice I map the results using a property <code>asThing</code></p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="565" data-attachment-id="2969" data-permalink="https://alancfrancis.com/2023/07/23/part-9-going-live/screenshot-2023-07-23-at-15-39-13/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.39.13.png" data-orig-size="1428,788" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-23-at-15.39.13" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.39.13.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.39.13.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.39.13.png?w=1024" alt="" class="wp-image-2969" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.39.13.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.39.13.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.39.13.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.39.13.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.39.13.png 1428w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>I added this as <code>PersistentThingExtension.swift</code> and it provides a basic encapsulation. of the request (in case we want to filter in some way later) and a conversion from a <code>PersistentThing</code> (a <code>CoreData</code> <code>ManagedObject</code>) to a Thing, our value type struct.  It also hard codes what to do if either is null.</p>



<p>So our <code>ThingCoreDataStore</code> provides a shuffled set of <code>Things</code>, just like the other store, only these are loaded from CloudKit.</p>



<p>With all that in place we can now switch the Provider over to using the new DataStore and we&#8217;re good to go!.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1014" height="276" data-attachment-id="2971" data-permalink="https://alancfrancis.com/2023/07/23/part-9-going-live/screenshot-2023-07-23-at-15-52-19/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.52.19.png" data-orig-size="1014,276" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-23-at-15.52.19" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.52.19.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.52.19.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.52.19.png?w=1014" alt="" class="wp-image-2971" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.52.19.png 1014w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.52.19.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.52.19.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.52.19.png?w=768 768w" sizes="(max-width: 1014px) 100vw, 1014px" /></figure>



<p>Lets make sure the app is using the right PersistenceController and we&#8217;ll commit.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="890" height="324" data-attachment-id="2980" data-permalink="https://alancfrancis.com/2023/07/23/part-9-going-live/screenshot-2023-07-23-at-16-00-28/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.00.28.png" data-orig-size="890,324" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-23-at-16.00.28" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.00.28.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.00.28.png?w=890" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.00.28.png?w=890" alt="" class="wp-image-2980" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.00.28.png 890w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.00.28.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.00.28.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-16.00.28.png?w=768 768w" sizes="(max-width: 890px) 100vw, 890px" /></figure>



<p>That&#8217;s in the repo as &#8220;Part 9: Load the Things from CoreData&#8221;.</p>



<p></p>



<p>Here&#8217;s the widgets on a Phone screen&#8230;</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="658" height="1024" data-attachment-id="2972" data-permalink="https://alancfrancis.com/2023/07/23/part-9-going-live/screenshot-2023-07-23-at-15-38-10/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.38.10.png" data-orig-size="722,1124" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-23-at-15.38.10" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.38.10.png?w=193" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.38.10.png?w=658" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.38.10.png?w=658" alt="" class="wp-image-2972" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.38.10.png?w=658 658w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.38.10.png?w=96 96w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.38.10.png?w=193 193w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.38.10.png 722w" sizes="(max-width: 658px) 100vw, 658px" /></figure>



<p>and on the Mac Notification Center</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="759" data-attachment-id="2974" data-permalink="https://alancfrancis.com/2023/07/23/part-9-going-live/screenshot-2023-07-23-at-15-31-47/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.31.47.png" data-orig-size="1790,1328" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-23-at-15.31.47" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.31.47.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.31.47.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.31.47.png?w=1024" alt="" class="wp-image-2974" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.31.47.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.31.47.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.31.47.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.31.47.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-23-at-15.31.47.png 1790w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>One thing I have discovered and have not yet found a way round for, you&#8217;ll see in the iPhone screenshot above.   If you add the same size widget multiple times and don&#8217;t have any <code>ConfigurationIntent</code> parameters to change, each displayed widget is coming from the same instance.  It&#8217;s not possible to have each instance pull a different random <code>Thing</code>.  In essence there&#8217;s only a single <code>SystemWidget</code> instance for each size, that single instance pulls a random Thing and then its view is just blotted as many times as necessary.</p>



<p>This was kind of a pain for me as I quite liked the idea of having a random thing on each page of my phone.  I could work around it by adding a purely synthetic integer configuration parameter &#8220;widget number&#8221; and changing it for each widget so they all become distinct and pull a different random <code>Thing</code>, but that&#8217;s beyond the scope of this little exercise.</p>



<p>I hope its been useful!</p>



<p></p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://alancfrancis.com/2023/07/23/part-9-going-live/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://alancfrancis.com/2023/07/23/part-9-going-live/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>alancfrancis</name>
							<uri>https://alancfrancis.wordpress.com</uri>
						</author>

		<title type="html"><![CDATA[Part 8b: One vision]]></title>
		<link rel="alternate" type="text/html" href="https://alancfrancis.com/2023/07/14/part-8b-one-vision/" />

		<id>http://alancfrancis.com/?p=2931</id>
		<updated>2023-07-23T16:04:20Z</updated>
		<published>2023-07-14T21:01:38Z</published>
		<category scheme="https://alancfrancis.com" term="Uncategorized" />
		<summary type="html"><![CDATA[Just for shits and giggles I opened the project in Xcode15 and added visionOS as a supported platform on the main app. I had to revisit the widget embedding to restrict the right widgets to the right platforms as Xcode had reset them to all platforms. I added a simple AppIcon for visionOS. (two layers, [&#8230;]]]></summary>

					<content type="html" xml:base="https://alancfrancis.com/2023/07/14/part-8b-one-vision/"><![CDATA[
<p>Just for shits and giggles I opened the project in Xcode15 and added visionOS as a supported platform on the main app.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="512" data-attachment-id="2933" data-permalink="https://alancfrancis.com/2023/07/14/part-8b-one-vision/screenshot-2023-07-14-at-21-50-45/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.45.png" data-orig-size="1382,692" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-14-at-21.50.45" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.45.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.45.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.45.png?w=1024" alt="" class="wp-image-2933" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.45.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.45.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.45.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.45.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.45.png 1382w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>I had to revisit the widget embedding to restrict the right widgets to the right platforms as Xcode had reset them to all platforms.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="274" data-attachment-id="2935" data-permalink="https://alancfrancis.com/2023/07/14/part-8b-one-vision/screenshot-2023-07-14-at-21-50-54/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.54.png" data-orig-size="1502,402" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-14-at-21.50.54" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.54.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.54.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.54.png?w=1024" alt="" class="wp-image-2935" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.54.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.54.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.54.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.54.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.50.54.png 1502w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>I added a simple AppIcon for visionOS. (two layers, 1024px @2x)</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="744" data-attachment-id="2939" data-permalink="https://alancfrancis.com/2023/07/14/part-8b-one-vision/screenshot-2023-07-14-at-21-51-19/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.51.19.png" data-orig-size="1442,1048" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-14-at-21.51.19" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.51.19.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.51.19.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.51.19.png?w=1024" alt="" class="wp-image-2939" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.51.19.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.51.19.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.51.19.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.51.19.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.51.19.png 1442w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>I also changed the <code>ContentView</code> where I had been restrictive in the else case <code>(if iOS elseif tv | Mac | watch ) </code>and made it just a straight <code>if iOS else....</code></p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="247" data-attachment-id="2937" data-permalink="https://alancfrancis.com/2023/07/14/part-8b-one-vision/screenshot-2023-07-14-at-21-54-33/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.54.33.png" data-orig-size="1448,350" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-14-at-21.54.33" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.54.33.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.54.33.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.54.33.png?w=1024" alt="" class="wp-image-2937" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.54.33.png?w=1022 1022w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.54.33.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.54.33.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.54.33.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.54.33.png 1448w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>I assumed this would mean my editable list was still just iOS and vision would use the readonly list.</p>



<p>Apparently not.</p>



<figure class="wp-block-video wp-block-embed is-type-video is-provider-videopress"><div class="wp-block-embed__wrapper">
<iframe title='VideoPress Video Player' aria-label='VideoPress Video Player' width='1000' height='750' src='https://video.wordpress.com/embed/eMpY6iMF?cover=1&amp;preloadContent=metadata&amp;useAverageColor=1&amp;hd=0' frameborder='0' allowfullscreen data-resize-to-parent="true"  allow='clipboard-write' ></iframe><script src='https://v0.wordpress.com/js/next/videopress-iframe.js?m=1674852142'></script>
</div></figure>



<p>I&#8217;m not clear why but it seems to prefer the iOS branch and shows the editable list <img src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>Anyway, I&#8217;ll be back on the main branch and the shipping Xcode for me later, this is just a little diversion at the <a href="https://git.alancfrancis.com/acf/JustOneThing/src/branch/xcode15-and-vision">xcode15-and-vision branch</a>.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://alancfrancis.com/2023/07/14/part-8b-one-vision/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://alancfrancis.com/2023/07/14/part-8b-one-vision/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>alancfrancis</name>
							<uri>https://alancfrancis.wordpress.com</uri>
						</author>

		<title type="html"><![CDATA[Part 8: A Quick App UI]]></title>
		<link rel="alternate" type="text/html" href="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/" />

		<id>http://alancfrancis.com/?p=2892</id>
		<updated>2023-07-23T16:03:42Z</updated>
		<published>2023-07-14T20:27:42Z</published>
		<category scheme="https://alancfrancis.com" term="Uncategorized" />
		<summary type="html"><![CDATA[This is probably the part I am least relaxed about doing in public as I really have no idea what I&#8217;m doing. 🙂 I made a new CoreData SwiftUI project and essentially stole the guts of that to make it work in my app. All it has to do, really, is show a big list [&#8230;]]]></summary>

					<content type="html" xml:base="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/"><![CDATA[
<p>This is probably the part I am least relaxed about doing in public as I really have no idea what I&#8217;m doing. <img src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>I made a new CoreData SwiftUI project and essentially stole the guts of that to make it work in my app.  All it has to do, really, is show a big list of All The Things.  It was relatively easy for me to add Add+Delete functionality on iOS so that&#8217;s what I did.  iOS can create and delete Things, all the other platforms just show a read only list.</p>



<h2 class="wp-block-heading">Environmental Context</h2>



<p>The first step is making the shared context from our persistence controller available to the app.  We do this through the SwiftUI environment.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="249" data-attachment-id="2900" data-permalink="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/screenshot-2023-07-14-at-20-53-52/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-20.53.52.png" data-orig-size="1600,390" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-14-at-20.53.52" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-20.53.52.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-20.53.52.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-20.53.52.png?w=1024" alt="" class="wp-image-2900" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-20.53.52.png?w=1022 1022w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-20.53.52.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-20.53.52.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-20.53.52.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-20.53.52.png 1600w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Since there&#8217;s no way to add any items for display yet, You can see above I added back the preview version of the <code>PersistenceController</code>.  Again this is just Apple&#8217;s template code unchanged apart from  adjustments for my own Entities.</p>



<p>It provides an in-memory, disposable context with 10 Things in it so we can </p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="763" data-attachment-id="2898" data-permalink="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/screenshot-2023-07-10-at-21-35-25/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.25.png" data-orig-size="1242,926" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-10-at-21.35.25" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.25.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.25.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.25.png?w=1024" alt="" class="wp-image-2898" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.25.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.25.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.25.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.25.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.25.png 1242w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>We can swap the app property from <code>PersistenceController.preview</code> to <code>PersistenceController.shared</code> when we&#8217;re happy.</p>



<hr class="wp-block-separator has-alpha-channel-opacity" />



<h2 class="wp-block-heading">List Views</h2>



<p>Next up I added two separate ListViews.  The first is in <code>AppShared</code> and added to both app targets because it works across Watch and Mac+TV+Phone and I called it <code>SimpleListOfThingsView</code></p>



<figure class="wp-block-image size-large"><img loading="lazy" width="510" height="226" data-attachment-id="2902" data-permalink="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/screenshot-2023-07-10-at-21-35-52/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.52.png" data-orig-size="510,226" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-10-at-21.35.52" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.52.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.52.png?w=510" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.52.png?w=510" alt="" class="wp-image-2902" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.52.png 510w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.52.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.52.png?w=300 300w" sizes="(max-width: 510px) 100vw, 510px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="535" data-attachment-id="2903" data-permalink="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/screenshot-2023-07-10-at-21-35-59/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.59.png" data-orig-size="1296,678" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-10-at-21.35.59" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.59.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.59.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.59.png?w=1024" alt="" class="wp-image-2903" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.59.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.59.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.59.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.59.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.59.png 1296w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>It&#8217;s dirt simple and just uses the environment context to fetch all the Things, sorted by oldest first, and displays them in a list.  </p>



<p>Here&#8217;s how it looks on a Mac, TV and Watch.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="978" height="508" data-attachment-id="2909" data-permalink="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/screenshot-2023-07-14-at-21-03-48-1/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.03.48-1.png" data-orig-size="978,508" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-14-at-21.03.48-1" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.03.48-1.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.03.48-1.png?w=978" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.03.48-1.png?w=978" alt="" class="wp-image-2909" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.03.48-1.png 978w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.03.48-1.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.03.48-1.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.03.48-1.png?w=768 768w" sizes="(max-width: 978px) 100vw, 978px" /></figure>



<figure data-carousel-extra='{"blog_id":122971807,"permalink":"https:\/\/alancfrancis.com\/2023\/07\/14\/part-8-a-quick-app-ui\/"}'  class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="924" data-attachment-id="2908" data-permalink="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/screenshot-2023-07-14-at-21-05-45/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.05.45.png" data-orig-size="1052,950" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-14-at-21.05.45" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.05.45.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.05.45.png?w=1000" tabindex="0" role="button" data-id="2908" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.05.45.png?w=1024" alt="" class="wp-image-2908" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.05.45.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.05.45.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.05.45.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.05.45.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.05.45.png 1052w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="536" height="558" data-attachment-id="2906" data-permalink="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/screenshot-2023-07-14-at-21-06-40/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.06.40.png" data-orig-size="536,558" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-14-at-21.06.40" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.06.40.png?w=288" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.06.40.png?w=536" tabindex="0" role="button" data-id="2906" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.06.40.png?w=536" alt="" class="wp-image-2906" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.06.40.png 536w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.06.40.png?w=144 144w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.06.40.png?w=288 288w" sizes="(max-width: 536px) 100vw, 536px" /></figure>
</figure>



<p>Nothing to write home about but it works.</p>



<p>Next we&#8217;ll create the version for the iPhone.  I&#8217;ve added this just to the Apps -&gt; JustOneThing folder and just the app target as it&#8217;s specific to the Phone app.  Its just called <code>ListOfThingsView</code></p>



<figure class="wp-block-image size-large"><img loading="lazy" width="484" height="198" data-attachment-id="2911" data-permalink="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/screenshot-2023-07-10-at-21-36-09/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.09.png" data-orig-size="484,198" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-10-at-21.36.09" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.09.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.09.png?w=484" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.09.png?w=484" alt="" class="wp-image-2911" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.09.png 484w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.09.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.09.png?w=300 300w" sizes="(max-width: 484px) 100vw, 484px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="249" data-attachment-id="2912" data-permalink="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/screenshot-2023-07-10-at-21-36-35/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.35.png" data-orig-size="1288,314" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-10-at-21.36.35" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.35.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.35.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.35.png?w=1024" alt="" class="wp-image-2912" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.35.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.35.png?w=1021 1021w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.35.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.35.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.35.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.35.png 1288w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Again this is just lifted directly from the new project I made.  The top of the View looks basically the same as the <code>SimpleListOfThingsView</code> but it comes with the add and remove methods that Apple&#8217;s template provided.</p>



<p></p>



<p>Here&#8217;s the body.  You can see the issue with using the CoreData entity directly since all its fields are optional I&#8217;m supplying default text everywhere for now.  We&#8217;ll fix that when we add a translation layer between our <code>PersistentThing</code> class and our <code>Thing</code> value type later.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="779" data-attachment-id="2914" data-permalink="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/screenshot-2023-07-10-at-21-36-43/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.43.png" data-orig-size="1256,956" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-10-at-21.36.43" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.43.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.43.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.43.png?w=1024" alt="" class="wp-image-2914" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.43.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.43.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.43.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.43.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.43.png 1256w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>The <code>addItem</code> method just creates a <code>PersistentThing</code> with no user input (Apple&#8217;s sample unchanged).</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="555" data-attachment-id="2916" data-permalink="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/screenshot-2023-07-10-at-21-36-53/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.53.png" data-orig-size="1346,730" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-10-at-21.36.53" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.53.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.53.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.53.png?w=1024" alt="" class="wp-image-2916" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.53.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.53.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.53.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.53.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.36.53.png 1346w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>and the <code>deleteItems</code> machinery is unchanged.  </p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="468" data-attachment-id="2919" data-permalink="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/screenshot-2023-07-10-at-21-37-00/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.37.00.png" data-orig-size="1312,600" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-10-at-21.37.00" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.37.00.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.37.00.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.37.00.png?w=1024" alt="" class="wp-image-2919" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.37.00.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.37.00.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.37.00.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.37.00.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.37.00.png 1312w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>I tried to get the swipe deletion working on the Mac but gave up as (like I&#8217;ve said) I really don&#8217;t care about the app UI I just want to work on the widgets.  Hence its just the iOS app that provides any kind of interaction.</p>



<p>On iOS the view looks like this and of course the edit button and swiping to delete works fine.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="754" height="1008" data-attachment-id="2924" data-permalink="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/screenshot-2023-07-14-at-21-18-38/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.18.38.png" data-orig-size="754,1008" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-14-at-21.18.38" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.18.38.png?w=224" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.18.38.png?w=754" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.18.38.png?w=754" alt="" class="wp-image-2924" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.18.38.png 754w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.18.38.png?w=112 112w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-14-at-21.18.38.png?w=224 224w" sizes="(max-width: 754px) 100vw, 754px" /></figure>



<p>The last step it to use these two new views in the app.  For that we make a change to the <code>ContentView</code> to load the right view on the right platform.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="287" data-attachment-id="2922" data-permalink="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/screenshot-2023-07-10-at-21-35-46/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.46.png" data-orig-size="1324,372" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-10-at-21.35.46" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.46.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.46.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.46.png?w=1024" alt="" class="wp-image-2922" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.46.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.46.png?w=1021 1021w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.46.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.46.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.46.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-10-at-21.35.46.png 1324w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>At this point we can test out both views on all the various simulators and when we&#8217;;re happy they work we can switch the <code>PersistenceController</code> in the app from <code>.preview</code> to <code>.shared</code> and try it all out.  If you sign into iCloud on the various platforms and simulators you should be able to create things on iPhone and see them appear on tv, Mac and watch.</p>



<p>One issue I have been unable to resolve is that it can take some time for a first run of an app to download its initial set of data from iCloud, leading me to believe it hadn&#8217;t worked. I&#8217;d love some way to put up, if not a modal, then some kind of indicator that says &#8220;hold on while I do the first sync of data&#8221;.  But because it&#8217;s all happening in the background and you&#8217;re not supposed to care, there doesn&#8217;t seem to be an easy way to be notified. (Happy to accept answers on a postcard).</p>



<p>Lets commit!  It&#8217;s under &#8220;Part 8: A Quick and Dirty App UI&#8221;  <a href="https://git.alancfrancis.com/acf/JustOneThing">in the repo</a>.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://alancfrancis.com/2023/07/14/part-8-a-quick-app-ui/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>alancfrancis</name>
							<uri>https://alancfrancis.wordpress.com</uri>
						</author>

		<title type="html"><![CDATA[Part 7: CloudKit]]></title>
		<link rel="alternate" type="text/html" href="https://alancfrancis.com/2023/07/07/part-7-cloudkit/" />

		<id>http://alancfrancis.com/?p=2806</id>
		<updated>2023-07-08T18:15:51Z</updated>
		<published>2023-07-07T14:45:40Z</published>
		<category scheme="https://alancfrancis.com" term="Uncategorized" />
		<summary type="html"><![CDATA[I&#8217;ve put it off for as long as I can but here&#8217;s the boring post on adding CloudKit. The first thing we need to do is add some capabilities to the apps and widget extensions. We&#8217;ll make them all part of the same app group, and then add background modes for push notifications, which CloudKit [&#8230;]]]></summary>

					<content type="html" xml:base="https://alancfrancis.com/2023/07/07/part-7-cloudkit/"><![CDATA[
<p>I&#8217;ve put it off for as long as I can but here&#8217;s the boring post on adding CloudKit.</p>



<p>The first thing we need to do is add some capabilities to the apps and widget extensions.  We&#8217;ll make them all part of the same app group, and then add background modes for push notifications, which CloudKit needs to keep our database up to date.</p>



<p>As I&#8217;ve mentioned before, it could be that SwiftData has added simpler ways to do these things but this is essentially documenting what I did earlier this year with CloudKit as the easiest way to share data between the widgets on all the platforms.</p>



<hr class="wp-block-separator has-alpha-channel-opacity" />



<h2 class="wp-block-heading">App Group</h2>



<p>First we need to add all 5 targets (two apps, 3 widgets) to the same AppGroup.  I started with the main app but you can pick any target to be first.</p>



<p>We&#8217;re going to select the target and the signing and capabilities target and you should see the app groups entitlement we added before.  If we click the (+) we can add a new app group.  I tend to use reverse DNS and since this is across multiple platforms I use <code>.apps.</code> between the domain name and the app name.  Note that it has to start with <code>group.</code></p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="502" data-attachment-id="2810" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-11-11-23/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.23.png" data-orig-size="1766,866" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-11.11.23" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.23.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.23.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.23.png?w=1024" alt="" class="wp-image-2810" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.23.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.23.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.23.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.23.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.23.png 1766w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>If you start with the main app make sure you see the app group in both the macOS and the iOS/tvOS sections.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="293" data-attachment-id="2814" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-11-11-58/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.58.png" data-orig-size="1966,564" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-11.11.58" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.58.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.58.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.58.png?w=1024" alt="" class="wp-image-2814" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.58.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.58.png?w=1021 1021w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.58.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.58.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.58.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.11.58.png 1966w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Once that&#8217;s done we can go to each of the other four targets and just enable that new group by checking the apparently-disabled-but-not-really checkbox.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="229" data-attachment-id="2815" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-11-12-07/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.12.07.png" data-orig-size="1430,320" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-11.12.07" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.12.07.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.12.07.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.12.07.png?w=1024" alt="" class="wp-image-2815" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.12.07.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.12.07.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.12.07.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.12.07.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.12.07.png 1430w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>An odd note.  First time I did this all was well.  Second time I found I hit a problem with the Mac Widget extension and somehow I couldn&#8217;t access app groups in the UI.  If this happens you can edit any of the other entitlements files <strong>as source</strong> and copy and paste the app groups section into the Mac widget entitlements.  Its the same text everywhere.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="169" data-attachment-id="2818" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-14-56-41/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.56.41.png" data-orig-size="1114,184" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-14.56.41" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.56.41.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.56.41.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.56.41.png?w=1024" alt="" class="wp-image-2818" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.56.41.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.56.41.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.56.41.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.56.41.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.56.41.png 1114w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Next we&#8217;re going to go back to each target in turn and add the &#8220;iCloud&#8221; entitlement.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="753" data-attachment-id="2819" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-11-22-10/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.22.10.png" data-orig-size="1444,1062" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-11.22.10" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.22.10.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.22.10.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.22.10.png?w=1024" alt="" class="wp-image-2819" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.22.10.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.22.10.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.22.10.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.22.10.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.22.10.png 1444w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>We&#8217;ll choose CloudKit, and add a new container in one of the targets, and then select that container in all the other targets.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="597" data-attachment-id="2821" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-11-23-04/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.23.04.png" data-orig-size="1470,858" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-11.23.04" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.23.04.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.23.04.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.23.04.png?w=1024" alt="" class="wp-image-2821" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.23.04.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.23.04.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.23.04.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.23.04.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.23.04.png 1470w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="417" data-attachment-id="2822" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-15-00-42/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.00.42.png" data-orig-size="1098,448" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-15.00.42" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.00.42.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.00.42.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.00.42.png?w=1024" alt="" class="wp-image-2822" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.00.42.png?w=1022 1022w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.00.42.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.00.42.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.00.42.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.00.42.png 1098w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Now all the apps and widgets will talk to iCloud and all will share data.</p>



<p>I committed here to keep things tidy, and so the diff is more obvious about what each step does.  Its &#8220;Part 7: Data Sharing Entitlements&#8221;</p>



<h2 class="wp-block-heading">Background Modes</h2>



<p>CloudKit works using silent push notifications to keep our data up to date, so we need to enable that for the two app targets (not the widgets).  Add the Background Modes entitlement to the main app (twice, once for iOS, once for tvOS) and then again to the Watch app target.</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" data-attachment-id="2826" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-12-06-04/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.04.png" data-orig-size="714,452" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-12.06.04" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.04.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.04.png?w=714" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.04.png?w=714" alt="" class="wp-image-2826" width="690" height="437" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.04.png?w=690 690w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.04.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.04.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.04.png 714w" sizes="(max-width: 690px) 100vw, 690px" /></figure>



<p>In both targets we need to check Remote Notifications (twice in the main app, once in the watch app).</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="442" data-attachment-id="2828" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-12-06-59/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.59.png" data-orig-size="1998,864" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-12.06.59" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.59.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.59.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.59.png?w=1024" alt="" class="wp-image-2828" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.59.png?w=1022 1022w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.59.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.59.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.59.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.59.png 1998w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="281" data-attachment-id="2829" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-12-06-45/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.45.png" data-orig-size="1606,442" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-12.06.45" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.45.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.45.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.45.png?w=1024" alt="" class="wp-image-2829" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.45.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.45.png?w=1021 1021w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.45.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.45.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.45.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-12.06.45.png 1606w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>There&#8217;s another commit here &#8211; &#8220;Part 7: Background Modes&#8221;</p>



<p>That&#8217;s all the configuration.  Now we need some more code.</p>



<h2 class="wp-block-heading">CoreData and CloudKit</h2>



<p>I shuffled the project structure around a little.  I made a &#8220;new group <strong>WITHOUT</strong> folder&#8221; called Apps and one called Widgets just to pull the various folders together.  Make sure its <strong>WITHOUT</strong> folder for this step otherwise the various paths we&#8217;ve set on the build settings stop working.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="718" height="320" data-attachment-id="2833" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-14-40-25/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.40.25.png" data-orig-size="718,320" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-14.40.25" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.40.25.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.40.25.png?w=718" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.40.25.png?w=718" alt="" class="wp-image-2833" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.40.25.png 718w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.40.25.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.40.25.png?w=300 300w" sizes="(max-width: 718px) 100vw, 718px" /></figure>



<p>Drag the three widgets and the widget shared to the Widgets group.  Drag the two apps and the app shared to the Apps group.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="684" height="468" data-attachment-id="2835" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-15-10-23/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.10.23.png" data-orig-size="684,468" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-15.10.23" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.10.23.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.10.23.png?w=684" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.10.23.png?w=684" alt="" class="wp-image-2835" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.10.23.png 684w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.10.23.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.10.23.png?w=300 300w" sizes="(max-width: 684px) 100vw, 684px" /></figure>



<p>Next I make a new group <strong>WITH</strong> a folder called Model.  This will hold all our persistence code that works across widgets and apps.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="526" height="316" data-attachment-id="2837" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-15-11-53/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.11.53.png" data-orig-size="526,316" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-15.11.53" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.11.53.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.11.53.png?w=526" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.11.53.png?w=526" alt="" class="wp-image-2837" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.11.53.png 526w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.11.53.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.11.53.png?w=300 300w" sizes="(max-width: 526px) 100vw, 526px" /></figure>



<p>I hate this with-or-without-folder stuff as sometimes the specific path matters (like the entitlements) and sometimes it doesn&#8217;t.  As a rule I try and have most things in folders that match the group structure and only use folderless groups at the very top level for collecting stuff together.</p>



<p>The first thing we&#8217;re going to add is a CoreData model, and we&#8217;ll add it to all targets.  I&#8217;ve called it <code>JustOneThingCloudModel</code> which is a bit verbose but I want to clearly distinguish the CoreData persistent model entities from any ViewModel type classes or structs (like <code>Thing</code>).  Maybe <code>SwiftData</code> will make this unnecessary but right now CoreData model properties all have to be nullable and <code>@objc</code> etc so lets leave the CoreData machinery isolated from our SwiftUI+Swift models.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="878" height="684" data-attachment-id="2839" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-11-41-38/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.41.38.png" data-orig-size="878,684" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-11.41.38" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.41.38.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.41.38.png?w=878" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.41.38.png?w=878" alt="" class="wp-image-2839" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.41.38.png 878w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.41.38.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.41.38.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.41.38.png?w=768 768w" sizes="(max-width: 878px) 100vw, 878px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="752" data-attachment-id="2841" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-11-43-36/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.43.36.png" data-orig-size="1410,1036" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-11.43.36" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.43.36.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.43.36.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.43.36.png?w=1024" alt="" class="wp-image-2841" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.43.36.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.43.36.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.43.36.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.43.36.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.43.36.png 1410w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>In that model I&#8217;ve created one entity, <code>PersistentThing</code>, and added properties for the <code>text</code> and <code>createdAt</code> (just like the current Swift model) and a <code>UUID</code> for uniqueness.  I don&#8217;t know for sure that I need that but old habits die hard and I was taught to give my database rows an explicit primary key.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="328" data-attachment-id="2843" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-11-47-05/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.47.05.png" data-orig-size="1326,426" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-11.47.05" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.47.05.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.47.05.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.47.05.png?w=1024" alt="" class="wp-image-2843" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.47.05.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.47.05.png?w=1021 1021w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.47.05.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.47.05.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.47.05.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.47.05.png 1326w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>One last step in this little journey and that&#8217;s to add some way for the apps and widgets to access the CoreData stack.</p>



<p>When you tick the CoreData+CloudKit box on creating a new project, you get a file called <code>Persistence.swift</code> that looks mostly like this.  (it also has some stuff for a preview, but I&#8217;ve ignored that for now).</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="433" data-attachment-id="2846" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-14-37-34/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.37.34.png" data-orig-size="1932,818" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-14.37.34" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.37.34.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.37.34.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.37.34.png?w=1024" alt="" class="wp-image-2846" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.37.34.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.37.34.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.37.34.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.37.34.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-14.37.34.png 1932w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>I&#8217;ve made a few changes to this as you&#8217;ll see.  Some were required to used App Groups, then I discovered a problem with paths on tvOS and then I&#8217;ve done some refactoring just to make it clearer (imo) which bits are which.</p>



<p>First here&#8217;s my version of what&#8217;s above.  Like the original we override the URL if we&#8217;re in memory.  Unlike the original we also have to override the URL even in the default case because we are using App Groups.  </p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="390" data-attachment-id="2848" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-11-52-40/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.40.png" data-orig-size="1936,738" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-11.52.40" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.40.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.40.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.40.png?w=1024" alt="" class="wp-image-2848" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.40.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.40.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.40.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.40.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.40.png 1936w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>The default, not-ideal error handling is just extracted to a separate method</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="311" data-attachment-id="2850" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-11-52-10/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.10.png" data-orig-size="2078,632" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-11.52.10" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.10.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.10.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.10.png?w=1024" alt="" class="wp-image-2850" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.10.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.10.png?w=2045 2045w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.10.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.10.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.52.10.png?w=768 768w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>And I added an extension on <code>URL</code> to build the store URL for the group.  The key is <code>FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup)</code>.  You can also see here the change I had to make when I discovered that tvOS didn&#8217;t work.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="412" data-attachment-id="2852" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-11-51-56/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.51.56.png" data-orig-size="1940,782" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-11.51.56" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.51.56.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.51.56.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.51.56.png?w=1024" alt="" class="wp-image-2852" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.51.56.png?w=1022 1022w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.51.56.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.51.56.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.51.56.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-11.51.56.png 1940w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>I also pulled out some of the static convenience code into an extension.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="317" data-attachment-id="2854" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-15-34-05/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.05.png" data-orig-size="1108,344" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-15.34.05" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.05.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.05.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.05.png?w=1024" alt="" class="wp-image-2854" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.05.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.05.png?w=1021 1021w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.05.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.05.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.05.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.05.png 1108w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>All this code is in a file called <code>PersistenceController.swift</code> in the Model group.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="676" height="242" data-attachment-id="2855" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-15-34-58/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.58.png" data-orig-size="676,242" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-15.34.58" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.58.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.58.png?w=676" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.58.png?w=676" alt="" class="wp-image-2855" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.58.png 676w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.58.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.34.58.png?w=300 300w" sizes="(max-width: 676px) 100vw, 676px" /></figure>



<p>The last thing we need to do here is add some code to initialise the Persistence controller in the App and Widgets and check it all build and runs.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="193" data-attachment-id="2857" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-15-36-59/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.36.59.png" data-orig-size="1026,194" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-15.36.59" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.36.59.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.36.59.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.36.59.png?w=1024" alt="" class="wp-image-2857" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.36.59.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.36.59.png?w=1021 1021w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.36.59.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.36.59.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.36.59.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.36.59.png 1026w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<hr class="wp-block-separator has-alpha-channel-opacity" />



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="183" data-attachment-id="2858" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-15-37-06/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.06.png" data-orig-size="1094,196" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-15.37.06" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.06.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.06.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.06.png?w=1024" alt="" class="wp-image-2858" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.06.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.06.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.06.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.06.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.06.png 1094w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<hr class="wp-block-separator has-alpha-channel-opacity" />



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="179" data-attachment-id="2859" data-permalink="https://alancfrancis.com/2023/07/07/part-7-cloudkit/screenshot-2023-07-07-at-15-37-12/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.12.png" data-orig-size="1040,182" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-07-at-15.37.12" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.12.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.12.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.12.png?w=1024" alt="" class="wp-image-2859" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.12.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.12.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.12.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.12.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-07-at-15.37.12.png 1040w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>All this is in another commit &#8220;Part 7: Simple PersistenceController&#8221;</p>



<p></p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://alancfrancis.com/2023/07/07/part-7-cloudkit/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://alancfrancis.com/2023/07/07/part-7-cloudkit/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>alancfrancis</name>
							<uri>https://alancfrancis.wordpress.com</uri>
						</author>

		<title type="html"><![CDATA[Part 6: Multiple Widgets]]></title>
		<link rel="alternate" type="text/html" href="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/" />

		<id>http://alancfrancis.com/?p=2729</id>
		<updated>2023-07-06T18:21:07Z</updated>
		<published>2023-07-06T18:14:42Z</published>
		<category scheme="https://alancfrancis.com" term="Uncategorized" />
		<summary type="html"><![CDATA[At the end of the last part I was aware that although the widget worked in all the contexts I care about, it looked a little weird in the .accessoryCircular family, which appears in certain watch complications and iPhone Lock Screen widgets. In this part I&#8217;ll add a second type of widget and talk a [&#8230;]]]></summary>

					<content type="html" xml:base="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/"><![CDATA[
<p>At the end of the last part I was aware that although the widget worked in all the contexts I care about, it looked a little weird in the .<code>accessoryCircular</code> family, which  appears in certain watch complications and iPhone Lock Screen widgets.</p>



<p>In this part I&#8217;ll add a second type of widget and talk a little about different widget families and contexts.  As usual my focus here is on trying to share as much code as I can and have a single project that supports all the different options in obvious ways.</p>



<p>This section is a lot of moving code around, really, but again it sets us up going forward for more flexible widgets.</p>



<hr class="wp-block-separator has-alpha-channel-opacity" />



<h2 class="wp-block-heading">Divide and Conquer</h2>



<p>First I&#8217;m going to pull apart the <code>JustOneThingWidget</code> file.  I&#8217;ve made a new <code>ThingView.swift</code> file and pulled the <code>ThingView</code> and the <code>ThingEntryView</code> out to it, to leave just the Widget-specific stuff in <code>JustOneThingWidget.swift</code>.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="636" data-attachment-id="2733" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-15-00-07/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.00.07.png" data-orig-size="1690,1050" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-15.00.07" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.00.07.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.00.07.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.00.07.png?w=1024" alt="" class="wp-image-2733" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.00.07.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.00.07.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.00.07.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.00.07.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.00.07.png 1690w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Lets also make a <code>WidgetBundle.swift</code> file and pull the <code>WidgetBundle</code> out to it.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="396" data-attachment-id="2735" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-16-58-53/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-16.58.53.png" data-orig-size="1544,598" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-16.58.53" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-16.58.53.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-16.58.53.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-16.58.53.png?w=1024" alt="" class="wp-image-2735" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-16.58.53.png?w=1022 1022w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-16.58.53.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-16.58.53.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-16.58.53.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-16.58.53.png 1544w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>That just leaves our <code>JustOneThingWidget</code> struct.</p>



<p>Next we&#8217;re going to rename the file and the struct to <code>SystemThingWidget</code> (and you&#8217;ll see I added some more descriptive text to the configuration display name and description.  Also, crucially, I&#8217;ve added a <code>.supportedFamilies</code> modifier to specify only the <code>.systemXXX</code> families.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="456" data-attachment-id="2737" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-17-01-23/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.01.23.png" data-orig-size="1242,554" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-17.01.23" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.01.23.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.01.23.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.01.23.png?w=1024" alt="" class="wp-image-2737" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.01.23.png?w=1022 1022w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.01.23.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.01.23.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.01.23.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.01.23.png 1242w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>There&#8217;s also a <code>.systemExtraLarge</code> family but it&#8217;s only on iPad, which I don&#8217;t much care about.  Having it there would mean more conditional checks so I just ignored it.   Those three are available on iOS and macOS so all good.</p>



<p>The last thing you can see above is that I ended up just deleting <code>ThingEntryView</code> and going straight to <code>ThingView</code>.  The EntryView wasn&#8217;t really doing anything useful and I didn&#8217;t need anything from the Entry but the <code>Thing</code>.</p>



<p>Next we&#8217;re going to add a new file and call it <code>AccessoryWidget</code> and copy and paste the whole <code>SystemWidget</code> into it.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="354" data-attachment-id="2760" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-17-09-14-1/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.09.14-1.png" data-orig-size="1438,498" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-17.09.14-1" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.09.14-1.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.09.14-1.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.09.14-1.png?w=1024" alt="" class="wp-image-2760" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.09.14-1.png?w=1022 1022w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.09.14-1.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.09.14-1.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.09.14-1.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.09.14-1.png 1438w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>I&#8217;ve renamed the struct and changed the <code>configurationDisplayName</code> and <code>description</code> just so we can tell it apart from the <code>SystemWidget</code>.  I&#8217;ve also set the <code>supportedFamilies</code> to the .<code>accessoryXXX</code> options.</p>



<p>Now we have two widget types we need to make sure they are both in the <code>WidgetBundle</code>.  This is where things get interesting.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="421" data-attachment-id="2762" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-15-09-43-1/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.09.43-1.png" data-orig-size="1400,576" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-15.09.43-1" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.09.43-1.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.09.43-1.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.09.43-1.png?w=1024" alt="" class="wp-image-2762" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.09.43-1.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.09.43-1.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.09.43-1.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.09.43-1.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.09.43-1.png 1400w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<hr class="wp-block-separator has-alpha-channel-opacity" />



<h2 class="wp-block-heading">Computer Says No</h2>



<figure data-carousel-extra='{"blog_id":122971807,"permalink":"https:\/\/alancfrancis.com\/2023\/07\/06\/part-6-multiple-widgets\/"}'  class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" width="546" height="366" data-attachment-id="2765" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-15-06-22-1/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.06.22-1.png" data-orig-size="546,366" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-15.06.22-1" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.06.22-1.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.06.22-1.png?w=546" tabindex="0" role="button" data-id="2765" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.06.22-1.png?w=546" alt="" class="wp-image-2765" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.06.22-1.png 546w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.06.22-1.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.06.22-1.png?w=300 300w" sizes="(max-width: 546px) 100vw, 546px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="588" height="454" data-attachment-id="2766" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-15-06-32-1/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.06.32-1.png" data-orig-size="588,454" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-15.06.32-1" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.06.32-1.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.06.32-1.png?w=588" tabindex="0" role="button" data-id="2766" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.06.32-1.png?w=588" alt="" class="wp-image-2766" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.06.32-1.png 588w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.06.32-1.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.06.32-1.png?w=300 300w" sizes="(max-width: 588px) 100vw, 588px" /></figure>
</figure>



<p>It turns out that (at time of writing) the system families are not supported on the Watch and the accessory families are not supported on the Mac, so we&#8217;ll need to help Xcode build and package the right things for the right platforms.</p>



<p>First we&#8217;ll see target memberships for the <code>SystemWidget</code> and <code>AccessoryWidget</code> files to only build them for the right platforms.  <code>SystemWidget</code> is <strong>NOT</strong> for the watch and <code>AccessoryWidget</code> is <strong>NOT</strong> for the Mac.</p>



<figure data-carousel-extra='{"blog_id":122971807,"permalink":"https:\/\/alancfrancis.com\/2023\/07\/06\/part-6-multiple-widgets\/"}'  class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-3 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" width="502" height="808" data-attachment-id="2768" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-15-12-27-1/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.27-1.png" data-orig-size="502,808" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-15.12.27-1" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.27-1.png?w=186" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.27-1.png?w=502" tabindex="0" role="button" data-id="2768" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.27-1.png?w=502" alt="" class="wp-image-2768" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.27-1.png 502w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.27-1.png?w=93 93w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.27-1.png?w=186 186w" sizes="(max-width: 502px) 100vw, 502px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="532" height="882" data-attachment-id="2769" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-15-12-33-1/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.33-1.png" data-orig-size="532,882" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-15.12.33-1" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.33-1.png?w=181" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.33-1.png?w=532" tabindex="0" role="button" data-id="2769" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.33-1.png?w=532" alt="" class="wp-image-2769" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.33-1.png 532w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.33-1.png?w=90 90w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.33-1.png?w=181 181w" sizes="(max-width: 532px) 100vw, 532px" /></figure>
</figure>



<p>Next, since the two widgets may or may not be available, we&#8217;ll need to help <code>WidgetBundle</code> out.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="455" data-attachment-id="2772" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-15-12-14-1/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.14-1.png" data-orig-size="1496,666" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-15.12.14-1" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.14-1.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.14-1.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.14-1.png?w=1024" alt="" class="wp-image-2772" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.14-1.png?w=1022 1022w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.14-1.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.14-1.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.14-1.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.12.14-1.png 1496w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Once again, <code>SystemWidget</code> is NOT for the watch, <code>AccessoryWidget</code> is NOT for the Mac.</p>



<p>At this point everything. should build again and we have two distinct widgets for two different situations, though they both just show our <code>ThingView</code> text.</p>



<p>Lets try them out in the various simulators.</p>



<h2 class="wp-block-heading">What do we have?</h2>



<figure data-carousel-extra='{"blog_id":122971807,"permalink":"https:\/\/alancfrancis.com\/2023\/07\/06\/part-6-multiple-widgets\/"}'  class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-4 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" width="760" height="994" data-attachment-id="2776" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-15-21-05-1/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.21.05-1.png" data-orig-size="760,994" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-15.21.05-1" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.21.05-1.png?w=229" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.21.05-1.png?w=760" tabindex="0" role="button" data-id="2776" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.21.05-1.png?w=760" alt="" class="wp-image-2776" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.21.05-1.png 760w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.21.05-1.png?w=115 115w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.21.05-1.png?w=229 229w" sizes="(max-width: 760px) 100vw, 760px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="645" height="1023" data-attachment-id="2777" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-15-20-20-1/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.20.20-1.png" data-orig-size="774,1228" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-15.20.20-1" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.20.20-1.png?w=189" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.20.20-1.png?w=645" tabindex="0" role="button" data-id="2777" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.20.20-1.png?w=645" alt="" class="wp-image-2777" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.20.20-1.png?w=645 645w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.20.20-1.png?w=95 95w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.20.20-1.png?w=189 189w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.20.20-1.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.20.20-1.png 774w" sizes="(max-width: 645px) 100vw, 645px" /></figure>
</figure>



<p>On the iPhone, we can see the Home Screen is loading the <code>SystemWidget</code> (the <code>displayName</code> is <em>Just One Thing</em>).  If we add a widget to the Lock Screen we can see its using the <code>AccessoryWidget</code> (<code>displayName</code> is <em>One Tiny Thing</em>).</p>



<p>The watch is interesting too.  It&#8217;s not immediately obvious we&#8217;re getting the <code>AccessoryWidget</code> because the watch doesn&#8217;t show the <code>displayName</code> or the <code>description</code>.  Instead its showing the text from the <code>recommendations</code> method on the Provider (&#8220;<em>My Intent Widget</em>&#8220;).</p>



<figure data-carousel-extra='{"blog_id":122971807,"permalink":"https:\/\/alancfrancis.com\/2023\/07\/06\/part-6-multiple-widgets\/"}'  class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-5 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" width="484" height="506" data-attachment-id="2779" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-15-23-32-1/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.23.32-1.png" data-orig-size="484,506" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-15.23.32-1" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.23.32-1.png?w=287" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.23.32-1.png?w=484" tabindex="0" role="button" data-id="2779" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.23.32-1.png?w=484" alt="" class="wp-image-2779" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.23.32-1.png 484w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.23.32-1.png?w=143 143w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.23.32-1.png?w=287 287w" sizes="(max-width: 484px) 100vw, 484px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="460" height="412" data-attachment-id="2781" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-15-24-46-1/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.24.46-1.png" data-orig-size="460,412" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-15.24.46-1" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.24.46-1.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.24.46-1.png?w=460" tabindex="0" role="button" data-id="2781" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.24.46-1.png?w=460" alt="" class="wp-image-2781" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.24.46-1.png 460w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.24.46-1.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.24.46-1.png?w=300 300w" sizes="(max-width: 460px) 100vw, 460px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="546" height="522" data-attachment-id="2780" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-15-23-52-1/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.23.52-1.png" data-orig-size="546,522" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-15.23.52-1" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.23.52-1.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.23.52-1.png?w=546" tabindex="0" role="button" data-id="2780" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.23.52-1.png?w=546" alt="" class="wp-image-2780" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.23.52-1.png 546w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.23.52-1.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.23.52-1.png?w=300 300w" sizes="(max-width: 546px) 100vw, 546px" /></figure>
</figure>



<p>Here we can see the <code>accessoryRectangular</code>, <code>accessoryInline</code> and <code>accessoryCircular</code>.  Rectangular looks just like the <code>SystemWidget</code>, and we could have tried to make the <code>SystemWidget</code> support that family, but we&#8217;d have still had to deal with a more complicated situation around the availability of families on platforms.  This way, there are two distinct widgets for different situations, but we know they are just simple wrappers round the <code>ThingView</code>, so even though we don&#8217;t share the Widget struct itself, there&#8217;s a single place we can make changes and have them be reflected in both platforms.</p>



<p>I notice that they <code>accessoryInline</code> view isn&#8217;t using my fonts or colours, just simple text.  Not a problem for now, but something to be aware of if we change <code>ThingView</code> to be more complicated.</p>



<p>Lastly the <code>accessoryCircular</code> is still just a tiny version of the <code>ThingView</code> and we want to change that.</p>



<p>I&#8217;d like to quickly explain the <code>recommendations</code> situation first though.</p>



<p>If we got back to the Provider code and add second recommendation&#8230;</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="292" data-attachment-id="2785" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-15-26-19-1/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.26.19-1.png" data-orig-size="1290,368" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-15.26.19-1" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.26.19-1.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.26.19-1.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.26.19-1.png?w=1024" alt="" class="wp-image-2785" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.26.19-1.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.26.19-1.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.26.19-1.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.26.19-1.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.26.19-1.png 1290w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Then go back to the watch simulator to add a widget&#8230;</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="490" height="546" data-attachment-id="2787" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-15-27-06-1/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.27.06-1.png" data-orig-size="490,546" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-15.27.06-1" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.27.06-1.png?w=269" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.27.06-1.png?w=490" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.27.06-1.png?w=490" alt="" class="wp-image-2787" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.27.06-1.png 490w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.27.06-1.png?w=135 135w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.27.06-1.png?w=269 269w" sizes="(max-width: 490px) 100vw, 490px" /></figure>



<p>You can see how the configurations work.  We have one single <code>AccessoryWidget</code> that (in this case) supports the <code>accessoryInline</code> family, but we offer the user two different configurations.</p>



<p>If you remember back a few posts ago, I explained that the <code>IntentConfiguration</code> stuff is to provide a way for a widget to be configured on the iPhone or the Mac.  Perhaps we offer a way to change the number of <code>Things</code>, or the colour.  </p>



<p>That complex UI is not possible on the watch and so we offer some suggested configurations like &#8220;<em>One Thing, Random Colour</em>&#8220;, &#8220;<em>Two Things, Accent Colour</em>&#8221; and the watch user can select which prebuilt configuration they want to add.</p>



<p>We&#8217;ll ignore this for now and leave the existing single recommendation as we have no configuration system yet. Let&#8217;s get back to making a slightly nicer circular complication.</p>



<p>Where the <code>SystemWidget</code> just uses a <code>ThingView</code>, the <code>AccessoryWidget</code> now has its own wrapper view, which checks the environment for the <code>widgetFamily</code> and returns something small and simple in the circular case.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="627" data-attachment-id="2792" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-17-42-13/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.13.png" data-orig-size="1522,932" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-17.42.13" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.13.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.13.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.13.png?w=1024" alt="" class="wp-image-2792" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.13.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.13.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.13.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.13.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.13.png 1522w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>When I hacked this together the first time I made the circular widget show a total number of <code>Things</code>, but since I haven&#8217;t built a real <code>DataStore</code> for this yet, I just went with the SFSymbol I&#8217;ve been using as an icon.  Its not winning any awards, and its just a basic launcher rather than glanceable information, but it looks slightly better than the tiny text.</p>



<figure data-carousel-extra='{"blog_id":122971807,"permalink":"https:\/\/alancfrancis.com\/2023\/07\/06\/part-6-multiple-widgets\/"}'  class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-6 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" width="528" height="556" data-attachment-id="2793" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-17-42-59/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.59.png" data-orig-size="528,556" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-17.42.59" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.59.png?w=285" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.59.png?w=528" tabindex="0" role="button" data-id="2793" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.59.png?w=528" alt="" class="wp-image-2793" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.59.png 528w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.59.png?w=142 142w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-17.42.59.png?w=285 285w" sizes="(max-width: 528px) 100vw, 528px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="554" height="546" data-attachment-id="2794" data-permalink="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/screenshot-2023-07-06-at-15-36-10-2/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.36.10-2.png" data-orig-size="554,546" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-15.36.10-2" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.36.10-2.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.36.10-2.png?w=554" tabindex="0" role="button" data-id="2794" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.36.10-2.png?w=554" alt="" class="wp-image-2794" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.36.10-2.png 554w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.36.10-2.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-15.36.10-2.png?w=300 300w" sizes="(max-width: 554px) 100vw, 554px" /></figure>
</figure>



<p>That&#8217;s a wrap for part 6.  The commit is &#8220;Part 6: Separate Widgets&#8221; </p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://alancfrancis.com/2023/07/06/part-6-multiple-widgets/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>alancfrancis</name>
							<uri>https://alancfrancis.wordpress.com</uri>
						</author>

		<title type="html"><![CDATA[Part 5: Even More Things]]></title>
		<link rel="alternate" type="text/html" href="https://alancfrancis.com/2023/07/06/part-5-even-more-things/" />

		<id>http://alancfrancis.com/?p=2702</id>
		<updated>2023-07-06T18:19:17Z</updated>
		<published>2023-07-06T12:59:25Z</published>
		<category scheme="https://alancfrancis.com" term="Uncategorized" />
		<summary type="html"><![CDATA[The &#8220;part&#8221; breaks are somewhat arbitrary now, but I figure I&#8217;ll just keep recording what I&#8217;m doing with the codebase and how I&#8217;m doing it. Its worth reiterating that I am very much Not An Expert and may well be Holding it Wrong, but I&#8217;m feeling my way there and I guess by &#8220;showing my [&#8230;]]]></summary>

					<content type="html" xml:base="https://alancfrancis.com/2023/07/06/part-5-even-more-things/"><![CDATA[
<p>The &#8220;part&#8221; breaks are somewhat arbitrary now, but I figure I&#8217;ll just keep recording what I&#8217;m doing with the codebase and how I&#8217;m doing it.   Its worth reiterating that I am very much <em>Not An Expert</em> and may well be <em>Holding it Wrong</em>, but I&#8217;m feeling my way there and I guess by &#8220;showing my working&#8221; someone will be able to help me understand which bit of thinking was wrong if it all goes pear shaped.</p>



<p>I feel I&#8217;m still very much putting off data persistence and CloudKit, because its a bit involved and not massively exciting, and I&#8217;m also putting off a functional UI because I have zero SwiftUI skills and I expect it to look awful <img src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>Anyhoo, I sat back down this morning and the first thing I did was extract a <code>ThingView</code> from my <code>ThingEntryView</code>.  Removed the slightly irritating Demeter violation and also means I have a simple <code>ThingView</code> to tweak and use in a bunch of places&#8230; maybe even migrate it from the Widget to shared with the App.</p>



<p>It probably looks a little pointless for the sake of a single dot-separator, but it feels like it&#8217;s worth doing now.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="712" height="550" data-attachment-id="2707" data-permalink="https://alancfrancis.com/2023/07/06/part-5-even-more-things/screenshot-2023-07-06-at-08-29-11/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-08.29.11.png" data-orig-size="712,550" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-08.29.11" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-08.29.11.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-08.29.11.png?w=712" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-08.29.11.png?w=712" alt="" class="wp-image-2707" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-08.29.11.png 712w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-08.29.11.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-08.29.11.png?w=300 300w" sizes="(max-width: 712px) 100vw, 712px" /></figure>



<p>Maybe the <code>ThingEntryView</code> won&#8217;t carry its weight for long.  The <code>ThingEntry</code> is just a timeline implementation detail and maybe nobody else (especially the View hierarchy) should care about it.</p>



<h2 class="wp-block-heading">A Bigger Thing</h2>



<p>I&#8217;d like the text in the Widget to be as large as it can be, and shrink if necessary.  And I&#8217;d like to have some random colours  so it catches my eye, so lets have a play with the ThingView.</p>



<p>For the colours I just hacked something together for now, though some better defined palettes might be better.  Essentially if we&#8217;re in light mode the system background for widgets is white so give me a dark-ish colour if we&#8217;re in dark mode, reverse that.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="416" data-attachment-id="2715" data-permalink="https://alancfrancis.com/2023/07/06/part-5-even-more-things/screenshot-2023-07-06-at-13-27-09/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.27.09.png" data-orig-size="1336,544" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-13.27.09" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.27.09.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.27.09.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.27.09.png?w=1024" alt="" class="wp-image-2715" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.27.09.png?w=1022 1022w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.27.09.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.27.09.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.27.09.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.27.09.png 1336w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Any <code>View</code> using the colour can access the environment variable <code>colorScheme</code> and then ask for a suitable foreground.</p>



<p>The font sizing was a little more involved.  I honestly cant remember all the things I tried before and I cant remember how I ended up with this snippet, but the first time I hacked this app together this is what I ended up with:</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="933" data-attachment-id="2717" data-permalink="https://alancfrancis.com/2023/07/06/part-5-even-more-things/screenshot-2023-07-06-at-13-29-00/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.29.00.png" data-orig-size="1314,1198" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-13.29.00" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.29.00.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.29.00.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.29.00.png?w=1024" alt="" class="wp-image-2717" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.29.00.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.29.00.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.29.00.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.29.00.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.29.00.png 1314w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>In essence it lets me attach a view modified which calculates the largest font size for the area, given some line limit and minimum scale factor.  Suggestions very welcome for a better way to do it.</p>



<p>Both of these are in a file in <code>WidgetShared</code> called <code>InterfaceExtensions.swift</code></p>



<p>So, I changed my <code>ThingDatastore</code> to have some random, different-sized Things and here&#8217;s the result in dark and light modes in a variety of widget sizes.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="411" data-attachment-id="2720" data-permalink="https://alancfrancis.com/2023/07/06/part-5-even-more-things/screenshot-2023-07-06-at-13-42-06/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.06.png" data-orig-size="2190,880" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-13.42.06" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.06.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.06.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.06.png?w=1024" alt="" class="wp-image-2720" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.06.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.06.png?w=2046 2046w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.06.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.06.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.06.png?w=768 768w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="236" data-attachment-id="2721" data-permalink="https://alancfrancis.com/2023/07/06/part-5-even-more-things/screenshot-2023-07-06-at-13-42-49/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.49.png" data-orig-size="2172,502" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-13.42.49" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.49.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.49.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.49.png?w=1024" alt="" class="wp-image-2721" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.49.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.49.png?w=1021 1021w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.49.png?w=2042 2042w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.49.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.49.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.42.49.png?w=768 768w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="721" data-attachment-id="2722" data-permalink="https://alancfrancis.com/2023/07/06/part-5-even-more-things/screenshot-2023-07-06-at-13-41-58/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.41.58.png" data-orig-size="2160,1522" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-13.41.58" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.41.58.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.41.58.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.41.58.png?w=1024" alt="" class="wp-image-2722" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.41.58.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.41.58.png?w=2046 2046w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.41.58.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.41.58.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.41.58.png?w=768 768w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>So far so good.   Random colours so it looks different enough that I don&#8217;t start to ignore it, and sized to make the best use of space.</p>



<p>Like the colours it would probably be better to have a standard &#8220;palette&#8221; of sizes to at least provide some consistency, but I&#8217;m not anticipating seeing multiple widgets together at once so I don&#8217;t mind one at 16 points and another at 17 points.  There&#8217;ll be one widget on my phone Home Screen and one on my Mac sidebar.  I have an idea to use the <code>Configuration</code> to maybe show two <code>Things</code> side by side in a medium widget, or stacked on top on a large widget, but that can wait for now.</p>



<p>One problem I noticed is only obvious if you play around with previews.  I changed the preview Thing to be a longer text and I changed the preview context to <code>accessoryCircular</code>.  You can see how tiny the text is there to the left of the clock.  Perhaps we&#8217;ll want to do something different for an accessory widget (phone Lock Screen will be the same), but <code>accessoryInline</code> and <code>accessoryRectangular</code> both look fine on the watch</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="811" data-attachment-id="2725" data-permalink="https://alancfrancis.com/2023/07/06/part-5-even-more-things/screenshot-2023-07-06-at-13-49-15/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.49.15.png" data-orig-size="1242,984" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-06-at-13.49.15" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.49.15.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.49.15.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.49.15.png?w=1024" alt="" class="wp-image-2725" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.49.15.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.49.15.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.49.15.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.49.15.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-06-at-13.49.15.png 1242w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>So that seems like a good place to commit (&#8220;Part 5: Fonts and Colours&#8221;) and start thinking about different kinds of widgets for different situations.  </p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://alancfrancis.com/2023/07/06/part-5-even-more-things/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://alancfrancis.com/2023/07/06/part-5-even-more-things/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>alancfrancis</name>
							<uri>https://alancfrancis.wordpress.com</uri>
						</author>

		<title type="html"><![CDATA[Part 4: A Thing]]></title>
		<link rel="alternate" type="text/html" href="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/" />

		<id>http://alancfrancis.com/?p=2652</id>
		<updated>2023-07-06T18:22:11Z</updated>
		<published>2023-07-04T14:02:17Z</published>
		<category scheme="https://alancfrancis.com" term="Uncategorized" />
		<summary type="html"><![CDATA[The three parts of the &#8220;Once and Only Once&#8221; reached a conclusion. You now have Apple&#8217;s templates and targets all added and refactored so you can make changes in the fewest places. This article sort of follows along from there but I&#8217;d hesitate to really call it part 4. More like Book 2: Part 1 [&#8230;]]]></summary>

					<content type="html" xml:base="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/"><![CDATA[
<p>The three parts of the &#8220;Once and Only Once&#8221; reached a conclusion.  You now have Apple&#8217;s templates and targets all added and refactored so you can make changes in the fewest places.  This article sort of follows along from there but I&#8217;d hesitate to really call it part 4.  More like Book 2: Part 1 <img src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>Now we&#8217;ve got our project structured how we (or rather I) like we can start adding something useful to it where required.  I&#8217;ll be taking fewer screenshots and taking bigger steps now as is this is really just me trying to document what I actually wanted to build, rather than a tutorial for you.  I&#8217;m far from experienced here, will be learning as I go and no doubt making a bunch of mistakes.  If you want a more in depth tutorial on Widgets or Intents, you&#8217;ll find better options elsewhere <img src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>Anyhoo, if you recall, what I wanted to build was something to let me add some random, 2-3 word reminders and display them, one at a time, randomly on widgets across my phone, watch and Mac so I don t get overwhelmed with ALL THE THINGS and get gentle nudges about JUST ONE THING at a time. </p>



<p>Since I was making a Multiplatform app, it will work on an iPad (which I don&#8217;t really use) and the AppleTV (which doesn&#8217;t really have widgets).  I&#8217;ll also remind you that I have minimal interest in the &#8220;data entry&#8221; part of the app. It will be as rough and simple as possible.  The two keys (for me) were: (1) I enjoyed messing with the code structure that got us this far and (2) I just want the strings appearing randomly on the widgets.</p>



<hr class="wp-block-separator has-alpha-channel-opacity" />



<h2 class="wp-block-heading">a Thing</h2>



<p>The beating heart of the Widget system is the timeline provider.  Its job is to supply one or more configured entries with a particular timestamp for the OS to display as close to this times as it can.  </p>



<p>The <code>ConfigurationIntent</code> part is essentially a supplied UI to configure each widget in a clear, constrained way.  In my case I&#8217;ll <strong>eventually</strong> use it to allow a user to configure the large widget to show one very big reminder, or two smaller reminders, but for now we&#8217;ll ignore it and work just on the timeline.</p>



<p>Right now the template has supplied us with a <code>ThingEntry:TimelineEntry</code> and that just contains the required properties of a <code>Date</code> (for the timeline) and a configuration (as discussed above).  What we don&#8217;t yet have is a model object so the first thing I want to do is make a <code>Thing</code> struct to represent the Things.</p>



<p>All it needs right now is a String to hold the text, but I&#8217;ll also add a created date as I suspect I might want to twiddle with the randomness to maybe show older ones more often.</p>



<p>For now I&#8217;m not worrying about persistence, or sharing between the apps and the widgets.  I just want a struct for the timeline to provide and the widget to display, so I&#8217;ll put it in the WidgetShared folder.  I also added a static placeholder I can use where required.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="307" data-attachment-id="2662" data-permalink="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/screenshot-2023-07-04-at-12-37-42/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.37.42.png" data-orig-size="1834,550" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-04-at-12.37.42" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.37.42.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.37.42.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.37.42.png?w=1024" alt="" class="wp-image-2662" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.37.42.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.37.42.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.37.42.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.37.42.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.37.42.png 1834w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Next I&#8217;ll go make some changes around the Timeline and the Entry to use this new struct.  I&#8217;ll rename <code>Provider</code> to <code>ThingProvider</code> and <code>SimpleEntry</code> to <code>ThingEntry</code>.  This is mostly in the <code>JustOneThingProvider</code> file but there are a couple of  changed in the <code>JustOneThingWidget</code> file.  While I&#8217;m there, and just because its annoying me, I&#8217;ll rename <code>JustOneThingWidgetEntryView</code> (the templates default name) to <code>ThingEntryView</code>, because that&#8217;s what it displays.</p>



<p>Next we&#8217;ll change the <code>ThingEntry</code> to take a <code>Thing</code>, alongside its <code>date</code> and <code>configuration</code>.  Wherever the compiler needs me to supply a <code>Thing</code>, I&#8217;ll just use a <code>Thing.placeholder</code> instance for now.</p>



<figure data-carousel-extra='{"blog_id":122971807,"permalink":"https:\/\/alancfrancis.com\/2023\/07\/04\/more-widgets-sort-of-part-4\/"}'  class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-7 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" width="872" height="378" data-attachment-id="2664" data-permalink="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/screenshot-2023-07-04-at-12-46-04/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.04.png" data-orig-size="872,378" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-04-at-12.46.04" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.04.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.04.png?w=872" tabindex="0" role="button" data-id="2664" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.04.png?w=872" alt="" class="wp-image-2664" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.04.png 872w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.04.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.04.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.04.png?w=768 768w" sizes="(max-width: 872px) 100vw, 872px" /></figure>



<figure class="wp-block-image size-full is-style-default"><img data-attachment-id="2665" data-permalink="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/screenshot-2023-07-04-at-12-46-23/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.23.png" data-orig-size="1260,310" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-04-at-12.46.23" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.23.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.23.png?w=1000" tabindex="0" role="button" data-id="2665" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.23.png" alt="" class="wp-image-2665" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="676" height="304" data-attachment-id="2663" data-permalink="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/screenshot-2023-07-04-at-12-46-37/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.37.png" data-orig-size="676,304" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-04-at-12.46.37" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.37.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.37.png?w=676" tabindex="0" role="button" data-id="2663" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.37.png?w=676" alt="" class="wp-image-2663" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.37.png 676w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.37.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-12.46.37.png?w=300 300w" sizes="(max-width: 676px) 100vw, 676px" /></figure>
</figure>



<p>This seems a decent place to make a commit, its in the repo as &#8220;<code>Part 4: Add a Thing struct</code>&#8220;</p>



<h2 class="wp-block-heading">ALL THE THINGS</h2>



<p>So next up I&#8217;m going to work on the timeline to make a few actual <code>Things</code>.  I&#8217;ll split up a simple data store array of things and the timeline building which add them at hourly intervals.  </p>



<p>Eventually the data store will need to be persistent and it will need to be shared between the apps and widgets, but again for now I&#8217;ll just embed them in the Provider so I can keep working on the widgets.</p>



<p>First thing I did was make a new initialiser for the ThingEntry that provided defaults for the date and the configuration to make things a bit less verbose.</p>



<p>That lets me reduce some of the code in the placeholder and snapshot methods, and in the preview in the <code>ThingWidget</code> file. I&#8217;m not yet sure what they do exactly, but less code is better and I will figure it out later.  The main timeline method still needs all three arguments but at least the <code>Thing</code> is first.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="276" data-attachment-id="2670" data-permalink="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/screenshot-2023-07-04-at-13-26-33/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.26.33.png" data-orig-size="1768,478" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-04-at-13.26.33" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.26.33.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.26.33.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.26.33.png?w=1024" alt="" class="wp-image-2670" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.26.33.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.26.33.png?w=1021 1021w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.26.33.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.26.33.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.26.33.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.26.33.png 1768w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>While I&#8217;m doing this I realise again that I am annoyed by <code>ConfigurationIntent</code>.  It&#8217;s passed into something else called an <code>IntentConfiguration</code> in the widget file and the names are irritating close together, and opaque.  This is a classname I can change, but it&#8217;s magically generated from the Intent Definition file.   I&#8217;ll fix it later, cause I&#8217;m doing something else, but it bugs me and I should find how how to change it.</p>



<p>Now back to the Data Store.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="572" data-attachment-id="2674" data-permalink="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/screenshot-2023-07-04-at-13-37-35/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.37.35.png" data-orig-size="1166,652" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-04-at-13.37.35" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.37.35.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.37.35.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.37.35.png?w=1024" alt="" class="wp-image-2674" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.37.35.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.37.35.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.37.35.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.37.35.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.37.35.png 1166w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>A simple <code>ThingDataStore</code> that can give me back an array of Things, hardcoded for now.  I&#8217;ve also added a way get them in random order.  I&#8217;ll add a <code>ThingDataStore</code> instance to the provider to separate the &#8220;getting of things&#8221; from the &#8220;building of timeline entries&#8221;.</p>



<p>In the Provider we&#8217;ll change the timeline code to get all the shuffled things and return them as timeline entries 15 minutes apart.</p>



<p>While I was there I pulled the <code>recommendations</code> method out to an extension as it didn&#8217;t seem to belong with the rest of the &#8220;give me some entries&#8221; methods.  Its only required on the watch so potentially I could move it to the WatchWidget folder/target in a separate file.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="476" data-attachment-id="2676" data-permalink="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/screenshot-2023-07-04-at-13-48-38/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.48.38.png" data-orig-size="2086,970" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-04-at-13.48.38" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.48.38.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.48.38.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.48.38.png?w=1024" alt="" class="wp-image-2676" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.48.38.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.48.38.png?w=2048 2048w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.48.38.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.48.38.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.48.38.png?w=768 768w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>I didn&#8217;t like having to the keep the separate line to increment the running time when what I really needed was a method on date which incremented and returned self. So I added one.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="211" data-attachment-id="2680" data-permalink="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/screenshot-2023-07-04-at-13-58-05/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.05.png" data-orig-size="1218,252" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-04-at-13.58.05" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.05.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.05.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.05.png?w=1024" alt="" class="wp-image-2680" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.05.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.05.png?w=1020 1020w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.05.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.05.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.05.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.05.png 1218w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>That let me simplify my timeline method a little</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="164" data-attachment-id="2681" data-permalink="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/screenshot-2023-07-04-at-13-58-11/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.11.png" data-orig-size="2056,330" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-04-at-13.58.11" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.11.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.11.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.11.png?w=1024" alt="" class="wp-image-2681" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.11.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.11.png?w=2044 2044w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.11.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.11.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-13.58.11.png?w=768 768w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Next, I want to update the <code>ThingView</code> to display the text of our <code>Thing</code>.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="798" height="290" data-attachment-id="2684" data-permalink="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/screenshot-2023-07-04-at-14-22-49/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.22.49.png" data-orig-size="798,290" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-04-at-14.22.49" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.22.49.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.22.49.png?w=798" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.22.49.png?w=798" alt="" class="wp-image-2684" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.22.49.png 798w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.22.49.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.22.49.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.22.49.png?w=768 768w" sizes="(max-width: 798px) 100vw, 798px" /></figure>



<p>I was tempted at this point to make it a ThingView and just pass the thing rather than the whole entry, but we may want to access the configuration at some point and so for now lets leave it taking the whole entry and live with the Demeter violation.</p>



<p>OK!  If we switch to the MacWidgetExtension target and do a clean build, and then run, we&#8217;ll load the widget up pin the WidgetKit simulator app where we can see the placeholders, snapshots etc, and most importantly our timeline!</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="775" data-attachment-id="2682" data-permalink="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/screenshot-2023-07-04-at-14-28-24/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.28.24.png" data-orig-size="1774,1344" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-04-at-14.28.24" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.28.24.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.28.24.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.28.24.png?w=1024" alt="" class="wp-image-2682" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.28.24.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.28.24.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.28.24.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.28.24.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.28.24.png 1774w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>The timestamp at the bottom of each widget is the timeline date from the entry and the text is the Thing.text. We can see as the timeline proceeds the widgets are displayed in a random order. W e&#8217;re done, right ?   SHIP IT.</p>



<p>Well, we&#8217;ll at least commit.  I&#8217;ve called it &#8220;Part 4: Show the Things&#8221;.  </p>



<p>I&#8217;m tempted to stop here for now.  It&#8217;s quite tiring doing a little programming and then stopping to show what I&#8217;ve done.  Last thing I&#8217;ll do for now is make a little icon for the apps and choose an accent colour to make things a little more interesting.</p>



<p>I went with the <code>systemOrange</code> for a highlight colour and I used the excellent <a href="https://www.createchsol.com/blog/?id=bakery-simple-icon-creator">Bakery app</a> to knock up a quick Icon.  Bakery is pretty clear that it&#8217;s just an SFSymbol on a background and that means you cant use them for App Store submissions due to copyright issues, but it&#8217;s fine for development :-). It doesnt do the AppleTV as the icon there is layered and complicated, but it&#8217;ll be nicer on the Mac and Phone and Watch (my primary use cases).</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="648" height="708" data-attachment-id="2683" data-permalink="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/screenshot-2023-07-04-at-14-42-57/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.42.57.png" data-orig-size="648,708" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-04-at-14.42.57" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.42.57.png?w=275" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.42.57.png?w=648" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.42.57.png?w=648" alt="" class="wp-image-2683" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.42.57.png 648w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.42.57.png?w=137 137w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-04-at-14.42.57.png?w=275 275w" sizes="(max-width: 648px) 100vw, 648px" /></figure>



<p>A last commit &#8211; &#8220;Part 4: Colour and Icon&#8221; for the above, and then one more for some super simple AppleTV assets I knocked up in <a href="https://flyingmeat.com/acorn/">Acorn</a> ( &#8220;Part 4: Apple TV Assets&#8221; ) and we&#8217;re done for now!</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="436" data-attachment-id="2697" data-permalink="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/screenshot-2023-07-05-at-17-07-14/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-05-at-17.07.14.png" data-orig-size="1596,680" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-07-05-at-17.07.14" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-05-at-17.07.14.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-05-at-17.07.14.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-05-at-17.07.14.png?w=1024" alt="" class="wp-image-2697" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-05-at-17.07.14.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-05-at-17.07.14.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-05-at-17.07.14.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-05-at-17.07.14.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/07/screenshot-2023-07-05-at-17.07.14.png 1596w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="317" data-attachment-id="2699" data-permalink="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/appletv_topshelf_wide402x/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/07/appletv_topshelf_wide402x.png" data-orig-size="4640,1440" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="appletv_topshelf_wide402x" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/07/appletv_topshelf_wide402x.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/07/appletv_topshelf_wide402x.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/07/appletv_topshelf_wide402x.png?w=1024" alt="" class="wp-image-2699" srcset="https://alancfrancis.com/wp-content/uploads/2023/07/appletv_topshelf_wide402x.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/07/appletv_topshelf_wide402x.png?w=1021 1021w, https://alancfrancis.com/wp-content/uploads/2023/07/appletv_topshelf_wide402x.png?w=2043 2043w, https://alancfrancis.com/wp-content/uploads/2023/07/appletv_topshelf_wide402x.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/07/appletv_topshelf_wide402x.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/07/appletv_topshelf_wide402x.png?w=768 768w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p></p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://alancfrancis.com/2023/07/04/more-widgets-sort-of-part-4/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>alancfrancis</name>
							<uri>https://alancfrancis.wordpress.com</uri>
						</author>

		<title type="html"><![CDATA[Once and Only Once (Part 3 : Loose Ends)]]></title>
		<link rel="alternate" type="text/html" href="https://alancfrancis.com/2023/06/24/once-and-only-once-part-3-loose-ends/" />

		<id>http://alancfrancis.com/?p=2593</id>
		<updated>2023-06-24T18:37:25Z</updated>
		<published>2023-06-24T18:37:25Z</published>
		<category scheme="https://alancfrancis.com" term="Uncategorized" />
		<summary type="html"><![CDATA[OK. As of the end of part two we have an app and a widget for every platform and we have reduced ourselves to the minimum number of files. Everything is declared just once and used everywhere. I could stop here but there are a couple of loose ends to address before we&#8217;re done. Step [&#8230;]]]></summary>

					<content type="html" xml:base="https://alancfrancis.com/2023/06/24/once-and-only-once-part-3-loose-ends/"><![CDATA[
<p>OK.  As of <a href="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/">the end of part two</a> we have an app and a widget for every platform and we have reduced ourselves to the minimum number of files.  Everything is declared just once and used everywhere.  I could stop here but there are a couple of loose ends to address before we&#8217;re done.</p>



<hr class="wp-block-separator has-alpha-channel-opacity" />



<h2 class="wp-block-heading">Step 11: Tidying up</h2>



<p>The first thing I want to do is get the timeline code out of the widget file.</p>



<p>Create a new file, JustOneThingProvider.swift in the WidgetShared folder.  Cut and paste the Provider and SimpleEntry structs over there.  Change the imports to <code>import WidgetKit</code> and <code>import Intents</code></p>



<figure class="wp-block-image size-large"><img loading="lazy" width="772" height="680" data-attachment-id="2598" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-3-loose-ends/screenshot-2023-06-24-at-13-51-10/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.51.10.png" data-orig-size="772,680" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-24-at-13.51.10" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.51.10.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.51.10.png?w=772" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.51.10.png?w=772" alt="" class="wp-image-2598" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.51.10.png 772w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.51.10.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.51.10.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.51.10.png?w=768 768w" sizes="(max-width: 772px) 100vw, 772px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="543" data-attachment-id="2599" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-3-loose-ends/screenshot-2023-06-24-at-13-52-12/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.52.12.png" data-orig-size="1116,592" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-24-at-13.52.12" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.52.12.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.52.12.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.52.12.png?w=1024" alt="" class="wp-image-2599" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.52.12.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.52.12.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.52.12.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.52.12.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-13.52.12.png 1116w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>we&#8217;ll also add the preview back in.  Add this code to the bottom of the JustOneThingWidget.swift file to have a simple preview that works on on iPhone and Watch.  Note you need to have one of the widget targets active for the preview to work.</p>



<p>We&#8217;re creating the EntryView with a simple entry and we use a different previewContext for watch, or iOS/macOS which share a set of families.  I event seen the widget preview work on macOS.  You need to run the extension and it opens in the widget gallery app.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="513" data-attachment-id="2601" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-3-loose-ends/screenshot-2023-06-24-at-14-19-59/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.19.59.png" data-orig-size="1216,610" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-24-at-14.19.59" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.19.59.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.19.59.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.19.59.png?w=1024" alt="" class="wp-image-2601" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.19.59.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.19.59.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.19.59.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.19.59.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.19.59.png 1216w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>If you pick one of the iOS or watchOS widget targets you should see an appropriate preview (its just a timestamp :).</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="828" height="780" data-attachment-id="2603" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-3-loose-ends/screenshot-2023-06-24-at-14-25-46/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.46.png" data-orig-size="828,780" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-24-at-14.25.46" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.46.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.46.png?w=828" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.46.png?w=828" alt="" class="wp-image-2603" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.46.png 828w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.46.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.46.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.46.png?w=768 768w" sizes="(max-width: 828px) 100vw, 828px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="846" height="962" data-attachment-id="2605" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-3-loose-ends/screenshot-2023-06-24-at-14-25-59/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.59.png" data-orig-size="846,962" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-24-at-14.25.59" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.59.png?w=264" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.59.png?w=846" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.59.png?w=846" alt="" class="wp-image-2605" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.59.png 846w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.59.png?w=132 132w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.59.png?w=264 264w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.25.59.png?w=768 768w" sizes="(max-width: 846px) 100vw, 846px" /></figure>



<p>The last thing I want to do in this step is rename the watch app target/folder etc because &#8220;JustOneThingWatch Watch App&#8221; is a bit redundant.</p>



<p>First rename the folder and remove the Watch App part.  Dont forget to also remove the first space or you&#8217;ll be really confused later.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="882" height="494" data-attachment-id="2607" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-3-loose-ends/screenshot-2023-06-24-at-14-28-24/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.28.24.png" data-orig-size="882,494" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-24-at-14.28.24" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.28.24.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.28.24.png?w=882" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.28.24.png?w=882" alt="" class="wp-image-2607" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.28.24.png 882w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.28.24.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.28.24.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.28.24.png?w=768 768w" sizes="(max-width: 882px) 100vw, 882px" /></figure>



<p>Then rename the entitlements file in the same way.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="710" height="526" data-attachment-id="2610" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-3-loose-ends/screenshot-2023-06-24-at-14-28-27/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.28.27.png" data-orig-size="710,526" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-24-at-14.28.27" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.28.27.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.28.27.png?w=710" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.28.27.png?w=710" alt="" class="wp-image-2610" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.28.27.png 710w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.28.27.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.28.27.png?w=300 300w" sizes="(max-width: 710px) 100vw, 710px" /></figure>



<p>Now we need to go to the build settings for the watch app target and rename the target.  Go into the settings and find the entitlements entry to make sure that reads <code>JustOneThingWatchApp/JustOneThingWatchApp.entitlements</code></p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="206" data-attachment-id="2612" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-3-loose-ends/screenshot-2023-06-24-at-14-36-18/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.36.18.png" data-orig-size="1690,340" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-24-at-14.36.18" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.36.18.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.36.18.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.36.18.png?w=1024" alt="" class="wp-image-2612" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.36.18.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.36.18.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.36.18.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.36.18.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.36.18.png 1690w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Lastly, just for good hygiene, we can rename the scheme used to build and run the watch app.</p>



<p>Use the Product-&gt;Scheme-&gt;Manage Schemes menu</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="363" data-attachment-id="2614" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-3-loose-ends/screenshot-2023-06-24-at-14-37-31/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.37.31.png" data-orig-size="1354,480" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-24-at-14.37.31" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.37.31.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.37.31.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.37.31.png?w=1024" alt="" class="wp-image-2614" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.37.31.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.37.31.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.37.31.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.37.31.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.37.31.png 1354w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>and rename the scheme to match the target (delete the &#8220;&lt;space&gt;Watch App&#8221;)</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="588" data-attachment-id="2616" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-3-loose-ends/screenshot-2023-06-24-at-14-29-52/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.29.52.png" data-orig-size="1142,656" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-24-at-14.29.52" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.29.52.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.29.52.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.29.52.png?w=1024" alt="" class="wp-image-2616" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.29.52.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.29.52.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.29.52.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.29.52.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-24-at-14.29.52.png 1142w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>OK, lets commit again!</p>



<p>At this point we have added no custom code of our own (aside from the empty app groups entitlement that we will undoubtedly need to share data between app and widget) and all we have is as if Xcode offered a &#8220;Multiplatform app and Widgets&#8221; template.  The actual contents of the App, the ContentView, the Provider and the Widget are all still what Apple gave us, just with the duplication extracted.  That seems a good place to leave things for this part.  Next time I&#8217;ll walk through adding my actual widget contents and configuration.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://alancfrancis.com/2023/06/24/once-and-only-once-part-3-loose-ends/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://alancfrancis.com/2023/06/24/once-and-only-once-part-3-loose-ends/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>alancfrancis</name>
							<uri>https://alancfrancis.wordpress.com</uri>
						</author>

		<title type="html"><![CDATA[Once and Only Once (Part 2 : Widgets)]]></title>
		<link rel="alternate" type="text/html" href="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/" />

		<id>http://alancfrancis.com/?p=2512</id>
		<updated>2023-06-24T18:37:56Z</updated>
		<published>2023-06-24T18:35:27Z</published>
		<category scheme="https://alancfrancis.com" term="Uncategorized" />
		<summary type="html"><![CDATA[In Part One of this article we created an Xcode Project that builds an app for macOS, tvOS, iOS and watchOS and removed all the (to us) redundant duplication that Xcode had added for each template. In this part we&#8217;ll add widgets for Mac, Phone and Watch and try to do the same job of [&#8230;]]]></summary>

					<content type="html" xml:base="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/"><![CDATA[
<p><a href="https://alancfrancis.com/2023/06/24/once-and-only-once-part-1-apps/">In Part One of this article</a> we created an Xcode Project that builds an app for macOS, tvOS, iOS and watchOS and removed all the (to us) redundant duplication that Xcode had added for each template.  In this part we&#8217;ll add widgets for Mac, Phone and Watch and try to do the same job of sharing files where can to give us a single place to change things.</p>



<hr class="wp-block-separator has-alpha-channel-opacity" />



<h2 class="wp-block-heading">Step 7: Adding Widgets</h2>



<p>In the targets list in the project file we&#8217;ll add a &#8220;Widget Extension&#8221; from each of macOS, iOS and watchOS (no widgets on tvOS).</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="298" data-attachment-id="2516" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-11-at-13-23-25/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.23.25.png" data-orig-size="1456,424" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-11-at-13.23.25" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.23.25.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.23.25.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.23.25.png?w=1024" alt="" class="wp-image-2516" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.23.25.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.23.25.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.23.25.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.23.25.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.23.25.png 1456w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="726" data-attachment-id="2519" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-11-at-13-24-19/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.24.19.png" data-orig-size="1500,1064" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-11-at-13.24.19" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.24.19.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.24.19.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.24.19.png?w=1024" alt="" class="wp-image-2519" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.24.19.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.24.19.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.24.19.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.24.19.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.24.19.png 1500w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>We name the widgets appropriately but otherwise accept the default.  Configuration Intents are common for configuring widgets so we&#8217;ll say yes to those.  We don&#8217;t need a Live Activity at the moment because my reminders don&#8217;t have any duration.  Mac and Phone get default embedded in JustOneThing, watch gets embedded in &#8220;Just One Thing WatchApp&#8221;.</p>



<p>After we&#8217;re done the navigator looks like this.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="882" height="1023" data-attachment-id="2521" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-11-at-13-43-09/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.43.09.png" data-orig-size="932,1082" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-11-at-13.43.09" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.43.09.png?w=258" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.43.09.png?w=882" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.43.09.png?w=882" alt="" class="wp-image-2521" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.43.09.png?w=882 882w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.43.09.png?w=129 129w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.43.09.png?w=258 258w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.43.09.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-13.43.09.png 932w" sizes="(max-width: 882px) 100vw, 882px" /></figure>



<p>So much duplication!  </p>



<ul class="wp-block-list">
<li>Once again the Assets, Info.plist and Intent Definition File are identical so we should be able to share those. </li>



<li>Only the Mac Widget project has an entitlements file.</li>



<li>Only the iOS Widget project has a WidgetBundle tagged with @Main.  Watch and Mac widgets have the @Main tag on the XXXWidget classes themselves.</li>



<li>The XXXWidget.swift files differ only in the names, and watch has some &#8220;recommendations&#8221; since Watch Widgets don&#8217;t use a full configuration UI like Mac+iOS.</li>
</ul>



<p>There&#8217;s a problem though.  We&#8217;ll commit anyway, just for posterity, but the code won&#8217;t currently build as all three Intent Definitions care a ConfigurationIntent class and Xcode complains.</p>



<p>For purposes of this article I was tempted to rename all three to get to a &#8220;it builds&#8221; state for this step.  We&#8217;d need to go change the timeline code in each widget to use the new individual name for the Intent.  Since the goal in the end is to make them more the same, not more different, I&#8217;m just going to leave them as is, broken, and commit so I know a known &#8220;starting point&#8221; when I begin the surgery to unify it all.</p>



<h2 class="wp-block-heading">Step 8: Extract a WidgetShared to MATCH AppShared.</h2>



<p>First we&#8217;ll make a new Group (with Folder) called WidgetShared.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="912" height="514" data-attachment-id="2527" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-11-at-20-20-22/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.20.22.png" data-orig-size="912,514" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-11-at-20.20.22" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.20.22.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.20.22.png?w=912" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.20.22.png?w=912" alt="" class="wp-image-2527" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.20.22.png 912w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.20.22.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.20.22.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.20.22.png?w=768 768w" sizes="(max-width: 912px) 100vw, 912px" /></figure>



<p>We can pick any one of the widgets (say Mac) and drag the Info. the Intent and the Assets to the WidgetShared folder and delete the other copies (from say Phone and watch).</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="556" height="806" data-attachment-id="2533" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-11-at-20-31-30/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.30.png" data-orig-size="556,806" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-11-at-20.31.30" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.30.png?w=207" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.30.png?w=556" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.30.png?w=556" alt="" class="wp-image-2533" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.30.png 556w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.30.png?w=103 103w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.30.png?w=207 207w" sizes="(max-width: 556px) 100vw, 556px" /></figure>



<p>We should check the intent definition is added to all three targets widget targets, and both app targets.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="522" height="1012" data-attachment-id="2530" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-11-at-20-31-37/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.37.png" data-orig-size="522,1012" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-11-at-20.31.37" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.37.png?w=155" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.37.png?w=522" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.37.png?w=522" alt="" class="wp-image-2530" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.37.png 522w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.37.png?w=77 77w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.37.png?w=155 155w" sizes="(max-width: 522px) 100vw, 522px" /></figure>



<p>The assets file we&#8217;ll rename to WidgetAssets just so we&#8217;re clear its different from the app and make sure its added to all three Widget targets.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="524" height="878" data-attachment-id="2532" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-11-at-20-31-44/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.44.png" data-orig-size="524,878" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-11-at-20.31.44" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.44.png?w=179" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.44.png?w=524" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.44.png?w=524" alt="" class="wp-image-2532" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.44.png 524w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.44.png?w=90 90w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.31.44.png?w=179 179w" sizes="(max-width: 524px) 100vw, 524px" /></figure>



<p>The Info.plist is more fiddly.  We have to go into the build settings for each widget target and change the Packaging-&gt; info.plist file to WidgetShared/Info.plist</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="426" data-attachment-id="2535" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-11-at-20-24-35/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.24.35.png" data-orig-size="1412,588" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-11-at-20.24.35" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.24.35.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.24.35.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.24.35.png?w=1024" alt="" class="wp-image-2535" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.24.35.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.24.35.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.24.35.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.24.35.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.24.35.png 1412w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Lastly we have the same problem we had in step 3 where the watch extension was being included in the Mac app.  Here we need to ensure the iPhone and Mac widget extensions are only included in the relevant builds (remember this is supposed to be a single app, but we have to be aware of the distinct platforms when it comes to embedding).</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="304" data-attachment-id="2538" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-11-at-20-25-52/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.25.52.png" data-orig-size="1310,390" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-11-at-20.25.52" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.25.52.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.25.52.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.25.52.png?w=1024" alt="" class="wp-image-2538" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.25.52.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.25.52.png?w=1021 1021w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.25.52.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.25.52.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.25.52.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-11-at-20.25.52.png 1310w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>For the main app target, make sure the Mac and iOS widget filters get set appropriately.</p>



<p>OK, it should all build for all platforms and we can go for another commit.  We now have:</p>



<ul class="wp-block-list">
<li>App
<ul class="wp-block-list">
<li>a Mac+iOS+TV app </li>



<li>a watch app </li>



<li>an AppShared folder for the bulk of the sources.</li>
</ul>
</li>



<li>Widgets
<ul class="wp-block-list">
<li>a Mac Widget Extension</li>



<li>a Phone Widget Extension</li>



<li>a Watch Widget Extension</li>



<li>a WidgetShared folder for the bulk of the sources</li>
</ul>
</li>
</ul>



<h2 class="wp-block-heading">Step 9: Just Like Step 6</h2>



<p>In step 6 I asked you to trust me and we added an entitlements file for each target.  We&#8217;re going to do the same for the widgets but its extra fiddly because Xcode puts them at the root of the project structure, so some manual move is required.</p>



<p>The Mac already has entitlements, so select first the Phone and then the Watch widget targets and add a new capability &#8211; App Groups.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="810" data-attachment-id="2570" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-23-at-19-00-50/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.00.50.png" data-orig-size="1142,904" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-23-at-19.00.50" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.00.50.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.00.50.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.00.50.png?w=1024" alt="" class="wp-image-2570" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.00.50.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.00.50.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.00.50.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.00.50.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.00.50.png 1142w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>These will be added to the root of the project (right at the top of the navigator) and so we&#8217;ll have to move them (and I renamed them too, because I think PhoneWidget and WatchWidget is quite enough).</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="564" height="768" data-attachment-id="2572" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-23-at-19-02-27/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.02.27.png" data-orig-size="564,768" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-23-at-19.02.27" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.02.27.png?w=220" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.02.27.png?w=564" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.02.27.png?w=564" alt="" class="wp-image-2572" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.02.27.png 564w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.02.27.png?w=110 110w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.02.27.png?w=220 220w" sizes="(max-width: 564px) 100vw, 564px" /></figure>



<p>Forst we can drag each entitlements file to the right Group, then we rename each by removing the word Extension from the filename.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="592" height="302" data-attachment-id="2574" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-23-at-19-04-09/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.04.09.png" data-orig-size="592,302" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-23-at-19.04.09" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.04.09.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.04.09.png?w=592" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.04.09.png?w=592" alt="" class="wp-image-2574" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.04.09.png 592w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.04.09.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.04.09.png?w=300 300w" sizes="(max-width: 592px) 100vw, 592px" /></figure>



<p>We have to tell the build settings about our change too, so got to the target settings for each of the Phone and Watch widgets and use the search bar to find&#8221; entitlements&#8221;.</p>



<p>We&#8217;ll replace &#8220;PhoneWidgetExtension.entitlements&#8221; with &#8220;PhoneWidget/PhoneWidget.entitlements&#8221; and do the same for the watch.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="656" height="278" data-attachment-id="2577" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-23-at-19-05-50/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.05.50.png" data-orig-size="656,278" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-23-at-19.05.50" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.05.50.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.05.50.png?w=656" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.05.50.png?w=656" alt="" class="wp-image-2577" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.05.50.png 656w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.05.50.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.05.50.png?w=300 300w" sizes="(max-width: 656px) 100vw, 656px" /></figure>



<p>Finally we are where we want to be.  Each widget has its own entitlements and they are named consistently. Lets commit.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="530" height="758" data-attachment-id="2579" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-23-at-19-06-15/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.06.15.png" data-orig-size="530,758" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-23-at-19.06.15" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.06.15.png?w=210" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.06.15.png?w=530" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.06.15.png?w=530" alt="" class="wp-image-2579" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.06.15.png 530w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.06.15.png?w=105 105w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.06.15.png?w=210 210w" sizes="(max-width: 530px) 100vw, 530px" /></figure>



<h2 class="wp-block-heading">Step 10: Sharing Code</h2>



<p>The work we&#8217;ve done on the widgets so far has shared configuration files and assets.  Like we did on the App targets it would be nice to share as much code as possible.</p>



<p>I&#8217;m not going to draw it all out, you can look for yourself, but if you compare the swift files PhoneWidget.swift, WatchWidget.swift and MacWidget.swift they are essentially identical except for the different names, and two distinct differences.</p>



<p>Firstly, the <code>Provid</code>er struct in the Watch widget has an additional method <code>recommendatio</code>ns( ) that&#8217;s used for configuration on the watch where the UI is limited and a full configuration interface is not possible.  In that situation the watch provides a few &#8220;pre-canned&#8221; configurations to choose from &#8211; the recommendations.</p>



<p>This is on the Provider, *not* the actual Widget, but still it doesnt hurt if that method appears on the Phone or Mac, its only Watch that needs it, so we&#8217;d be ok to pick the Watch version of <code>Provider</code> to share.  Phone and Mac will just ignore the method.</p>



<p>The second difference is directly related to the Widget however.  </p>



<p>On Mac and Watch, there&#8217;s a <code>@main</code> decorating the Widget struct. It s not there on Phone.  Why not?  On the Phone there&#8217;s an additional file <code>WidgetBundle</code> which as the <code>@main</code>.</p>



<p>WidgetBundle is used if the extension exports more than one kind of widget and it seems that Apple almost expect this of the Phone, but not of the Mac or  Watch.</p>



<p>Oversight? Or  maybe they&#8217;d prefer we make a new extension per widget on the Watch and Mac.  In either case, the distinction is arbitrary and so again we can choose the Phone version to share &#8211; all platforms with have a @main WidgetBundle wrapping an non-@main Widget.</p>



<p>Lets get started.</p>



<p>First lets Drag the WatchWidget.swift file to WidgetShared. We&#8217; ll pick that one just because it has the extra Provider method and will save us a few seconds.</p>



<p>Check its available in all three widget targets.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="782" height="878" data-attachment-id="2581" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-23-at-19-36-51/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.51.png" data-orig-size="782,878" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-23-at-19.36.51" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.51.png?w=267" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.51.png?w=782" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.51.png?w=782" alt="" class="wp-image-2581" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.51.png 782w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.51.png?w=134 134w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.51.png?w=267 267w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.51.png?w=768 768w" sizes="(max-width: 782px) 100vw, 782px" /></figure>



<p>Delete the PhoneWidget and WatchWidget files,</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="822" height="994" data-attachment-id="2583" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-23-at-19-36-03/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.03.png" data-orig-size="822,994" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-23-at-19.36.03" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.03.png?w=248" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.03.png?w=822" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.03.png?w=822" alt="" class="wp-image-2583" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.03.png 822w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.03.png?w=124 124w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.03.png?w=248 248w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.36.03.png?w=768 768w" sizes="(max-width: 822px) 100vw, 822px" /></figure>



<p>Then rename the WatchWidget.swift file to JustOneThingWidget.swift and edit the contents to remove the preview (for now) and rename the WatchWidgetEntryView and WatchWidget to JustOneThingWidgetEntryView and JustOneThingWidget.</p>



<p>The last thing we are going to do in this stage is bring across the WidgetBundle to make it shared as well.  We won&#8217;t need the file, but we&#8217;ll copy and paste the code.</p>



<p>First select the code in PhoneWidgetBundle.swift and copy it it over to the top of JustOneThingWidget.swift.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1018" height="540" data-attachment-id="2585" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-23-at-19-45-26/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.26.png" data-orig-size="1018,540" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-23-at-19.45.26" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.26.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.26.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.26.png?w=1018" alt="" class="wp-image-2585" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.26.png 1018w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.26.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.26.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.26.png?w=768 768w" sizes="(max-width: 1018px) 100vw, 1018px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="892" height="328" data-attachment-id="2586" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-23-at-19-45-48/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.48.png" data-orig-size="892,328" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-23-at-19.45.48" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.48.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.48.png?w=892" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.48.png?w=892" alt="" class="wp-image-2586" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.48.png 892w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.48.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.48.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.45.48.png?w=768 768w" sizes="(max-width: 892px) 100vw, 892px" /></figure>



<p>Replace the PhoneWidget parts with JustOneThingWidget</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="968" height="356" data-attachment-id="2588" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-23-at-19-46-28/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.28.png" data-orig-size="968,356" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-23-at-19.46.28" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.28.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.28.png?w=968" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.28.png?w=968" alt="" class="wp-image-2588" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.28.png 968w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.28.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.28.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.28.png?w=768 768w" sizes="(max-width: 968px) 100vw, 968px" /></figure>



<p>And we&#8217;ll need to remove the @main from the JustOneThingWidget struct below because we have it on the bundle now.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="1024" height="202" data-attachment-id="2590" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-23-at-19-46-06/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.06.png" data-orig-size="1776,352" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-23-at-19.46.06" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.06.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.06.png?w=1000" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.06.png?w=1024" alt="" class="wp-image-2590" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.06.png?w=1024 1024w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.06.png?w=1019 1019w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.06.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.06.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.06.png?w=768 768w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.46.06.png 1776w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>The last thing we need to do is delete the PhoneWidgetBundle.swift file because we don&#8217;t need it any more.</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="922" height="820" data-attachment-id="2591" data-permalink="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/screenshot-2023-06-23-at-19-50-47/" data-orig-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.50.47.png" data-orig-size="922,820" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="screenshot-2023-06-23-at-19.50.47" data-image-description="" data-image-caption="" data-medium-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.50.47.png?w=300" data-large-file="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.50.47.png?w=922" tabindex="0" role="button" src="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.50.47.png?w=922" alt="" class="wp-image-2591" srcset="https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.50.47.png 922w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.50.47.png?w=150 150w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.50.47.png?w=300 300w, https://alancfrancis.com/wp-content/uploads/2023/06/screenshot-2023-06-23-at-19.50.47.png?w=768 768w" sizes="(max-width: 922px) 100vw, 922px" /></figure>



<p>And that&#8217;s the end of Step 10!  Like the App we now have moved pretty much everything to a shared folder and all that&#8217;s left as target specific are the entitlements files.</p>



<p>This will change as we add support for different widget types, but for now, we have a single widget that displays and works on all of our platforms (no widgets on TV).</p>



<p>Lets commit and then <a href="https://alancfrancis.com/2023/06/24/once-and-only-once-part-3-loose-ends/">move on to Part 3</a>.</p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://alancfrancis.com/2023/06/24/once-and-only-once-part-2-widgets/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
	</feed>
