2:I[9275,[],""] 3:I[1343,[],""] 4:I[2650,["173","static/chunks/173-424fa9be91923976.js","231","static/chunks/231-1e7bbdc770c66fc3.js","521","static/chunks/521-7266f541e89dccd7.js","185","static/chunks/app/layout-1a67d20efb7fbcee.js"],"Providers"] 5:I[7848,["173","static/chunks/173-424fa9be91923976.js","231","static/chunks/231-1e7bbdc770c66fc3.js","521","static/chunks/521-7266f541e89dccd7.js","185","static/chunks/app/layout-1a67d20efb7fbcee.js"],"Header"] 6:I[231,["173","static/chunks/173-424fa9be91923976.js","49","static/chunks/49-d41f7eeba1de0524.js","231","static/chunks/231-1e7bbdc770c66fc3.js","847","static/chunks/847-d03f1a8cba4db626.js","404","static/chunks/app/blog/page-527c30508ff17cd7.js"],""] 0:["zCwPuQV_WbLEohhlcHJz-",[[["",{"children":["blog",{"children":["swiftui-for-small-internal-desktop-app-tools",{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],["",{"children":["blog",{"children":["swiftui-for-small-internal-desktop-app-tools",{"children":["__PAGE__",{},[["$L1",["$","div",null,{"className":"sm:px-8 mt-16 lg:mt-32","children":["$","div",null,{"className":"mx-auto w-full max-w-7xl lg:px-8","children":["$","div",null,{"className":"relative px-4 sm:px-8 lg:px-12","children":["$","div",null,{"className":"mx-auto max-w-2xl lg:max-w-5xl","children":["$","div",null,{"className":"xl:relative","children":["$","div",null,{"className":"mx-auto max-w-2xl","children":["$","article",null,{"children":[["$","header",null,{"className":"flex flex-col","children":[["$","h1",null,{"className":"mt-6 text-4xl font-bold tracking-tight text-zinc-800 sm:text-5xl dark:text-zinc-100","children":"SwiftUI for Mini Desktop Apps: A Tutorial"}],["$","time",null,{"dateTime":"2022-08-14T13:00:00.000Z","className":"order-first flex items-center text-base text-zinc-400 dark:text-zinc-500","children":[["$","span",null,{"className":"h-4 w-0.5 rounded-full bg-zinc-200 dark:bg-zinc-500"}],["$","span",null,{"className":"ml-3","children":"14 August 2022"}]]}]]}],["$","div",null,{"className":"mt-8 prose dark:prose-invert","data-mdx-content":true,"children":[["$","p",null,{"children":["A little while ago I wrote about the ",["$","a",null,{"href":"/blog/swiftui-in-late-2021/","children":"state of SwiftUI"}],". While I was generally skeptical of the technology as a general purpose/widely used solution it still has some major strengths thanks to Apple integration and the Swift language. Here I want to look at something that it does very nicely: making a small GUI Mac desktop App. You can follow along in Xcode (which in later 13.x releases has improved a lot). I will try to make this accessible to non-Swift developers."]}],"\n",["$","p",null,{"children":"We will make a small App to configure a JSON file and save it; the kind of thing you might actually want to do on larger project. Also the kind of thing where getting it correct is important; something Swift's strong type system can help with."}],"\n",["$","h2",null,{"children":"Start"}],"\n",["$","p",null,{"children":["Create a new project, choose ",["$","code",null,{"children":"App"}]," within the ",["$","code",null,{"children":"macOS"}]," platform tab. The ",["$","code",null,{"children":"Document App"}]," is also something it does well (as in documents on your computer, how retro(!)), but today I'm going to focus on the simpler case. Choose ",["$","code",null,{"children":"SwiftUI"}]," for interface and ",["$","code",null,{"children":"Next"}],". The main file will look like the below. We will just work in this file to keep things simple; Swift like many modern languages isn't picky about where you put code. You shouldn't do this for any non-trivial real projects."]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"import"}]," ",["$","span",null,{"className":"token class-name","children":"SwiftUI"}],"\n\n",["$","span",null,{"className":"token keyword","children":"struct"}]," ",["$","span",null,{"className":"token class-name","children":"ContentView"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"var"}]," body",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token keyword","children":"some"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"Text"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Hello, world!\""}]}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"padding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n",["$","span",null,{"className":"token keyword","children":"struct"}]," ",["$","span",null,{"className":"token class-name","children":"ContentView_Previews"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"PreviewProvider"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"static"}]," ",["$","span",null,{"className":"token keyword","children":"var"}]," previews",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token keyword","children":"some"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"ContentView"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":"Hit \"Cmd + R\" to run the project. You should see a window with the text \"Hello, world!\"."}],"\n",["$","h2",null,{"children":"Codability"}],"\n",["$","p",null,{"children":["Modern Swift often uses ",["$","code",null,{"children":"structs"}]," for data modelling. They have value semantics (rather than the reference semantics of ",["$","code",null,{"children":"classes"}],") which can often make them easier to work with, especially when we want to avoid mutating data as that is harder to keep track of in our heads."]}],"\n",["$","p",null,{"children":"In Swift we can conform to a protocol (what most languages call implement an interface). There are some 'magic' protocols which the Swift compiler will conform to for us. Let's dive in and see an example:"}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"struct"}]," ",["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"Codable"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"var"}]," id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],"\n ",["$","span",null,{"className":"token keyword","children":"var"}]," name",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],"\n ",["$","span",null,{"className":"token keyword","children":"var"}]," kind",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"StepKind"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":["But let's say we want to model that something is one of set of things, for these we use ",["$","code",null,{"children":"enums"}],"."]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"enum"}]," ",["$","span",null,{"className":"token class-name","children":"StepKind"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token class-name","children":"Codable"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"case"}]," textEntry",["$","span",null,{"className":"token punctuation","children":","}]," numberEntry\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":["Roughly speaking something can be ",["$","code",null,{"children":"Codable"}]," if it is composed of ",["$","code",null,{"children":"Codable"}]," things. Let's look at how we can encode this to JSON. First, let's create some sample data (Swift follows Haskell in wrapping something in ",["$","code",null,{"children":"[]"}]," to make it an array)."]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"let"}]," sample",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"["}],["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":"]"}]," ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token punctuation","children":"["}],"\n ",["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":"("}],"id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"1\""}]}],["$","span",null,{"className":"token punctuation","children":","}]," name",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Name\""}]}],["$","span",null,{"className":"token punctuation","children":","}]," kind",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"textEntry",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}],"\n ",["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":"("}],"id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"2\""}]}],["$","span",null,{"className":"token punctuation","children":","}]," name",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Age\""}]}],["$","span",null,{"className":"token punctuation","children":","}]," kind",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"numberEntry",["$","span",null,{"className":"token punctuation","children":")"}],"\n",["$","span",null,{"className":"token punctuation","children":"]"}],"\n"]}]}],"\n",["$","p",null,{"children":"Now replace our UI with:"}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"struct"}]," ",["$","span",null,{"className":"token class-name","children":"ContentView"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"var"}]," body",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token keyword","children":"some"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"VStack"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"Button"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token function","children":"print"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"try"}],["$","span",null,{"className":"token operator","children":"!"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],["$","span",null,{"className":"token punctuation","children":"("}],"data",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"JSONEncoder"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"encode"}],["$","span",null,{"className":"token punctuation","children":"("}],"sample",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}]," encoding",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"utf8",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token operator","children":"!"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}]," label",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"Text"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Encode\""}]}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":"Let's unpack that:"}],"\n",["$","ul",null,{"children":["\n",["$","li",null,{"children":[["$","code",null,{"children":"print("}]," Swift's general purpose ",["$","code",null,{"children":"print"}]," function."]}],"\n",["$","li",null,{"children":[["$","code",null,{"children":"try!"}]," Danger(!) but for small utility things this is okay. Tells Swift not to worry about this crashing."]}],"\n",["$","li",null,{"children":[["$","code",null,{"children":"String(data: "}]," Covert the data to a string."]}],"\n",["$","li",null,{"children":[["$","code",null,{"children":"JSONEncoder().encode(sample)"}]," The actual JSON encoding; which is very simple. Decoding is similar."]}],"\n",["$","li",null,{"children":[["$","code",null,{"children":", encoding: .utf8)"}]," We must choose a text encoding for the string."]}],"\n",["$","li",null,{"children":[["$","code",null,{"children":"!)"}]," Danger(!) this might not succeed in general, so we are telling Swift again not to worry."]}],"\n"]}],"\n",["$","p",null,{"children":"The above was very brief but perhaps you are willing to believe that:"}],"\n",["$","ol",null,{"children":["\n",["$","li",null,{"children":"Swift can model data in a strict, concise and yet flexible way"}],"\n",["$","li",null,{"children":"It can very easily convert data to (and from) JSON"}],"\n"]}],"\n",["$","h2",null,{"children":"UI and State"}],"\n",["$","p",null,{"children":["Let's create a simple UI to edit the data. In SwiftUI a convenient way to this (for non-simple cases) is with an ",["$","code",null,{"children":"ObservableObject"}],". This is a class where we can listen to changes. Let's do it:"]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"class"}]," ",["$","span",null,{"className":"token class-name","children":"AppState"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"ObservableObject"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"var"}]," steps",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"["}],["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":"]"}]," ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token punctuation","children":"["}],["$","span",null,{"className":"token punctuation","children":"]"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"func"}]," ",["$","span",null,{"className":"token function-definition function","children":"updateStep"}],["$","span",null,{"className":"token punctuation","children":"("}],"step",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"if"}]," ",["$","span",null,{"className":"token keyword","children":"let"}]," idx ",["$","span",null,{"className":"token operator","children":"="}]," steps",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"firstIndex"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"where"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}]," ",["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":"."}],"id ",["$","span",null,{"className":"token operator","children":"=="}]," step",["$","span",null,{"className":"token punctuation","children":"."}],"id ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n steps",["$","span",null,{"className":"token punctuation","children":"["}],"idx",["$","span",null,{"className":"token punctuation","children":"]"}]," ",["$","span",null,{"className":"token operator","children":"="}]," step\n objectWillChange",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"send"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"func"}]," ",["$","span",null,{"className":"token function-definition function","children":"addStep"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n steps",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"append"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":"("}],"id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token function","children":"UUID"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":"."}],"uuidString",["$","span",null,{"className":"token punctuation","children":","}]," name",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"\""}]}],["$","span",null,{"className":"token punctuation","children":","}]," kind",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"textEntry",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n objectWillChange",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"send"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":["A couple of key things. We use ",["$","code",null,{"children":"objectWillChange"}]," to tell Swift that something has changed. So any UI that depends on the state can be updated. To update a step we look for first matching item and change it."]}],"\n",["$","p",null,{"children":["We could easily add things like a ",["$","code",null,{"children":"remove"}]," function and it would be very encapsulated and decoupled from our UI."]}],"\n",["$","p",null,{"children":"We can hook up to the UI with one line of code:"}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token attribute atrule","children":"@StateObject"}]," ",["$","span",null,{"className":"token keyword","children":"var"}]," state ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token class-name","children":"AppState"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n"]}]}],"\n",["$","p",null,{"children":"this both sets up the state and observes it (on changes UI will update)."}],"\n",["$","p",null,{"children":["We are going to need one more thing though, SwiftUI uses a ",["$","code",null,{"children":"protocol"}]," called ",["$","code",null,{"children":"Identifiable"}]," to distinguish items in a collection. So we'll update our data code a little:"]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"struct"}]," ",["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"Codable"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token class-name","children":"Identifiable"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"var"}]," id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],"\n ",["$","span",null,{"className":"token keyword","children":"var"}]," name",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],"\n ",["$","span",null,{"className":"token keyword","children":"var"}]," kind",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"StepKind"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n",["$","span",null,{"className":"token keyword","children":"enum"}]," ",["$","span",null,{"className":"token class-name","children":"StepKind"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token class-name","children":"Codable"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token class-name","children":"Identifiable"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token class-name","children":"CaseIterable"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"case"}]," textEntry",["$","span",null,{"className":"token punctuation","children":","}]," numberEntry\n\n ",["$","span",null,{"className":"token keyword","children":"var"}]," id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n rawValue\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":["For the first one it is easy, we are actually already conforming. In the second case we must implement an ",["$","code",null,{"children":"id"}],". We also add ",["$","code",null,{"children":"CaseIterable"}]," (this will be convenient later as it gives us a ",["$","code",null,{"children":"StepKind.allCases"}]," or simple way to iterate over the cases)."]}],"\n",["$","h2",null,{"children":"Wire up the UI"}],"\n",["$","p",null,{"children":"Let's build a UI. This can be quite concise, yet very clear and easy to change. Let's overhaul what we had. As before we start with:"}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"struct"}]," ",["$","span",null,{"className":"token class-name","children":"ContentView"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token attribute atrule","children":"@StateObject"}]," ",["$","span",null,{"className":"token keyword","children":"var"}]," state ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token class-name","children":"AppState"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"var"}]," body",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token keyword","children":"some"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n"]}]}],"\n",["$","p",null,{"children":["Now we add in a ",["$","code",null,{"children":"ScrollView"}]," which will allow for lots of items, then a ",["$","code",null,{"children":"LazyVStack"}],"; this is a special view where items are lazily included on screen as needed."]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[" ",["$","span",null,{"className":"token class-name","children":"ScrollView"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"LazyVStack"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n"]}]}],"\n",["$","p",null,{"children":["Now we iterate over the ",["$","code",null,{"children":"state.steps"}],". This ",["$","code",null,{"children":"ForEach"}]," is a special view that works with a collections of ",["$","code",null,{"children":"Identifiable"}]," items."]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[" ",["$","span",null,{"className":"token class-name","children":"ForEach"}],["$","span",null,{"className":"token punctuation","children":"("}],"state",["$","span",null,{"className":"token punctuation","children":"."}],"steps",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}]," item ",["$","span",null,{"className":"token keyword","children":"in"}],"\n ",["$","span",null,{"className":"token class-name","children":"Text"}],["$","span",null,{"className":"token punctuation","children":"("}],"item",["$","span",null,{"className":"token punctuation","children":"."}],"id",["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":["Let's set a size with a ",["$","code",null,{"children":"frame"}]," modifier."]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[" ",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"frame"}],["$","span",null,{"className":"token punctuation","children":"("}],"minWidth",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token number","children":"800"}],["$","span",null,{"className":"token punctuation","children":","}]," minHeight",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token number","children":"640"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n"]}]}],"\n",["$","p",null,{"children":["And now add a ",["$","code",null,{"children":"Toolbar"}],", the native MacOS header bar:"]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[" ",["$","span",null,{"className":"token punctuation","children":"."}],"toolbar ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"ToolbarItemGroup"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n"]}]}],"\n",["$","p",null,{"children":"We can add buttons to it, as before, but now they will have the correct appearance for a Toolbar."}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[" ",["$","span",null,{"className":"token class-name","children":"Button"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n"]}]}],"\n",["$","p",null,{"children":"And wiring up our action is just:"}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[" state",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"addStep"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}]," label",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n"]}]}],"\n",["$","p",null,{"children":"We add a icon with SwiftUI's system image feature."}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[" ",["$","span",null,{"className":"token class-name","children":"Image"}],["$","span",null,{"className":"token punctuation","children":"("}],"systemName",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"plus\""}]}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":["Finally tweak what we had before by using the ",["$","code",null,{"children":"state.steps"}]," to print our actual data."]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[" ",["$","span",null,{"className":"token class-name","children":"Button"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token function","children":"print"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"try"}],["$","span",null,{"className":"token operator","children":"!"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],["$","span",null,{"className":"token punctuation","children":"("}],"data",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"JSONEncoder"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"encode"}],["$","span",null,{"className":"token punctuation","children":"("}],"state",["$","span",null,{"className":"token punctuation","children":"."}],"steps",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}]," encoding",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"utf8",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token operator","children":"!"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}]," label",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"Text"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Save\""}]}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":"}"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":"Try running this. You should see a proper native looking UI. When you click on the plus button it will add a new item. When you click on Save it will print the data to the console."}],"\n",["$","h2",null,{"children":"Item Editor(s)"}],"\n",["$","p",null,{"children":["Let's create a component (in SwiftUI terms a ",["$","code",null,{"children":"View"}],") to edit an item. The UI part is easy enough with a ",["$","code",null,{"children":"HStack"}]," (horizontal container) and a few form fields. To do a two way binding we add a binding helper to the ",["$","code",null,{"children":"AppState"}],". While our state code will get a bit messier our UI code is fairly simple."]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"struct"}]," ",["$","span",null,{"className":"token class-name","children":"ItemEditor"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token attribute atrule","children":"@ObservedObject"}]," ",["$","span",null,{"className":"token keyword","children":"var"}]," state",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"AppState"}],"\n ",["$","span",null,{"className":"token keyword","children":"var"}]," id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"var"}]," body",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token keyword","children":"some"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"HStack"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"TextField"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Name\""}]}],["$","span",null,{"className":"token punctuation","children":","}]," text",["$","span",null,{"className":"token punctuation","children":":"}]," state",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"textBinding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"for"}],["$","span",null,{"className":"token punctuation","children":":"}]," id",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n\n ",["$","span",null,{"className":"token class-name","children":"Picker"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Kind\""}]}],["$","span",null,{"className":"token punctuation","children":","}]," selection",["$","span",null,{"className":"token punctuation","children":":"}]," state",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"kindBinding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"for"}],["$","span",null,{"className":"token punctuation","children":":"}]," id",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"ForEach"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token class-name","children":"StepKind"}],["$","span",null,{"className":"token punctuation","children":"."}],"allCases",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"Text"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":"."}],"rawValue",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"tag"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"padding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":"We set up the helper bindings (basically a getter and setter for each item) like:"}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"func"}]," ",["$","span",null,{"className":"token function-definition function","children":"textBinding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"for"}]," id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"->"}]," ",["$","span",null,{"className":"token class-name","children":"Binding"}],["$","span",null,{"className":"token operator","children":"<"}],["$","span",null,{"className":"token class-name","children":"String"}],["$","span",null,{"className":"token operator","children":">"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"if"}]," ",["$","span",null,{"className":"token keyword","children":"let"}]," step ",["$","span",null,{"className":"token operator","children":"="}]," steps",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"first"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"where"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}]," ",["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":"."}],"id ",["$","span",null,{"className":"token operator","children":"=="}]," id ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token class-name","children":"Binding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"get"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}]," step",["$","span",null,{"className":"token punctuation","children":"."}],"name ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token keyword","children":"set"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"self"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"updateStep"}],["$","span",null,{"className":"token punctuation","children":"("}],"step",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":"("}],"id",["$","span",null,{"className":"token punctuation","children":":"}]," step",["$","span",null,{"className":"token punctuation","children":"."}],"id",["$","span",null,{"className":"token punctuation","children":","}]," name",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":","}]," kind",["$","span",null,{"className":"token punctuation","children":":"}]," step",["$","span",null,{"className":"token punctuation","children":"."}],"kind ",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}]," ",["$","span",null,{"className":"token keyword","children":"else"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token class-name","children":"Binding"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"constant"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"\""}]}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"func"}]," ",["$","span",null,{"className":"token function-definition function","children":"kindBinding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"for"}]," id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"->"}]," ",["$","span",null,{"className":"token class-name","children":"Binding"}],["$","span",null,{"className":"token operator","children":"<"}],["$","span",null,{"className":"token class-name","children":"StepKind"}],["$","span",null,{"className":"token operator","children":">"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"if"}]," ",["$","span",null,{"className":"token keyword","children":"let"}]," step ",["$","span",null,{"className":"token operator","children":"="}]," steps",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"first"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"where"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}]," ",["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":"."}],"id ",["$","span",null,{"className":"token operator","children":"=="}]," id ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token class-name","children":"Binding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"get"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}]," step",["$","span",null,{"className":"token punctuation","children":"."}],"kind ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token keyword","children":"set"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"self"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"updateStep"}],["$","span",null,{"className":"token punctuation","children":"("}],"step",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":"("}],"id",["$","span",null,{"className":"token punctuation","children":":"}]," step",["$","span",null,{"className":"token punctuation","children":"."}],"id",["$","span",null,{"className":"token punctuation","children":","}]," name",["$","span",null,{"className":"token punctuation","children":":"}]," step",["$","span",null,{"className":"token punctuation","children":"."}],"name",["$","span",null,{"className":"token punctuation","children":","}]," kind",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token short-argument","children":"$$0"}]," ",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}]," ",["$","span",null,{"className":"token keyword","children":"else"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token class-name","children":"Binding"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"constant"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":"."}],"textEntry",["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","h2",null,{"children":"Save Files"}],"\n",["$","p",null,{"children":["Let's save the file. This is, like much Apple stuff non-obvious and horribly documented. First in the main target (browse to what seems like the top level item in the project), ",["$","code",null,{"children":"Targets"}],", ",["$","code",null,{"children":"Signing & Capabilties"}],", ",["$","code",null,{"children":"App Sandbox"}]," and choose in ",["$","code",null,{"children":"File Access"}],", ",["$","code",null,{"children":"User Selected File"}],": ",["$","code",null,{"children":"Read/Write"}],". If you don't do that it won't work."]}],"\n",["$","p",null,{"children":["Let's create a save function and add it to the ",["$","code",null,{"children":"AppState"}],". This is a basic thing that will work and that ignores problems:"]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"func"}]," ",["$","span",null,{"className":"token function-definition function","children":"save"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"let"}]," savePanel ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token class-name","children":"NSSavePanel"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n savePanel",["$","span",null,{"className":"token punctuation","children":"."}],"allowedContentTypes ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token punctuation","children":"["}],["$","span",null,{"className":"token punctuation","children":"."}],"json",["$","span",null,{"className":"token punctuation","children":"]"}],"\n savePanel",["$","span",null,{"className":"token punctuation","children":"."}],"canCreateDirectories ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token boolean","children":"true"}],"\n savePanel",["$","span",null,{"className":"token punctuation","children":"."}],"isExtensionHidden ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token boolean","children":"false"}],"\n savePanel",["$","span",null,{"className":"token punctuation","children":"."}],"title ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Save steps\""}]}],"\n savePanel",["$","span",null,{"className":"token punctuation","children":"."}],"message ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Choose where to save your steps\""}]}],"\n savePanel",["$","span",null,{"className":"token punctuation","children":"."}],"nameFieldLabel ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Fle name:\""}]}],"\n\n ",["$","span",null,{"className":"token keyword","children":"let"}]," response ",["$","span",null,{"className":"token operator","children":"="}]," savePanel",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"runModal"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token keyword","children":"if"}]," response ",["$","span",null,{"className":"token operator","children":"=="}]," ",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token constant","children":"OK"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"let"}]," stringToSave ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token class-name","children":"String"}],["$","span",null,{"className":"token punctuation","children":"("}],"data",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token keyword","children":"try"}],["$","span",null,{"className":"token operator","children":"!"}]," ",["$","span",null,{"className":"token class-name","children":"JSONEncoder"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"encode"}],["$","span",null,{"className":"token punctuation","children":"("}],"steps",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}]," encoding",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"utf8",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token operator","children":"!"}],"\n ",["$","span",null,{"className":"token keyword","children":"try"}],["$","span",null,{"className":"token operator","children":"!"}]," stringToSave",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"write"}],["$","span",null,{"className":"token punctuation","children":"("}],"to",["$","span",null,{"className":"token punctuation","children":":"}]," savePanel",["$","span",null,{"className":"token punctuation","children":"."}],"url",["$","span",null,{"className":"token operator","children":"!"}],["$","span",null,{"className":"token punctuation","children":","}]," atomically",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token boolean","children":"true"}],["$","span",null,{"className":"token punctuation","children":","}]," encoding",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"utf8",["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":"We update the save button to:"}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token class-name","children":"Button"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n state",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"save"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}]," label",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"Text"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Save\""}]}],["$","span",null,{"className":"token punctuation","children":")"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":"And we are basically done. We can distribute the App in a number of ways, including the Mac App Store. There are a few things like icons we should probably also take care of. But I want to try to demonstrate one of the main benefits of declarative UI, that we can come back to projects later and sanely modify them."}],"\n",["$","h2",null,{"children":"Making changes: deleting items"}],"\n",["$","p",null,{"children":"Here is a complete implementation of delete business logic:"}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"func"}]," ",["$","span",null,{"className":"token function-definition function","children":"removeStep"}],["$","span",null,{"className":"token punctuation","children":"("}],"id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n steps",["$","span",null,{"className":"token punctuation","children":"."}],"removeAll ",["$","span",null,{"className":"token punctuation","children":"{"}]," ",["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":"."}],"id ",["$","span",null,{"className":"token operator","children":"=="}]," id ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n objectWillChange",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"send"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":["In our ",["$","code",null,{"children":"ItemEditor"}]," we add a button to delete the item."]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token class-name","children":"Button"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n state",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"removeStep"}],["$","span",null,{"className":"token punctuation","children":"("}],"id",["$","span",null,{"className":"token punctuation","children":":"}]," id",["$","span",null,{"className":"token punctuation","children":")"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}]," label",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"Image"}],["$","span",null,{"className":"token punctuation","children":"("}],"systemName",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"minus.square\""}]}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"resizable"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"aspectRatio"}],["$","span",null,{"className":"token punctuation","children":"("}],"contentMode",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"fit",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"frame"}],["$","span",null,{"className":"token punctuation","children":"("}],"width",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token number","children":"24"}],["$","span",null,{"className":"token punctuation","children":","}]," height",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token number","children":"24"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"buttonStyle"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token class-name","children":"PlainButtonStyle"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n"]}]}],"\n",["$","p",null,{"children":"Done. Nicely decoupled logic. Trivial wiring up."}],"\n",["$","h2",null,{"children":"Making changes: adding a hint"}],"\n",["$","p",null,{"children":["Above the ",["$","code",null,{"children":"LazyVStack"}]," add:"]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"if"}]," state",["$","span",null,{"className":"token punctuation","children":"."}],"steps",["$","span",null,{"className":"token punctuation","children":"."}],"isEmpty ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"Text"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Add steps via +\""}]}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"font"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":"."}],"headline",["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"padding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":"Done: when the list is empty you get a nice prompt."}],"\n",["$","h2",null,{"children":"Kind Labels"}],"\n",["$","p",null,{"children":[["$","code",null,{"children":"textEntry"}]," looks ugly let's fix that. Add"]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"var"}]," label",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"switch"}]," ",["$","span",null,{"className":"token keyword","children":"self"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"case"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"textEntry",["$","span",null,{"className":"token punctuation","children":":"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Text\""}]}],"\n ",["$","span",null,{"className":"token keyword","children":"case"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"numberEntry",["$","span",null,{"className":"token punctuation","children":":"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Number\""}]}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","p",null,{"children":["In ",["$","code",null,{"children":"StepKind"}]," and update the ",["$","code",null,{"children":"Picker"}]," code to:"]}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token class-name","children":"Picker"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Kind\""}]}],["$","span",null,{"className":"token punctuation","children":","}]," selection",["$","span",null,{"className":"token punctuation","children":":"}]," state",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"kindBinding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"for"}],["$","span",null,{"className":"token punctuation","children":":"}]," id",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"ForEach"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token class-name","children":"StepKind"}],["$","span",null,{"className":"token punctuation","children":"."}],"allCases",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"Text"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":"."}],"label",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"tag"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}],"\n",["$","h2",null,{"children":"Complete Code"}],"\n",["$","p",null,{"children":"The entire code is below. While some things are a little hacky (though in many cases reasonably so for a small helper) it is overall actually quite concise and readable. A 'real' app that did some kind of structured data editing (e.g. a wizard/flow editor) wouldn't really be that much more complex."}],"\n",["$","p",null,{"children":"And while many things are currently missing we are already supporting stuff like dark mode."}],"\n",["$","pre",null,{"className":"language-swift","children":["$","code",null,{"className":"language-swift","children":[["$","span",null,{"className":"token keyword","children":"import"}]," ",["$","span",null,{"className":"token class-name","children":"SwiftUI"}],"\n\n",["$","span",null,{"className":"token keyword","children":"struct"}]," ",["$","span",null,{"className":"token class-name","children":"ContentView"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token attribute atrule","children":"@StateObject"}]," ",["$","span",null,{"className":"token keyword","children":"var"}]," state ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token class-name","children":"AppState"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"var"}]," body",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token keyword","children":"some"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"ScrollView"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"if"}]," state",["$","span",null,{"className":"token punctuation","children":"."}],"steps",["$","span",null,{"className":"token punctuation","children":"."}],"isEmpty ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"Text"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Add steps via +\""}]}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"font"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":"."}],"headline",["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"padding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token class-name","children":"LazyVStack"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"ForEach"}],["$","span",null,{"className":"token punctuation","children":"("}],"state",["$","span",null,{"className":"token punctuation","children":"."}],"steps",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}]," item ",["$","span",null,{"className":"token keyword","children":"in"}],"\n ",["$","span",null,{"className":"token class-name","children":"ItemEditor"}],["$","span",null,{"className":"token punctuation","children":"("}],"state",["$","span",null,{"className":"token punctuation","children":":"}]," state",["$","span",null,{"className":"token punctuation","children":","}]," id",["$","span",null,{"className":"token punctuation","children":":"}]," item",["$","span",null,{"className":"token punctuation","children":"."}],"id",["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"frame"}],["$","span",null,{"className":"token punctuation","children":"("}],"minWidth",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token number","children":"800"}],["$","span",null,{"className":"token punctuation","children":","}]," minHeight",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token number","children":"640"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"."}],"toolbar ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"ToolbarItemGroup"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"Button"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n state",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"addStep"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}]," label",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"Image"}],["$","span",null,{"className":"token punctuation","children":"("}],"systemName",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"plus\""}]}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n ",["$","span",null,{"className":"token class-name","children":"Button"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n state",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"save"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}]," label",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"Text"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Save\""}]}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":"}"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n",["$","span",null,{"className":"token keyword","children":"struct"}]," ",["$","span",null,{"className":"token class-name","children":"ItemEditor"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token attribute atrule","children":"@ObservedObject"}]," ",["$","span",null,{"className":"token keyword","children":"var"}]," state",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"AppState"}],"\n ",["$","span",null,{"className":"token keyword","children":"var"}]," id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"var"}]," body",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token keyword","children":"some"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"HStack"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"TextField"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Name\""}]}],["$","span",null,{"className":"token punctuation","children":","}]," text",["$","span",null,{"className":"token punctuation","children":":"}]," state",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"textBinding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"for"}],["$","span",null,{"className":"token punctuation","children":":"}]," id",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n\n ",["$","span",null,{"className":"token class-name","children":"Picker"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Kind\""}]}],["$","span",null,{"className":"token punctuation","children":","}]," selection",["$","span",null,{"className":"token punctuation","children":":"}]," state",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"kindBinding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"for"}],["$","span",null,{"className":"token punctuation","children":":"}]," id",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"ForEach"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token class-name","children":"StepKind"}],["$","span",null,{"className":"token punctuation","children":"."}],"allCases",["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"Text"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":"."}],"label",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"tag"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n ",["$","span",null,{"className":"token class-name","children":"Button"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n state",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"removeStep"}],["$","span",null,{"className":"token punctuation","children":"("}],"id",["$","span",null,{"className":"token punctuation","children":":"}]," id",["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}]," label",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"Image"}],["$","span",null,{"className":"token punctuation","children":"("}],"systemName",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"minus.square\""}]}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"resizable"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"aspectRatio"}],["$","span",null,{"className":"token punctuation","children":"("}],"contentMode",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"fit",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"frame"}],["$","span",null,{"className":"token punctuation","children":"("}],"width",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token number","children":"24"}],["$","span",null,{"className":"token punctuation","children":","}]," height",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token number","children":"24"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"buttonStyle"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token class-name","children":"PlainButtonStyle"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"padding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n",["$","span",null,{"className":"token keyword","children":"struct"}]," ",["$","span",null,{"className":"token class-name","children":"ContentView_Previews"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"PreviewProvider"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"static"}]," ",["$","span",null,{"className":"token keyword","children":"var"}]," previews",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token keyword","children":"some"}]," ",["$","span",null,{"className":"token class-name","children":"View"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token class-name","children":"ContentView"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n",["$","span",null,{"className":"token keyword","children":"struct"}]," ",["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"Codable"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token class-name","children":"Identifiable"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"var"}]," id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],"\n ",["$","span",null,{"className":"token keyword","children":"var"}]," name",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],"\n ",["$","span",null,{"className":"token keyword","children":"var"}]," kind",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"StepKind"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n",["$","span",null,{"className":"token keyword","children":"enum"}]," ",["$","span",null,{"className":"token class-name","children":"StepKind"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token class-name","children":"Codable"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token class-name","children":"Identifiable"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token class-name","children":"CaseIterable"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"case"}]," textEntry",["$","span",null,{"className":"token punctuation","children":","}]," numberEntry\n\n ",["$","span",null,{"className":"token keyword","children":"var"}]," id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n rawValue\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"var"}]," label",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"switch"}]," ",["$","span",null,{"className":"token keyword","children":"self"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"case"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"textEntry",["$","span",null,{"className":"token punctuation","children":":"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Text\""}]}],"\n ",["$","span",null,{"className":"token keyword","children":"case"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"numberEntry",["$","span",null,{"className":"token punctuation","children":":"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Number\""}]}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n",["$","span",null,{"className":"token keyword","children":"let"}]," sample",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"["}],["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":"]"}]," ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token punctuation","children":"["}],"\n ",["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":"("}],"id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"1\""}]}],["$","span",null,{"className":"token punctuation","children":","}]," name",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Name\""}]}],["$","span",null,{"className":"token punctuation","children":","}]," kind",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"textEntry",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}],"\n ",["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":"("}],"id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"2\""}]}],["$","span",null,{"className":"token punctuation","children":","}]," name",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Age\""}]}],["$","span",null,{"className":"token punctuation","children":","}]," kind",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"numberEntry",["$","span",null,{"className":"token punctuation","children":")"}],"\n",["$","span",null,{"className":"token punctuation","children":"]"}],"\n\n",["$","span",null,{"className":"token keyword","children":"class"}]," ",["$","span",null,{"className":"token class-name","children":"AppState"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"ObservableObject"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"var"}]," steps",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"["}],["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":"]"}]," ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token punctuation","children":"["}],["$","span",null,{"className":"token punctuation","children":"]"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"func"}]," ",["$","span",null,{"className":"token function-definition function","children":"updateStep"}],["$","span",null,{"className":"token punctuation","children":"("}],"step",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"if"}]," ",["$","span",null,{"className":"token keyword","children":"let"}]," idx ",["$","span",null,{"className":"token operator","children":"="}]," steps",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"firstIndex"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"where"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}]," ",["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":"."}],"id ",["$","span",null,{"className":"token operator","children":"=="}]," step",["$","span",null,{"className":"token punctuation","children":"."}],"id ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n steps",["$","span",null,{"className":"token punctuation","children":"["}],"idx",["$","span",null,{"className":"token punctuation","children":"]"}]," ",["$","span",null,{"className":"token operator","children":"="}]," step\n objectWillChange",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"send"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"func"}]," ",["$","span",null,{"className":"token function-definition function","children":"addStep"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n steps",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"append"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":"("}],"id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token function","children":"UUID"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":"."}],"uuidString",["$","span",null,{"className":"token punctuation","children":","}]," name",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"\""}]}],["$","span",null,{"className":"token punctuation","children":","}]," kind",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"textEntry",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n objectWillChange",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"send"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"func"}]," ",["$","span",null,{"className":"token function-definition function","children":"removeStep"}],["$","span",null,{"className":"token punctuation","children":"("}],"id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n steps",["$","span",null,{"className":"token punctuation","children":"."}],"removeAll ",["$","span",null,{"className":"token punctuation","children":"{"}]," ",["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":"."}],"id ",["$","span",null,{"className":"token operator","children":"=="}]," id ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n objectWillChange",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"send"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"func"}]," ",["$","span",null,{"className":"token function-definition function","children":"textBinding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"for"}]," id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"->"}]," ",["$","span",null,{"className":"token class-name","children":"Binding"}],["$","span",null,{"className":"token operator","children":"<"}],["$","span",null,{"className":"token class-name","children":"String"}],["$","span",null,{"className":"token operator","children":">"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"if"}]," ",["$","span",null,{"className":"token keyword","children":"let"}]," step ",["$","span",null,{"className":"token operator","children":"="}]," steps",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"first"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"where"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}]," ",["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":"."}],"id ",["$","span",null,{"className":"token operator","children":"=="}]," id ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token class-name","children":"Binding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"get"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}]," step",["$","span",null,{"className":"token punctuation","children":"."}],"name ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token keyword","children":"set"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"self"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"updateStep"}],["$","span",null,{"className":"token punctuation","children":"("}],"step",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":"("}],"id",["$","span",null,{"className":"token punctuation","children":":"}]," step",["$","span",null,{"className":"token punctuation","children":"."}],"id",["$","span",null,{"className":"token punctuation","children":","}]," name",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":","}]," kind",["$","span",null,{"className":"token punctuation","children":":"}]," step",["$","span",null,{"className":"token punctuation","children":"."}],"kind ",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}]," ",["$","span",null,{"className":"token keyword","children":"else"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token class-name","children":"Binding"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"constant"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"\""}]}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"func"}]," ",["$","span",null,{"className":"token function-definition function","children":"kindBinding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"for"}]," id",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"String"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token operator","children":"->"}]," ",["$","span",null,{"className":"token class-name","children":"Binding"}],["$","span",null,{"className":"token operator","children":"<"}],["$","span",null,{"className":"token class-name","children":"StepKind"}],["$","span",null,{"className":"token operator","children":">"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"if"}]," ",["$","span",null,{"className":"token keyword","children":"let"}]," step ",["$","span",null,{"className":"token operator","children":"="}]," steps",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"first"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"where"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}]," ",["$","span",null,{"className":"token short-argument","children":"$$0"}],["$","span",null,{"className":"token punctuation","children":"."}],"id ",["$","span",null,{"className":"token operator","children":"=="}]," id ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token class-name","children":"Binding"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token keyword","children":"get"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}]," step",["$","span",null,{"className":"token punctuation","children":"."}],"kind ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":","}]," ",["$","span",null,{"className":"token keyword","children":"set"}],["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"self"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"updateStep"}],["$","span",null,{"className":"token punctuation","children":"("}],"step",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token class-name","children":"Step"}],["$","span",null,{"className":"token punctuation","children":"("}],"id",["$","span",null,{"className":"token punctuation","children":":"}]," step",["$","span",null,{"className":"token punctuation","children":"."}],"id",["$","span",null,{"className":"token punctuation","children":","}]," name",["$","span",null,{"className":"token punctuation","children":":"}]," step",["$","span",null,{"className":"token punctuation","children":"."}],"name",["$","span",null,{"className":"token punctuation","children":","}]," kind",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token short-argument","children":"$$0"}]," ",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}]," ",["$","span",null,{"className":"token keyword","children":"else"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"return"}]," ",["$","span",null,{"className":"token class-name","children":"Binding"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"constant"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":"."}],"textEntry",["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n\n ",["$","span",null,{"className":"token keyword","children":"func"}]," ",["$","span",null,{"className":"token function-definition function","children":"save"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"let"}]," savePanel ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token class-name","children":"NSSavePanel"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n savePanel",["$","span",null,{"className":"token punctuation","children":"."}],"allowedContentTypes ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token punctuation","children":"["}],["$","span",null,{"className":"token punctuation","children":"."}],"json",["$","span",null,{"className":"token punctuation","children":"]"}],"\n savePanel",["$","span",null,{"className":"token punctuation","children":"."}],"canCreateDirectories ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token boolean","children":"true"}],"\n savePanel",["$","span",null,{"className":"token punctuation","children":"."}],"isExtensionHidden ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token boolean","children":"false"}],"\n savePanel",["$","span",null,{"className":"token punctuation","children":"."}],"title ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Save steps\""}]}],"\n savePanel",["$","span",null,{"className":"token punctuation","children":"."}],"message ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Choose where to save your steps\""}]}],"\n savePanel",["$","span",null,{"className":"token punctuation","children":"."}],"nameFieldLabel ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token string-literal","children":["$","span",null,{"className":"token string","children":"\"Fle name:\""}]}],"\n\n ",["$","span",null,{"className":"token keyword","children":"let"}]," response ",["$","span",null,{"className":"token operator","children":"="}]," savePanel",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"runModal"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token keyword","children":"if"}]," response ",["$","span",null,{"className":"token operator","children":"=="}]," ",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token constant","children":"OK"}]," ",["$","span",null,{"className":"token punctuation","children":"{"}],"\n ",["$","span",null,{"className":"token keyword","children":"let"}]," stringToSave ",["$","span",null,{"className":"token operator","children":"="}]," ",["$","span",null,{"className":"token class-name","children":"String"}],["$","span",null,{"className":"token punctuation","children":"("}],"data",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token keyword","children":"try"}],["$","span",null,{"className":"token operator","children":"!"}]," ",["$","span",null,{"className":"token class-name","children":"JSONEncoder"}],["$","span",null,{"className":"token punctuation","children":"("}],["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"encode"}],["$","span",null,{"className":"token punctuation","children":"("}],"steps",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token punctuation","children":","}]," encoding",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"utf8",["$","span",null,{"className":"token punctuation","children":")"}],["$","span",null,{"className":"token operator","children":"!"}],"\n ",["$","span",null,{"className":"token keyword","children":"try"}],["$","span",null,{"className":"token operator","children":"!"}]," stringToSave",["$","span",null,{"className":"token punctuation","children":"."}],["$","span",null,{"className":"token function","children":"write"}],["$","span",null,{"className":"token punctuation","children":"("}],"to",["$","span",null,{"className":"token punctuation","children":":"}]," savePanel",["$","span",null,{"className":"token punctuation","children":"."}],"url",["$","span",null,{"className":"token operator","children":"!"}],["$","span",null,{"className":"token punctuation","children":","}]," atomically",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token boolean","children":"true"}],["$","span",null,{"className":"token punctuation","children":","}]," encoding",["$","span",null,{"className":"token punctuation","children":":"}]," ",["$","span",null,{"className":"token punctuation","children":"."}],"utf8",["$","span",null,{"className":"token punctuation","children":")"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n ",["$","span",null,{"className":"token punctuation","children":"}"}],"\n",["$","span",null,{"className":"token punctuation","children":"}"}],"\n"]}]}]]}]]}]}]}]}]}]}]}]],null],null]},["$","$L2",null,{"parallelRouterKey":"children","segmentPath":["children","blog","children","swiftui-for-small-internal-desktop-app-tools","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined","styles":null}],null]},["$","$L2",null,{"parallelRouterKey":"children","segmentPath":["children","blog","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined","styles":null}],null]},[["$","html",null,{"lang":"en","className":"h-full antialiased","suppressHydrationWarning":true,"children":["$","body",null,{"className":"flex h-full bg-zinc-200 dark:bg-black","children":["$","$L4",null,{"children":["$","div",null,{"className":"flex w-full","children":[["$","div",null,{"className":"fixed inset-0 flex justify-center sm:px-8","children":["$","div",null,{"className":"flex w-full max-w-7xl lg:px-8","children":["$","div",null,{"className":"w-full bg-white ring-1 ring-zinc-100 dark:bg-zinc-900 dark:ring-zinc-300/20"}]}]}],["$","div",null,{"className":"relative flex w-full flex-col","children":[["$","$L5",null,{}],["$","main",null,{"className":"flex-auto","children":["$","$L2",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":["$","div",null,{"className":"sm:px-8 flex h-full items-center pt-16 sm:pt-32","children":["$","div",null,{"className":"mx-auto w-full max-w-7xl lg:px-8","children":["$","div",null,{"className":"relative px-4 sm:px-8 lg:px-12","children":["$","div",null,{"className":"mx-auto max-w-2xl lg:max-w-5xl","children":["$","div",null,{"className":"flex flex-col items-center","children":[["$","p",null,{"className":"text-base font-semibold text-zinc-400 dark:text-zinc-500","children":"404"}],["$","h1",null,{"className":"mt-4 text-4xl font-bold tracking-tight text-rose-800 sm:text-5xl dark:text-rose-100","children":"Page not found"}],["$","p",null,{"className":"mt-4 text-base text-zinc-600 dark:text-zinc-400","children":"Sorry, we couldn’t find the page you’re looking for."}],["$","p",null,{"className":"mt-4 text-base text-zinc-600 dark:text-zinc-400","children":["You may want to try"," ",["$","a",null,{"href":"https://archive.amimetic.co.uk","className":"font-semibold text-rose-600 hover:text-rose-500","children":"the old version of this website"}]," ","as not everything was included here."]}],["$","$L6",null,{"className":"inline-flex items-center gap-2 justify-center rounded-md py-2 px-3 text-sm outline-offset-2 transition active:transition-none bg-zinc-50 font-medium text-zinc-900 hover:bg-zinc-100 active:bg-zinc-100 active:text-zinc-900/60 dark:bg-zinc-800/50 dark:text-zinc-300 dark:hover:bg-zinc-800 dark:hover:text-zinc-50 dark:active:bg-zinc-800/50 dark:active:text-zinc-50/70 mt-4","href":"/","children":"Go back home"}]]}]}]}]}]}],"notFoundStyles":[],"styles":null}]}],["$","footer",null,{"className":"mt-32 flex-none","children":["$","div",null,{"className":"sm:px-8","children":["$","div",null,{"className":"mx-auto w-full max-w-7xl lg:px-8","children":["$","div",null,{"className":"border-t border-zinc-100 pb-16 pt-10 dark:border-zinc-700/40","children":["$","div",null,{"className":"relative px-4 sm:px-8 lg:px-12","children":["$","div",null,{"className":"mx-auto max-w-2xl lg:max-w-5xl","children":["$","div",null,{"className":"flex flex-col items-center justify-between gap-6 sm:flex-row","children":[["$","div",null,{"className":"flex flex-wrap justify-center gap-x-6 gap-y-1 text-sm font-medium text-zinc-800 dark:text-zinc-200","children":[["$","$L6",null,{"href":"/about","className":"transition hover:text-sky-500 dark:hover:text-sky-400","children":"About"}],["$","$L6",null,{"href":"/blog","className":"transition hover:text-sky-500 dark:hover:text-sky-400","children":"Writing"}],["$","$L6",null,{"href":"/projects","className":"transition hover:text-sky-500 dark:hover:text-sky-400","children":"Projects"}]]}],["$","p",null,{"className":"text-sm text-zinc-400 dark:text-zinc-500","children":["© ",2024," James Porter"]}]]}]}]}]}]}]}]}]]}]]}]}]}]}],null],null],[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/3dda7107ffc2265a.css","precedence":"next","crossOrigin":"$undefined"}]],"$L7"]]]] 7:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"SwiftUI for Mini Desktop Apps: A Tutorial - James Porter"}],["$","meta","3",{"name":"description","content":"Projects and thoughts from James Porter"}]] 1:null