diff --git a/README.md b/README.md deleted file mode 100644 index 70d8a9ed4..000000000 --- a/README.md +++ /dev/null @@ -1,97 +0,0 @@ - -[![Xcode][xcode-shield]][xcode-url] -[![Swift][swift-shield]][swift-url] -[![Contributors][contributors-shield]][contributors-url] -[![Forks][forks-shield]][forks-url] -[![Stargazers][stars-shield]][stars-url] -[![Issues][issues-shield]][issues-url] -[![MIT License][license-shield]][license-url] - - -
-

- - Logo - - -

Make It So - Again!

- -

- This is the source code for Make It So, a sample app that demonstrates how to use Firebase in a SwiftUI app that runs on all (most) of Apple's platforms. -
- Follow along on Twitter as I code the app » -
-
- Report Bug - · - Request Feature -

-

- -# Getting started - -This app requires a Firebase project, which you can create at no cost using the [Firebase Console](https://console.firebase.google.com). Here are the steps. For a more detailed description of how to add Firebase to an iOS project, refer to the [official Firebase docs for iOS and Apple's other platforms](https://firebase.google.com/docs/ios/setup). - -1. Clone the repo -1. Create a Firebase project -2. Create a Cloud Firestore database in the new Firebase project ([link](https://console.firebase.google.com/project/_/firestore/)) -2. Enable Anonymous Authentication ([link](https://console.firebase.google.com/project/_/authentication/providers)) -1. Register the iOS app in the Firebase project -1. Download the `GoogleService-Info.plist` file to the `code/frontend/Configuration/Firebase/Development` folder -1. Open `MakeItSo.xcodeproj` in Xcode -1. Select the `MakeItSo (iOS) DEV` target -1. Run the app - -# About the project - - - -## License - -See [LICENSE](LICENSE) - - -## Disclaimer - -This is not an official Google product. - - -## Contact -Peter Friese - [@peterfriese](https://twitter.com/peterfriese) - -Project Link: [https://github.com/peterfriese/MakeItSo](https://github.com/peterfriese/MakeItSo) - - - -## Acknowledgements - -The application icon is based on [Check](https://thenounproject.com/term/check/1905028/) by [Robert Won](https://thenounproject.com/robertwon/) from the [Noun Project](https://thenounproject.com/) - - - -[xcode-shield]: https://img.shields.io/badge/xcode-v13.3.1-blue -[xcode-url]: https://developer.apple.com/xcode/ - -[swift-shield]: https://img.shields.io/badge/swift-v5.5-%23fe4b2d -[swift-url]: https://swift.org/ - -[contributors-shield]: https://img.shields.io/github/contributors/peterfriese/MakeItSo.svg?style=flat-square -[contributors-url]: https://github.com/peterfriese/MakeItSo/graphs/contributors - -[forks-shield]: https://img.shields.io/github/forks/peterfriese/MakeItSo.svg?style=flat-square -[forks-url]: https://github.com/peterfriese/MakeItSo/network/members - -[stars-shield]: https://img.shields.io/github/stars/peterfriese/MakeItSo.svg?style=flat-square -[stars-url]: https://github.com/peterfriese/MakeItSo/stargazers - -[issues-shield]: https://img.shields.io/github/issues/peterfriese/MakeItSo.svg?style=flat-square -[issues-url]: https://github.com/peterfriese/MakeItSo/issues - -[license-shield]: https://img.shields.io/github/license/peterfriese/MakeItSo.svg?style=flat-square -[license-url]: https://github.com/peterfriese/MakeItSo/blob/master/LICENSE - -[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=flat-square&logo=linkedin&colorB=555 -[linkedin-url]: https://linkedin.com/in/peterfriese -[product-screenshot]: assets/screenshot.png -[product-demo]: assets/demo.gif -[product-screenshot]: assets/screenshot.png "Screenshot of Make It So, a replication of the iOS Reminders app" diff --git a/assets/hero/MakeItSo-Hero.key b/assets/hero/MakeItSo-Hero.key deleted file mode 100755 index e2fe3c925..000000000 Binary files a/assets/hero/MakeItSo-Hero.key and /dev/null differ diff --git a/assets/hero/MakeItSo-Hero.png b/assets/hero/MakeItSo-Hero.png deleted file mode 100644 index d4232d135..000000000 Binary files a/assets/hero/MakeItSo-Hero.png and /dev/null differ diff --git a/assets/hero/MakeItSo-Hero.rotato b/assets/hero/MakeItSo-Hero.rotato deleted file mode 100644 index daddd66f8..000000000 Binary files a/assets/hero/MakeItSo-Hero.rotato and /dev/null differ diff --git a/assets/hero/repo-hero.png b/assets/hero/repo-hero.png deleted file mode 100644 index 980f5c942..000000000 Binary files a/assets/hero/repo-hero.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/Contents.json b/assets/logo/AppIcon.appiconset/Contents.json deleted file mode 100644 index 34717a9f8..000000000 --- a/assets/logo/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,176 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "Bakery" - }, - "images" : [ - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x", - "filename" : "notification40.png" - }, - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x", - "filename" : "notification60.png" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x", - "filename" : "settings58.png" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x", - "filename" : "settings87.png" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x", - "filename" : "spotlight80.png" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x", - "filename" : "spotlight120.png" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x", - "filename" : "iphone120.png" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x", - "filename" : "iphone180.png" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "1x", - "filename" : "ipadNotification20.png" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "2x", - "filename" : "ipadNotification40.png" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x", - "filename" : "ipadSettings29.png" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x", - "filename" : "ipadSettings58.png" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x", - "filename" : "ipadSpotlight40.png" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x", - "filename" : "ipadSpotlight80.png" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x", - "filename" : "ipad76.png" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x", - "filename" : "ipad152.png" - }, - { - "idiom" : "ipad", - "size" : "83.5x83.5", - "scale" : "2x", - "filename" : "ipadPro167.png" - }, - { - "idiom" : "ios-marketing", - "size" : "1024x1024", - "scale" : "1x", - "filename" : "appstore1024.png" - }, - { - "idiom" : "mac", - "size" : "16x16", - "scale" : "1x", - "filename" : "mac16.png" - }, - { - "idiom" : "mac", - "size" : "16x16", - "scale" : "2x", - "filename" : "mac32.png" - }, - { - "idiom" : "mac", - "size" : "32x32", - "scale" : "1x", - "filename" : "mac32.png" - }, - { - "idiom" : "mac", - "size" : "32x32", - "scale" : "2x", - "filename" : "mac64.png" - }, - { - "idiom" : "mac", - "size" : "128x128", - "scale" : "1x", - "filename" : "mac128.png" - }, - { - "idiom" : "mac", - "size" : "128x128", - "scale" : "2x", - "filename" : "mac256.png" - }, - { - "idiom" : "mac", - "size" : "256x256", - "scale" : "1x", - "filename" : "mac256.png" - }, - { - "idiom" : "mac", - "size" : "256x256", - "scale" : "2x", - "filename" : "mac512.png" - }, - { - "idiom" : "mac", - "size" : "512x512", - "scale" : "1x", - "filename" : "mac512.png" - }, - { - "idiom" : "mac", - "size" : "512x512", - "scale" : "2x", - "filename" : "mac1024.png" - } - ] -} diff --git a/assets/logo/AppIcon.appiconset/appstore1024.png b/assets/logo/AppIcon.appiconset/appstore1024.png deleted file mode 100644 index 3136e5b29..000000000 Binary files a/assets/logo/AppIcon.appiconset/appstore1024.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/ipad152.png b/assets/logo/AppIcon.appiconset/ipad152.png deleted file mode 100644 index 6fb4ff12c..000000000 Binary files a/assets/logo/AppIcon.appiconset/ipad152.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/ipad76.png b/assets/logo/AppIcon.appiconset/ipad76.png deleted file mode 100644 index 44020028e..000000000 Binary files a/assets/logo/AppIcon.appiconset/ipad76.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/ipadNotification20.png b/assets/logo/AppIcon.appiconset/ipadNotification20.png deleted file mode 100644 index 301c87f22..000000000 Binary files a/assets/logo/AppIcon.appiconset/ipadNotification20.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/ipadNotification40.png b/assets/logo/AppIcon.appiconset/ipadNotification40.png deleted file mode 100644 index 3b5552c07..000000000 Binary files a/assets/logo/AppIcon.appiconset/ipadNotification40.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/ipadPro167.png b/assets/logo/AppIcon.appiconset/ipadPro167.png deleted file mode 100644 index 0eeae1465..000000000 Binary files a/assets/logo/AppIcon.appiconset/ipadPro167.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/ipadSettings29.png b/assets/logo/AppIcon.appiconset/ipadSettings29.png deleted file mode 100644 index da2e88574..000000000 Binary files a/assets/logo/AppIcon.appiconset/ipadSettings29.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/ipadSettings58.png b/assets/logo/AppIcon.appiconset/ipadSettings58.png deleted file mode 100644 index ecf358a4f..000000000 Binary files a/assets/logo/AppIcon.appiconset/ipadSettings58.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/ipadSpotlight40.png b/assets/logo/AppIcon.appiconset/ipadSpotlight40.png deleted file mode 100644 index 3b5552c07..000000000 Binary files a/assets/logo/AppIcon.appiconset/ipadSpotlight40.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/ipadSpotlight80.png b/assets/logo/AppIcon.appiconset/ipadSpotlight80.png deleted file mode 100644 index 370101d7b..000000000 Binary files a/assets/logo/AppIcon.appiconset/ipadSpotlight80.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/iphone120.png b/assets/logo/AppIcon.appiconset/iphone120.png deleted file mode 100644 index 61980089b..000000000 Binary files a/assets/logo/AppIcon.appiconset/iphone120.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/iphone180.png b/assets/logo/AppIcon.appiconset/iphone180.png deleted file mode 100644 index 07632ad76..000000000 Binary files a/assets/logo/AppIcon.appiconset/iphone180.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/mac1024.png b/assets/logo/AppIcon.appiconset/mac1024.png deleted file mode 100644 index a5ca57a37..000000000 Binary files a/assets/logo/AppIcon.appiconset/mac1024.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/mac128.png b/assets/logo/AppIcon.appiconset/mac128.png deleted file mode 100644 index 087e5375e..000000000 Binary files a/assets/logo/AppIcon.appiconset/mac128.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/mac16.png b/assets/logo/AppIcon.appiconset/mac16.png deleted file mode 100644 index 1f07c15d6..000000000 Binary files a/assets/logo/AppIcon.appiconset/mac16.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/mac256.png b/assets/logo/AppIcon.appiconset/mac256.png deleted file mode 100644 index 01d0bc100..000000000 Binary files a/assets/logo/AppIcon.appiconset/mac256.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/mac32.png b/assets/logo/AppIcon.appiconset/mac32.png deleted file mode 100644 index 84dd32c1d..000000000 Binary files a/assets/logo/AppIcon.appiconset/mac32.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/mac512.png b/assets/logo/AppIcon.appiconset/mac512.png deleted file mode 100644 index cf4bbc46c..000000000 Binary files a/assets/logo/AppIcon.appiconset/mac512.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/mac64.png b/assets/logo/AppIcon.appiconset/mac64.png deleted file mode 100644 index 1a201c6b8..000000000 Binary files a/assets/logo/AppIcon.appiconset/mac64.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/notification40.png b/assets/logo/AppIcon.appiconset/notification40.png deleted file mode 100644 index 3b5552c07..000000000 Binary files a/assets/logo/AppIcon.appiconset/notification40.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/notification60.png b/assets/logo/AppIcon.appiconset/notification60.png deleted file mode 100644 index 6d30f63d9..000000000 Binary files a/assets/logo/AppIcon.appiconset/notification60.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/settings58.png b/assets/logo/AppIcon.appiconset/settings58.png deleted file mode 100644 index ecf358a4f..000000000 Binary files a/assets/logo/AppIcon.appiconset/settings58.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/settings87.png b/assets/logo/AppIcon.appiconset/settings87.png deleted file mode 100644 index 3cba1f2ef..000000000 Binary files a/assets/logo/AppIcon.appiconset/settings87.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/spotlight120.png b/assets/logo/AppIcon.appiconset/spotlight120.png deleted file mode 100644 index 61980089b..000000000 Binary files a/assets/logo/AppIcon.appiconset/spotlight120.png and /dev/null differ diff --git a/assets/logo/AppIcon.appiconset/spotlight80.png b/assets/logo/AppIcon.appiconset/spotlight80.png deleted file mode 100644 index 370101d7b..000000000 Binary files a/assets/logo/AppIcon.appiconset/spotlight80.png and /dev/null differ diff --git a/assets/logo/MakeItSo.png b/assets/logo/MakeItSo.png deleted file mode 100644 index 5cb7d7d18..000000000 Binary files a/assets/logo/MakeItSo.png and /dev/null differ diff --git a/assets/logo/check-square.png b/assets/logo/check-square.png deleted file mode 100644 index b71c4100b..000000000 Binary files a/assets/logo/check-square.png and /dev/null differ diff --git a/assets/logo/check-square.psd b/assets/logo/check-square.psd deleted file mode 100644 index 8e0703d48..000000000 Binary files a/assets/logo/check-square.psd and /dev/null differ diff --git a/assets/repocard/MakeItSo-repocard-smaller.png b/assets/repocard/MakeItSo-repocard-smaller.png deleted file mode 100644 index 0f0061f40..000000000 Binary files a/assets/repocard/MakeItSo-repocard-smaller.png and /dev/null differ diff --git a/assets/repocard/MakeItSo-repocard-smaller2.png b/assets/repocard/MakeItSo-repocard-smaller2.png deleted file mode 100644 index 79ac96bb1..000000000 Binary files a/assets/repocard/MakeItSo-repocard-smaller2.png and /dev/null differ diff --git a/assets/repocard/MakeItSo-repocard.png b/assets/repocard/MakeItSo-repocard.png deleted file mode 100644 index 837b6e616..000000000 Binary files a/assets/repocard/MakeItSo-repocard.png and /dev/null differ diff --git a/code/backend/.gitignore b/code/backend/.gitignore deleted file mode 100644 index f62685251..000000000 --- a/code/backend/.gitignore +++ /dev/null @@ -1,65 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -firebase-debug.log* - -# Firebase cache -.firebase/ - -# Firebase config - -# Uncomment this if you'd like others to create their own Firebase project. -# For a team working on the same Firebase project(s), it is recommended to leave -# it commented so all members can deploy to the same project(s) in .firebaserc. -# .firebaserc - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env diff --git a/code/frontend/MakeItSo/Configuration/Firebase/Development/.gitkeep b/code/frontend/MakeItSo/Configuration/Firebase/Development/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/code/frontend/MakeItSo/Configuration/Firebase/Production/.gitkeep b/code/frontend/MakeItSo/Configuration/Firebase/Production/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/code/frontend/MakeItSo/MakeItSo.docc/MakeItSo.md b/code/frontend/MakeItSo/MakeItSo.docc/MakeItSo.md new file mode 100644 index 000000000..7264ce4cf --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/MakeItSo.md @@ -0,0 +1,13 @@ +# ``MakeItSo`` + +Summary + +## Overview + +Text + +## Topics + +### Group + +- ``Symbol`` diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.cmproj/bookmarks.plist b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.cmproj/bookmarks.plist new file mode 100644 index 000000000..0c67376eb --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.cmproj/bookmarks.plist @@ -0,0 +1,5 @@ + + + + + diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.cmproj/docPrefs b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.cmproj/docPrefs new file mode 100644 index 000000000..2592531e1 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.cmproj/docPrefs @@ -0,0 +1,39 @@ + + + + + DocPrefHorizontalScrollBarValue + 0 + DocPrefIsAssetPanelOpen + 1 + DocPrefIsCanvasRulersEnabled + 0 + DocPrefIsCaptionEditorOpen + 0 + DocPrefIsPropertiesOpen + 1 + DocPrefIsTocOpen + 0 + DocPrefMainSplitterValue + 1057.00000000000000000000 + DocPrefPlayheadTime + 11195520000 + DocPrefPreviewAutoFit + 1 + DocPrefPreviewScaleValue + 0.40991379310344827624 + DocPrefTrackHeaderWidth + 80.00000000000000000000 + DocPrefTrackHeights + + 54 + 54 + + DocPrefWindowSizePos + 0 0 3840 2135 0 0 3840 2135 + DocPrefZoomValue + 1.95010395010394987914 + SaveAsStandaloneProject + 1 + + diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.cmproj/project.tscproj b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.cmproj/project.tscproj new file mode 100644 index 000000000..48619fa10 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.cmproj/project.tscproj @@ -0,0 +1,1016 @@ +{ + "title" : "", + "description" : "", + "author" : "", + "targetLoudness" : -18.0, + "shouldApplyLoudnessNormalization" : true, + "videoFormatFrameRate" : 30, + "audioFormatSampleRate" : 44100, + "allowSubFrameEditing" : false, + "width" : 1158.0, + "height" : 2320.0, + "version" : "6.0", + "editRate" : 705600000, + "authoringClientName" : { + "name" : "Camtasia", + "platform" : "Mac", + "version" : "2022.6.1" + }, + "sourceBin" : [ + { + "id" : 1, + "src" : "./recordings/1678193905.388172/Rec 3-7-2023 9.trec", + "rect" : [0, 0, 1158, 2320], + "lastMod" : "20230307T125224", + "loudnessNormalization" : true, + "sourceTracks" : [ + { + "range" : [0, 19246], + "type" : 0, + "editRate" : 600, + "trackRect" : [0, 0, 1158, 2320], + "sampleRate" : "149957/5000", + "bitDepth" : 24, + "numChannels" : 0, + "integratedLUFS" : 100.0, + "peakLevel" : -1.0, + "metaData" : "Rec 3-7-2023 9.trec;2b7b6a05-7a1f-11e2-83d0-0017f200be7f;2b7b6a06-7a1f-11e2-83d0-0017f200be7f;2b7b6a07-7a1f-11e2-83d0-0017f200be7f;2b7b6a08-7a1f-11e2-83d0-0017f200be7f;2b7b6a0a-7a1f-11e2-83d0-0017f200be7f;2b7b6af0-7a1f-11e2-83d0-0017f200be7f;2b7b6af1-7a1f-11e2-83d0-0017f200be7f;2b7b6af2-7a1f-11e2-83d0-0017f200be7f;2b7b6af3-7a1f-11e2-83d0-0017f200be7f;2b7b6af5-7a1f-11e2-83d0-0017f200be7f;2b7b6af6-7a1f-11e2-83d0-0017f200be7f;2b7b6af7-7a1f-11e2-83d0-0017f200be7f;2b7b6af8-7a1f-11e2-83d0-0017f200be7f;2b7b6af9-7a1f-11e2-83d0-0017f200be7f;2b7b6afa-7a1f-11e2-83d0-0017f200be7f;2b7b6afb-7a1f-11e2-83d0-0017f200be7f;2b7b6afc-7a1f-11e2-83d0-0017f200be7f;" + } + ], + "metadata" : { + "timeAdded" : "20230307T125224.715327" + } + }, + { + "id" : 2, + "src" : "./recordings/1678193905.388338/Rec 3-7-2023 11.trec", + "rect" : [0, 0, 1158, 2320], + "lastMod" : "20230307T125356", + "loudnessNormalization" : true, + "sourceTracks" : [ + { + "range" : [0, 17210], + "type" : 0, + "editRate" : 600, + "trackRect" : [0, 0, 1158, 2320], + "sampleRate" : "299831/10000", + "bitDepth" : 24, + "numChannels" : 0, + "integratedLUFS" : 100.0, + "peakLevel" : -1.0, + "metaData" : "Rec 3-7-2023 11.trec;2b7b6a05-7a1f-11e2-83d0-0017f200be7f;2b7b6a06-7a1f-11e2-83d0-0017f200be7f;2b7b6a07-7a1f-11e2-83d0-0017f200be7f;2b7b6a08-7a1f-11e2-83d0-0017f200be7f;2b7b6a0a-7a1f-11e2-83d0-0017f200be7f;2b7b6af0-7a1f-11e2-83d0-0017f200be7f;2b7b6af1-7a1f-11e2-83d0-0017f200be7f;2b7b6af2-7a1f-11e2-83d0-0017f200be7f;2b7b6af3-7a1f-11e2-83d0-0017f200be7f;2b7b6af5-7a1f-11e2-83d0-0017f200be7f;2b7b6af6-7a1f-11e2-83d0-0017f200be7f;2b7b6af7-7a1f-11e2-83d0-0017f200be7f;2b7b6af8-7a1f-11e2-83d0-0017f200be7f;2b7b6af9-7a1f-11e2-83d0-0017f200be7f;2b7b6afa-7a1f-11e2-83d0-0017f200be7f;2b7b6afb-7a1f-11e2-83d0-0017f200be7f;2b7b6afc-7a1f-11e2-83d0-0017f200be7f;" + } + ], + "metadata" : { + "timeAdded" : "20230307T125356.483125" + } + } + ], + "timeline" : { + "id" : 3, + "sceneTrack" : { + "scenes" : [ + { + "csml" : { + "tracks" : [ + { + "trackIndex" : 0, + "medias" : [ + { + "id" : 4, + "_type" : "ScreenVMFile", + "src" : 1, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 9" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 235200000, + "cursorLocation" : { + "ignoreSource" : true, + "edits" : [ + { + "time" : 0, + "value" : [ -588, 610, 0] }, + { + "time" : 564480000, + "value" : [ -712.042, 487.083, 0], + "interp" : { "bezier" : [ [ -612.808, 585.417, 0], [ -687.233, 511.667, 0]] } + }, + { + "time" : 1105440000, + "value" : [ -712.042, 487.083, 0] }, + { + "time" : 1176000000, + "value" : [ -711.913, 537.261, 0], + "interp" : { "bezier" : [ [ -720.696, 482.003, 0], [ -711.939, 527.225, 0]] } + }, + { + "time" : 1693440000, + "value" : [ -711.913, 537.261, 0] }, + { + "time" : 1740480000, + "value" : [ -699.806, 590.389, 0], + "interp" : { "bezier" : [ [ -710.631, 548.083, 0], [ -702.227, 579.763, 0]] } + }, + { + "time" : 2563680000, + "value" : [ -699.806, 590.389, 0] }, + { + "time" : 3010560000, + "value" : [ -728.109, 1119.09, 0], + "interp" : { "bezier" : [ [ -702.752, 696.239, 0], [ -722.449, 1013.35, 0]] } + }, + { + "time" : 9008160000, + "value" : [ -728.109, 1119.09, 0] }, + { + "time" : 9807840000, + "value" : [ -721.065, 375.478, 0], + "interp" : { "bezier" : [ [ -742.751, 971.083, 0], [ -722.474, 524.201, 0]] } + }, + { + "time" : 10866240000, + "value" : [ -721.065, 375.478, 0] }, + { + "time" : 11266080000, + "value" : [ -723.072, 1104.64, 0], + "interp" : { "bezier" : [ [ -673.049, 237.776, 0], [ -722.671, 958.812, 0]] } + }, + { + "time" : 18063360000, + "value" : [ -723.072, 1104.64, 0] }, + { + "time" : 18298560000, + "value" : [ -449, 785, 0], + "interp" : { "bezier" : [ [ -676.473, 1174.79, 0], [ -485.779, 860.755, 0]] } + }, + { + "time" : 18627840000, + "value" : [ -370.2, 377.817, 0], + "interp" : { "bezier" : [ [ -419.491, 707.479, 0], [ -385.96, 459.253, 0]] } + }, + { + "time" : 20015520000, + "value" : [ -370.2, 377.817, 0] }, + { + "time" : 20297760000, + "value" : [ -491, 651, 0], + "interp" : { "bezier" : [ [ -388.067, 320.811, 0], [ -443.891, 614.263, 0]] } + }, + { + "time" : 22626240000, + "value" : [ -700, 635, 0], + "interp" : { "bezier" : [ [ -529.264, 668.128, 0], [ -658.2, 638.2, 0]] } + } + ] + } + }, + "effects" : [ + + ], + "start" : 0, + "duration" : 3974880000, + "mediaStart" : 0, + "mediaDuration" : 3974880000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : false, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 5, + "_type" : "ScreenVMFile", + "src" : 1, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 9" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 235200000 + }, + "effects" : [ + + ], + "start" : 3974880000, + "duration" : 2022720000, + "mediaStart" : 3974880000, + "mediaDuration" : 4962720000, + "scalar" : "86/211", + "metadata" : { + "clipSpeedAttribute" : true, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 6, + "_type" : "ScreenVMFile", + "src" : 1, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 9" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 235200000 + }, + "effects" : [ + + ], + "start" : 5997600000, + "duration" : 4163040000, + "mediaStart" : 8937600000, + "mediaDuration" : 4163040000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : false, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 7, + "_type" : "ScreenVMFile", + "src" : 1, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 9" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 235200000 + }, + "effects" : [ + + ], + "start" : 10160640000, + "duration" : 2422560000, + "mediaStart" : 13100640000, + "mediaDuration" : 5056800000, + "scalar" : "103/215", + "metadata" : { + "clipSpeedAttribute" : true, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 8, + "_type" : "ScreenVMFile", + "src" : 1, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 9" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 235200000 + }, + "effects" : [ + + ], + "start" : 12583200000, + "duration" : 3904320000, + "mediaStart" : 18157440000, + "mediaDuration" : 3904320000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : true, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + } + ] + }, + { + "trackIndex" : 1, + "medias" : [ + { + "id" : 9, + "_type" : "ScreenVMFile", + "src" : 2, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 11" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 0 + }, + "effects" : [ + + ], + "start" : 16769760000, + "duration" : 4515840000, + "mediaStart" : 0, + "mediaDuration" : 4515840000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : false, + "default-scale" : "1", + "effectApplied" : "none" + }, + "animationTracks" : { + + } + }, + { + "id" : 10, + "_type" : "ScreenVMFile", + "src" : 2, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 11" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 0 + }, + "effects" : [ + + ], + "start" : 21285600000, + "duration" : 2163840000, + "mediaStart" : 4515840000, + "mediaDuration" : 4421760000, + "scalar" : "23/47", + "metadata" : { + "clipSpeedAttribute" : true, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 11, + "_type" : "ScreenVMFile", + "src" : 2, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 11" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 0 + }, + "effects" : [ + + ], + "start" : 23449440000, + "duration" : 3645600000, + "mediaStart" : 8937600000, + "mediaDuration" : 3645600000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : false, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 12, + "_type" : "ScreenVMFile", + "src" : 2, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 11" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 0 + }, + "effects" : [ + + ], + "start" : 27095040000, + "duration" : 2069760000, + "mediaStart" : 12583200000, + "mediaDuration" : 3575040000, + "scalar" : "11/19", + "metadata" : { + "clipSpeedAttribute" : true, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 13, + "_type" : "ScreenVMFile", + "src" : 2, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 11" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 0 + }, + "effects" : [ + + ], + "start" : 29164800000, + "duration" : 2869440000, + "mediaStart" : 16158240000, + "mediaDuration" : 2869440000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : false, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + } + ] + } ] + } + } + ] + }, + "trackAttributes" : [ + { + "ident" : "", + "audioMuted" : false, + "videoHidden" : false, + "magnetic" : false, + "matte" : 0, + "solo" : false, + "metadata" : { + "IsLocked" : "False", + "trackHeight" : "54" + } + }, + { + "ident" : "", + "audioMuted" : false, + "videoHidden" : false, + "magnetic" : false, + "matte" : 0, + "solo" : false, + "metadata" : { + "IsLocked" : "False", + "trackHeight" : "54" + } + } + ], + "captionAttributes" : { + "enabled" : true, + "fontName" : "Arial", + "fontSize" : 32, + "backgroundColor" : [ 0, 0, 0, 204], + "foregroundColor" : [ 255, 255, 255, 255], + "lang" : "en", + "alignment" : 0, + "defaultFontSize" : true, + "opacity" : 0.5, + "backgroundEnabled" : true, + "backgroundOnlyAroundText" : true + }, + "gain" : 1.0, + "legacyAttenuateAudioMix" : false, + "backgroundColor" : [ 0, 0, 0, 255], + "metadata" : { + "RecordingHeight" : "2320", + "RecordingWidth" : "1158" + } + }, + "metadata" : { + "ProjectThumbnail" : "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", + "RulerGuidesX" : [], + "RulerGuidesY" : [], + "RulerShowing" : false, + "activeThemeId" : "e59eeb42-ccf0-4a36-bdf9-e630fdab686d", + "audiateSessionId" : "", + "firstMedia" : true, + "hasNotifiedAboutHFRMedia" : false, + "projectDuration" : "00:45" + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.cmproj/recordings/1678193905.388172/Rec 3-7-2023 9.trec b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.cmproj/recordings/1678193905.388172/Rec 3-7-2023 9.trec new file mode 100644 index 000000000..b15ab8582 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.cmproj/recordings/1678193905.388172/Rec 3-7-2023 9.trec differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.cmproj/recordings/1678193905.388338/Rec 3-7-2023 11.trec b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.cmproj/recordings/1678193905.388338/Rec 3-7-2023 11.trec new file mode 100644 index 000000000..f6949cd19 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.cmproj/recordings/1678193905.388338/Rec 3-7-2023 11.trec differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.mp4 b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.mp4 new file mode 100644 index 000000000..9f3ac5183 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale.mp4 differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale~dark.mp4 b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale~dark.mp4 new file mode 100644 index 000000000..49d8047f2 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-07-finale~dark.mp4 differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-intro-1@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-intro-1@2x.png new file mode 100644 index 000000000..75c2a3c00 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-intro-1@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-intro-white@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-intro-white@2x.png new file mode 100644 index 000000000..c03361099 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-intro-white@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-intro.key b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-intro.key new file mode 100755 index 000000000..b3c67d3e9 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-intro.key differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-intro@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-intro@2x.png new file mode 100644 index 000000000..6cc54903f Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-intro@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-new-swift-file@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-new-swift-file@2x.png new file mode 100644 index 000000000..f273f89d1 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-new-swift-file@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-new-swift-file~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-new-swift-file~dark@2x.png new file mode 100644 index 000000000..f91e12f89 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-new-swift-file~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-new-swiftui-file@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-new-swiftui-file@2x.png new file mode 100644 index 000000000..a8ac1ecfc Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-new-swiftui-file@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-new-swiftui-file~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-new-swiftui-file~dark@2x.png new file mode 100644 index 000000000..650bc4ba3 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-new-swiftui-file~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-02@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-02@2x.png new file mode 100644 index 000000000..897a289a6 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-02@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-03@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-03@2x.png new file mode 100644 index 000000000..38cd15ac2 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-03@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-04@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-04@2x.png new file mode 100644 index 000000000..b3118856e Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-04@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-06@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-06@2x.png new file mode 100644 index 000000000..78c34e541 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-06@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-06~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-06~dark@2x.png new file mode 100644 index 000000000..8528dfebf Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-06~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-07@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-07@2x.png new file mode 100644 index 000000000..c004430cc Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-07@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-08@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-08@2x.png new file mode 100644 index 000000000..b010e01c0 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-02-contentview-08@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-01@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-01@2x.png new file mode 100644 index 000000000..b010e01c0 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-01@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-03@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-03@2x.png new file mode 100644 index 000000000..b019765bf Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-03@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.cmproj/bookmarks.plist b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.cmproj/bookmarks.plist new file mode 100644 index 000000000..0c67376eb --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.cmproj/bookmarks.plist @@ -0,0 +1,5 @@ + + + + + diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.cmproj/docPrefs b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.cmproj/docPrefs new file mode 100644 index 000000000..7d0ef05be --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.cmproj/docPrefs @@ -0,0 +1,39 @@ + + + + + DocPrefHorizontalScrollBarValue + 0 + DocPrefIsAssetPanelOpen + 1 + DocPrefIsCanvasRulersEnabled + 0 + DocPrefIsCaptionEditorOpen + 0 + DocPrefIsPropertiesOpen + 1 + DocPrefIsTocOpen + 0 + DocPrefMainSplitterValue + 1585.00000000000000000000 + DocPrefPlayheadTime + 4680480000 + DocPrefPreviewAutoFit + 0 + DocPrefPreviewScaleValue + 0.93774999999999997247 + DocPrefTrackHeaderWidth + 80.00000000000000000000 + DocPrefTrackHeights + + 54 + 54 + + DocPrefWindowSizePos + 120 72 3055 2005 0 0 3840 2135 + DocPrefZoomValue + 5.09782608695652328379 + SaveAsStandaloneProject + 1 + + diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.cmproj/project.tscproj b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.cmproj/project.tscproj new file mode 100644 index 000000000..8ac5f05d0 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.cmproj/project.tscproj @@ -0,0 +1,451 @@ +{ + "title" : "", + "description" : "", + "author" : "", + "targetLoudness" : -18.0, + "shouldApplyLoudnessNormalization" : true, + "videoFormatFrameRate" : 30, + "audioFormatSampleRate" : 44100, + "allowSubFrameEditing" : false, + "width" : 1158.0, + "height" : 2320.0, + "version" : "6.0", + "editRate" : 705600000, + "authoringClientName" : { + "name" : "Camtasia", + "platform" : "Mac", + "version" : "2022.6.1" + }, + "sourceBin" : [ + { + "id" : 1, + "src" : "./recordings/1677757965.641490/Rec 3-2-2023 2.trec", + "rect" : [0, 0, 1158, 2320], + "lastMod" : "20230302T114228", + "loudnessNormalization" : true, + "sourceTracks" : [ + { + "range" : [0, 7376], + "type" : 0, + "editRate" : 600, + "trackRect" : [0, 0, 1158, 2320], + "sampleRate" : "149679/5000", + "bitDepth" : 24, + "numChannels" : 0, + "integratedLUFS" : 100.0, + "peakLevel" : -1.0, + "metaData" : "Rec 3-2-2023 2.trec;2b7b6a05-7a1f-11e2-83d0-0017f200be7f;2b7b6a06-7a1f-11e2-83d0-0017f200be7f;2b7b6a07-7a1f-11e2-83d0-0017f200be7f;2b7b6a08-7a1f-11e2-83d0-0017f200be7f;2b7b6a0a-7a1f-11e2-83d0-0017f200be7f;2b7b6af0-7a1f-11e2-83d0-0017f200be7f;2b7b6af1-7a1f-11e2-83d0-0017f200be7f;2b7b6af2-7a1f-11e2-83d0-0017f200be7f;2b7b6af3-7a1f-11e2-83d0-0017f200be7f;2b7b6af5-7a1f-11e2-83d0-0017f200be7f;2b7b6af6-7a1f-11e2-83d0-0017f200be7f;2b7b6af7-7a1f-11e2-83d0-0017f200be7f;2b7b6af8-7a1f-11e2-83d0-0017f200be7f;2b7b6af9-7a1f-11e2-83d0-0017f200be7f;2b7b6afa-7a1f-11e2-83d0-0017f200be7f;2b7b6afb-7a1f-11e2-83d0-0017f200be7f;2b7b6afc-7a1f-11e2-83d0-0017f200be7f;" + } + ], + "metadata" : { + "timeAdded" : "20230302T114228.621774" + } + }, + { + "id" : 2, + "src" : "./recordings/1677758116.355885/Rec 3-2-2023 3.trec", + "rect" : [0, 0, 1158, 2320], + "lastMod" : "20230302T115316", + "loudnessNormalization" : true, + "sourceTracks" : [ + { + "range" : [0, 6056], + "type" : 0, + "editRate" : 600, + "trackRect" : [0, 0, 1158, 2320], + "sampleRate" : "18701/625", + "bitDepth" : 24, + "numChannels" : 0, + "integratedLUFS" : 100.0, + "peakLevel" : -1.0, + "metaData" : "Rec 3-2-2023 3.trec;2b7b6a05-7a1f-11e2-83d0-0017f200be7f;2b7b6a06-7a1f-11e2-83d0-0017f200be7f;2b7b6a07-7a1f-11e2-83d0-0017f200be7f;2b7b6a08-7a1f-11e2-83d0-0017f200be7f;2b7b6a0a-7a1f-11e2-83d0-0017f200be7f;2b7b6af0-7a1f-11e2-83d0-0017f200be7f;2b7b6af1-7a1f-11e2-83d0-0017f200be7f;2b7b6af2-7a1f-11e2-83d0-0017f200be7f;2b7b6af3-7a1f-11e2-83d0-0017f200be7f;2b7b6af5-7a1f-11e2-83d0-0017f200be7f;2b7b6af6-7a1f-11e2-83d0-0017f200be7f;2b7b6af7-7a1f-11e2-83d0-0017f200be7f;2b7b6af8-7a1f-11e2-83d0-0017f200be7f;2b7b6af9-7a1f-11e2-83d0-0017f200be7f;2b7b6afa-7a1f-11e2-83d0-0017f200be7f;2b7b6afb-7a1f-11e2-83d0-0017f200be7f;2b7b6afc-7a1f-11e2-83d0-0017f200be7f;" + } + ], + "metadata" : { + "timeAdded" : "20230302T115316.622974" + } + } + ], + "timeline" : { + "id" : 3, + "sceneTrack" : { + "scenes" : [ + { + "csml" : { + "tracks" : [ + { + "trackIndex" : 0, + "medias" : [ + { + "id" : 4, + "_type" : "ScreenVMFile", + "src" : 1, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-2-2023 2" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 235200000 + }, + "effects" : [ + { + "effectName" : "LeftClickRings", + "bypassed" : false, + "category" : "categoryCursorEffects", + "parameters" : { + "clickDuration" : { + "type" : "double", + "defaultValue" : 0.5, + "interp" : "linr", + "uiHints" : { + "userInterfaceType" : 0, + "unitType" : 0 + } + }, + "postClickPercent" : 100.0, + "color-red" : { + "type" : "double", + "defaultValue" : 0.137254901960784, + "interp" : "linr", + "uiHints" : { + "userInterfaceType" : 0, + "unitType" : 0 + } + }, + "color-green" : { + "type" : "double", + "defaultValue" : 0.156862745098039, + "interp" : "linr", + "uiHints" : { + "userInterfaceType" : 0, + "unitType" : 0 + } + }, + "color-blue" : { + "type" : "double", + "defaultValue" : 0.184313725490196, + "interp" : "linr", + "uiHints" : { + "userInterfaceType" : 0, + "unitType" : 0 + } + }, + "color-alpha" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr", + "uiHints" : { + "userInterfaceType" : 0, + "unitType" : 0 + } + }, + "radius" : { + "type" : "double", + "defaultValue" : 50.0415625, + "interp" : "linr", + "uiHints" : { + "userInterfaceType" : 0, + "unitType" : 0 + } + }, + "scale" : { + "type" : "double", + "defaultValue" : 0.5, + "interp" : "linr", + "uiHints" : { + "userInterfaceType" : 0, + "unitType" : 0 + } + } + } + } + ], + "start" : 0, + "duration" : 4421760000, + "mediaStart" : 0, + "mediaDuration" : 8655360000, + "scalar" : "47/92", + "metadata" : { + "clipSpeedAttribute" : true, + "default-LeftClickRings-clickDuration" : "1.25", + "default-LeftClickRings-color" : "(255,0,0,255)", + "default-LeftClickRings-postClickPercent" : "100", + "default-LeftClickRings-radius" : "50", + "default-LeftClickRings-scale" : "0.5", + "default-scale" : "1", + "effectApplied" : "LeftClickRings", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + } + ] + }, + { + "trackIndex" : 1, + "medias" : [ + { + "id" : 5, + "_type" : "ScreenVMFile", + "src" : 2, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-2-2023 3" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 0 + }, + "effects" : [ + { + "effectName" : "LeftClickRings", + "bypassed" : false, + "category" : "categoryCursorEffects", + "parameters" : { + "clickDuration" : { + "type" : "double", + "defaultValue" : 0.5, + "interp" : "linr", + "uiHints" : { + "userInterfaceType" : 0, + "unitType" : 0 + } + }, + "postClickPercent" : 100.0, + "color-red" : { + "type" : "double", + "defaultValue" : 0.137254901960784, + "interp" : "linr", + "uiHints" : { + "userInterfaceType" : 0, + "unitType" : 0 + } + }, + "color-green" : { + "type" : "double", + "defaultValue" : 0.156862745098039, + "interp" : "linr", + "uiHints" : { + "userInterfaceType" : 0, + "unitType" : 0 + } + }, + "color-blue" : { + "type" : "double", + "defaultValue" : 0.184313725490196, + "interp" : "linr", + "uiHints" : { + "userInterfaceType" : 0, + "unitType" : 0 + } + }, + "color-alpha" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr", + "uiHints" : { + "userInterfaceType" : 0, + "unitType" : 0 + } + }, + "radius" : { + "type" : "double", + "defaultValue" : 50.0415625, + "interp" : "linr", + "uiHints" : { + "userInterfaceType" : 0, + "unitType" : 0 + } + }, + "scale" : { + "type" : "double", + "defaultValue" : 0.5, + "interp" : "linr", + "uiHints" : { + "userInterfaceType" : 0, + "unitType" : 0 + } + } + } + } + ], + "start" : 4562880000, + "duration" : 4421760000, + "mediaStart" : 0, + "mediaDuration" : 7103040000, + "scalar" : "94/151", + "metadata" : { + "clipSpeedAttribute" : true, + "default-scale" : "1", + "effectApplied" : "Pasted Effects", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + } + ] + } ] + } + } + ] + }, + "trackAttributes" : [ + { + "ident" : "Dark", + "audioMuted" : false, + "videoHidden" : false, + "magnetic" : false, + "matte" : 0, + "solo" : false, + "metadata" : { + "IsLocked" : "False", + "trackHeight" : "54" + } + }, + { + "ident" : "Light", + "audioMuted" : false, + "videoHidden" : false, + "magnetic" : false, + "matte" : 0, + "solo" : false, + "metadata" : { + "IsLocked" : "False", + "trackHeight" : "54" + } + } + ], + "captionAttributes" : { + "enabled" : true, + "fontName" : "Arial", + "fontSize" : 32, + "backgroundColor" : [ 0, 0, 0, 204], + "foregroundColor" : [ 255, 255, 255, 255], + "lang" : "en", + "alignment" : 0, + "defaultFontSize" : true, + "opacity" : 0.5, + "backgroundEnabled" : true, + "backgroundOnlyAroundText" : true + }, + "gain" : 1.0, + "legacyAttenuateAudioMix" : false, + "backgroundColor" : [ 0, 0, 0, 255], + "metadata" : { + "RecordingHeight" : "2320", + "RecordingWidth" : "1158" + } + }, + "metadata" : { + "ProjectThumbnail" : "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", + "RulerGuidesX" : [], + "RulerGuidesY" : [], + "RulerShowing" : false, + "activeThemeId" : "e59eeb42-ccf0-4a36-bdf9-e630fdab686d", + "audiateSessionId" : "", + "firstMedia" : true, + "hasNotifiedAboutHFRMedia" : false, + "projectDuration" : "00:12" + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.cmproj/recordings/1677757965.641490/Rec 3-2-2023 2.trec b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.cmproj/recordings/1677757965.641490/Rec 3-2-2023 2.trec new file mode 100644 index 000000000..752ca770c Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.cmproj/recordings/1677757965.641490/Rec 3-2-2023 2.trec differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.cmproj/recordings/1677758116.355885/Rec 3-2-2023 3.trec b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.cmproj/recordings/1677758116.355885/Rec 3-2-2023 3.trec new file mode 100644 index 000000000..87968ad07 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.cmproj/recordings/1677758116.355885/Rec 3-2-2023 3.trec differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.mp4 b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.mp4 new file mode 100644 index 000000000..8955b9682 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05.mp4 differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05~dark.mp4 b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05~dark.mp4 new file mode 100644 index 000000000..edd0c8233 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-03-contentview-05~dark.mp4 differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-04-addreminderview-01@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-04-addreminderview-01@2x.png new file mode 100644 index 000000000..57eb8aaf0 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-04-addreminderview-01@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-04-addreminderview-04@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-04-addreminderview-04@2x.png new file mode 100644 index 000000000..d183298d5 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-04-addreminderview-04@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-04-addreminderview-05@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-04-addreminderview-05@2x.png new file mode 100644 index 000000000..c147a0f26 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-04-addreminderview-05@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-04-addreminderview-06@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-04-addreminderview-06@2x.png new file mode 100644 index 000000000..8728f2490 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-04-addreminderview-06@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-04@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-04@2x.png new file mode 100644 index 000000000..183bccc8f Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-04@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.cmproj/bookmarks.plist b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.cmproj/bookmarks.plist new file mode 100644 index 000000000..0c67376eb --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.cmproj/bookmarks.plist @@ -0,0 +1,5 @@ + + + + + diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.cmproj/docPrefs b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.cmproj/docPrefs new file mode 100644 index 000000000..55af4b3a8 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.cmproj/docPrefs @@ -0,0 +1,39 @@ + + + + + DocPrefHorizontalScrollBarValue + 0 + DocPrefIsAssetPanelOpen + 1 + DocPrefIsCanvasRulersEnabled + 0 + DocPrefIsCaptionEditorOpen + 0 + DocPrefIsPropertiesOpen + 1 + DocPrefIsTocOpen + 0 + DocPrefMainSplitterValue + 1689.00000000000000000000 + DocPrefPlayheadTime + 15076320000 + DocPrefPreviewAutoFit + 0 + DocPrefPreviewScaleValue + 0.77499999999999991118 + DocPrefTrackHeaderWidth + 80.00000000000000000000 + DocPrefTrackHeights + + 54 + 54 + + DocPrefWindowSizePos + 0 0 3840 2135 0 0 3840 2135 + DocPrefZoomValue + 3.32035398230088540927 + SaveAsStandaloneProject + 1 + + diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.cmproj/project.tscproj b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.cmproj/project.tscproj new file mode 100644 index 000000000..f21d4c42d --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.cmproj/project.tscproj @@ -0,0 +1,1617 @@ +{ + "title" : "", + "description" : "", + "author" : "", + "targetLoudness" : -18.0, + "shouldApplyLoudnessNormalization" : true, + "videoFormatFrameRate" : 30, + "audioFormatSampleRate" : 44100, + "allowSubFrameEditing" : false, + "width" : 1158.0, + "height" : 2320.0, + "version" : "6.0", + "editRate" : 705600000, + "authoringClientName" : { + "name" : "Camtasia", + "platform" : "Mac", + "version" : "2022.6.1" + }, + "sourceBin" : [ + { + "id" : 1, + "src" : "./recordings/1678189865.121170/Rec 3-7-2023 2.trec", + "rect" : [0, 0, 1158, 2320], + "lastMod" : "20230307T114732", + "loudnessNormalization" : true, + "sourceTracks" : [ + { + "range" : [0, 11305], + "type" : 0, + "editRate" : 600, + "trackRect" : [0, 0, 1158, 2320], + "sampleRate" : "74969/2500", + "bitDepth" : 24, + "numChannels" : 0, + "integratedLUFS" : 100.0, + "peakLevel" : -1.0, + "metaData" : "Rec 3-7-2023 2.trec;2b7b6a05-7a1f-11e2-83d0-0017f200be7f;2b7b6a06-7a1f-11e2-83d0-0017f200be7f;2b7b6a07-7a1f-11e2-83d0-0017f200be7f;2b7b6a08-7a1f-11e2-83d0-0017f200be7f;2b7b6a0a-7a1f-11e2-83d0-0017f200be7f;2b7b6af0-7a1f-11e2-83d0-0017f200be7f;2b7b6af1-7a1f-11e2-83d0-0017f200be7f;2b7b6af2-7a1f-11e2-83d0-0017f200be7f;2b7b6af3-7a1f-11e2-83d0-0017f200be7f;2b7b6af5-7a1f-11e2-83d0-0017f200be7f;2b7b6af6-7a1f-11e2-83d0-0017f200be7f;2b7b6af7-7a1f-11e2-83d0-0017f200be7f;2b7b6af8-7a1f-11e2-83d0-0017f200be7f;2b7b6af9-7a1f-11e2-83d0-0017f200be7f;2b7b6afa-7a1f-11e2-83d0-0017f200be7f;2b7b6afb-7a1f-11e2-83d0-0017f200be7f;2b7b6afc-7a1f-11e2-83d0-0017f200be7f;" + } + ], + "metadata" : { + "timeAdded" : "20230307T114732.401485" + } + }, + { + "id" : 2, + "src" : "./recordings/1678190222.501826/Rec 3-7-2023 5.trec", + "rect" : [0, 0, 1158, 2320], + "lastMod" : "20230307T115448", + "loudnessNormalization" : true, + "sourceTracks" : [ + { + "range" : [0, 9617], + "type" : 0, + "editRate" : 600, + "trackRect" : [0, 0, 1158, 2320], + "sampleRate" : "11979/400", + "bitDepth" : 24, + "numChannels" : 0, + "integratedLUFS" : 100.0, + "peakLevel" : -1.0, + "metaData" : "Rec 3-7-2023 5.trec;2b7b6a05-7a1f-11e2-83d0-0017f200be7f;2b7b6a06-7a1f-11e2-83d0-0017f200be7f;2b7b6a07-7a1f-11e2-83d0-0017f200be7f;2b7b6a08-7a1f-11e2-83d0-0017f200be7f;2b7b6a0a-7a1f-11e2-83d0-0017f200be7f;2b7b6af0-7a1f-11e2-83d0-0017f200be7f;2b7b6af1-7a1f-11e2-83d0-0017f200be7f;2b7b6af2-7a1f-11e2-83d0-0017f200be7f;2b7b6af3-7a1f-11e2-83d0-0017f200be7f;2b7b6af5-7a1f-11e2-83d0-0017f200be7f;2b7b6af6-7a1f-11e2-83d0-0017f200be7f;2b7b6af7-7a1f-11e2-83d0-0017f200be7f;2b7b6af8-7a1f-11e2-83d0-0017f200be7f;2b7b6af9-7a1f-11e2-83d0-0017f200be7f;2b7b6afa-7a1f-11e2-83d0-0017f200be7f;2b7b6afb-7a1f-11e2-83d0-0017f200be7f;2b7b6afc-7a1f-11e2-83d0-0017f200be7f;" + } + ], + "metadata" : { + "timeAdded" : "20230307T115448.411178" + } + } + ], + "timeline" : { + "id" : 3, + "sceneTrack" : { + "scenes" : [ + { + "csml" : { + "tracks" : [ + { + "trackIndex" : 0, + "medias" : [ + { + "id" : 4, + "_type" : "ScreenVMFile", + "src" : 1, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 2" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 235200000 + }, + "effects" : [ + + ], + "start" : 0, + "duration" : 1622880000, + "mediaStart" : 0, + "mediaDuration" : 1622880000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : false, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 5, + "_type" : "ScreenVMFile", + "src" : 1, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 2" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 235200000 + }, + "effects" : [ + + ], + "start" : 1622880000, + "duration" : 493920000, + "mediaStart" : 1622880000, + "mediaDuration" : 1081920000, + "scalar" : "21/46", + "metadata" : { + "clipSpeedAttribute" : true, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 6, + "_type" : "ScreenVMFile", + "src" : 1, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 2" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 235200000 + }, + "effects" : [ + + ], + "start" : 2116800000, + "duration" : 2234400000, + "mediaStart" : 2704800000, + "mediaDuration" : 4915680000, + "scalar" : "5/11", + "metadata" : { + "clipSpeedAttribute" : true, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 7, + "_type" : "StitchedMedia", + "minMediaStart" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 2", + "gain" : 1.0, + "mixToMono" : false, + "loudnessNormalization" : true, + "sourceFileOffset" : 0 + }, + "parameters" : { + "sourceCrop0" : 0.0, + "sourceCrop1" : 0.0, + "sourceCrop2" : 0.0, + "sourceCrop3" : 0.0, + "geometryCrop0" : 0.0, + "geometryCrop1" : 0.0, + "geometryCrop2" : 0.0, + "geometryCrop3" : 0.0, + "cursorOpacity" : 1.0, + "cursorScale" : 2.25, + "smoothCursorAcrossEditDuration" : 235200000 + }, + "medias" : [ + { + "id" : 8, + "_type" : "ScreenVMFile", + "src" : 1, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 2" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 235200000, + "cursorLocation" : { + "ignoreSource" : true, + "edits" : [ + { + "time" : 7620480000, + "value" : [ -668, 470, 0] }, + { + "time" : 7785120000, + "value" : [ -451, 453, 0], + "interp" : { "bezier" : [ [ -624.6, 466.6, 0], [ -492.404, 466.446, 0]] } + }, + { + "time" : 8161440000, + "value" : [ -368.098, 372.608, 0], + "interp" : { "bezier" : [ [ -430.053, 443.272, 0], [ -384.678, 388.686, 0]] } + }, + { + "time" : 9337440000, + "value" : [ -368.098, 372.608, 0] }, + { + "time" : 9996000000, + "value" : [ -710.534, 634.384, 0], + "interp" : { "bezier" : [ [ -438.758, 421.991, 0], [ -642.047, 582.028, 0]] } + }, + { + "time" : 11689440000, + "value" : [ -710.534, 634.384, 0] }, + { + "time" : 11854080000, + "value" : [ -702, 663.972, 0], + "interp" : { "bezier" : [ [ -715.175, 638.433, 0], [ -703.707, 658.054, 0]] } + }, + { + "time" : 12677280000, + "value" : [ -702, 663.972, 0] }, + { + "time" : 13288800000, + "value" : [ -702, 664, 0], + "interp" : { "bezier" : [ [ -701.998, 663.978, 0], [ -702, 663.994, 0]] } + } + ] + } + }, + "effects" : [ + + ], + "start" : 0, + "duration" : 8843520000, + "mediaStart" : 0, + "mediaDuration" : 8843520000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : true, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 9, + "_type" : "ScreenVMFile", + "src" : 1, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 2" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 235200000, + "cursorLocation" : { + "ignoreSource" : true, + "edits" : [ + { + "time" : 7620480000, + "value" : [ -668, 470, 0] }, + { + "time" : 7785120000, + "value" : [ -451, 453, 0], + "interp" : { "bezier" : [ [ -624.6, 466.6, 0], [ -492.404, 466.446, 0]] } + }, + { + "time" : 8161440000, + "value" : [ -368.098, 372.608, 0], + "interp" : { "bezier" : [ [ -430.053, 443.272, 0], [ -384.678, 388.686, 0]] } + }, + { + "time" : 9337440000, + "value" : [ -368.098, 372.608, 0] }, + { + "time" : 9996000000, + "value" : [ -710.534, 634.384, 0], + "interp" : { "bezier" : [ [ -438.758, 421.991, 0], [ -642.047, 582.028, 0]] } + }, + { + "time" : 11689440000, + "value" : [ -710.534, 634.384, 0] }, + { + "time" : 11854080000, + "value" : [ -702, 663.972, 0], + "interp" : { "bezier" : [ [ -715.175, 638.433, 0], [ -703.707, 658.054, 0]] } + }, + { + "time" : 12677280000, + "value" : [ -702, 663.972, 0] }, + { + "time" : 13288800000, + "value" : [ -702, 664, 0], + "interp" : { "bezier" : [ [ -701.998, 663.978, 0], [ -702, 663.994, 0]] } + } + ] + } + }, + "effects" : [ + + ], + "start" : 8843520000, + "duration" : 917280000, + "mediaStart" : 9219840000, + "mediaDuration" : 917280000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : true, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 10, + "_type" : "ScreenVMFile", + "src" : 1, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 2" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 235200000, + "cursorLocation" : { + "ignoreSource" : true, + "edits" : [ + { + "time" : 7620480000, + "value" : [ -668, 470, 0] }, + { + "time" : 7785120000, + "value" : [ -451, 453, 0], + "interp" : { "bezier" : [ [ -624.6, 466.6, 0], [ -492.404, 466.446, 0]] } + }, + { + "time" : 8161440000, + "value" : [ -368.098, 372.608, 0], + "interp" : { "bezier" : [ [ -430.053, 443.272, 0], [ -384.678, 388.686, 0]] } + }, + { + "time" : 9337440000, + "value" : [ -368.098, 372.608, 0] }, + { + "time" : 9996000000, + "value" : [ -710.534, 634.384, 0], + "interp" : { "bezier" : [ [ -438.758, 421.991, 0], [ -642.047, 582.028, 0]] } + }, + { + "time" : 11689440000, + "value" : [ -710.534, 634.384, 0] }, + { + "time" : 11854080000, + "value" : [ -702, 663.972, 0], + "interp" : { "bezier" : [ [ -715.175, 638.433, 0], [ -703.707, 658.054, 0]] } + }, + { + "time" : 12677280000, + "value" : [ -702, 663.972, 0] }, + { + "time" : 13288800000, + "value" : [ -702, 664, 0], + "interp" : { "bezier" : [ [ -701.998, 663.978, 0], [ -702, 663.994, 0]] } + } + ] + } + }, + "effects" : [ + + ], + "start" : 9760800000, + "duration" : 329280000, + "mediaStart" : 10419360000, + "mediaDuration" : 329280000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : true, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 11, + "_type" : "ScreenVMFile", + "src" : 1, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 2" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 235200000, + "cursorLocation" : { + "ignoreSource" : true, + "edits" : [ + { + "time" : 7620480000, + "value" : [ -668, 470, 0] }, + { + "time" : 7785120000, + "value" : [ -451, 453, 0], + "interp" : { "bezier" : [ [ -624.6, 466.6, 0], [ -492.404, 466.446, 0]] } + }, + { + "time" : 8161440000, + "value" : [ -368.098, 372.608, 0], + "interp" : { "bezier" : [ [ -430.053, 443.272, 0], [ -384.678, 388.686, 0]] } + }, + { + "time" : 9337440000, + "value" : [ -368.098, 372.608, 0] }, + { + "time" : 9996000000, + "value" : [ -710.534, 634.384, 0], + "interp" : { "bezier" : [ [ -438.758, 421.991, 0], [ -642.047, 582.028, 0]] } + }, + { + "time" : 11689440000, + "value" : [ -710.534, 634.384, 0] }, + { + "time" : 11854080000, + "value" : [ -702, 663.972, 0], + "interp" : { "bezier" : [ [ -715.175, 638.433, 0], [ -703.707, 658.054, 0]] } + }, + { + "time" : 12677280000, + "value" : [ -702, 663.972, 0] }, + { + "time" : 13288800000, + "value" : [ -702, 664, 0], + "interp" : { "bezier" : [ [ -701.998, 663.978, 0], [ -702, 663.994, 0]] } + } + ] + } + }, + "effects" : [ + + ], + "start" : 10090080000, + "duration" : 1764000000, + "mediaStart" : 11524800000, + "mediaDuration" : 1764000000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : true, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + } + ], + "effects" : [ + + ], + "start" : 4351200000, + "duration" : 3245760000, + "mediaStart" : 7620480000, + "mediaDuration" : 3245760000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : true, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + } + ] + }, + { + "trackIndex" : 1, + "medias" : [ + { + "id" : 12, + "_type" : "ScreenVMFile", + "src" : 2, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 5" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 0, + "cursorLocation" : { + "ignoreSource" : true, + "edits" : [ + { + "time" : 0, + "value" : [ -691.357, 1080.43, 0] }, + { + "time" : 305760000, + "value" : [ -691.357, 1080.43, 0] }, + { + "time" : 423360000, + "value" : [ -721.6, 1109.4, 0], + "interp" : { "bezier" : [ [ -697.406, 1086.22, 0], [ -715.551, 1103.61, 0]] } + }, + { + "time" : 987840000, + "value" : [ -721.6, 1109.4, 0] }, + { + "time" : 1199520000, + "value" : [ -633, 584, 0], + "interp" : { "bezier" : [ [ -709.159, 1003.57, 0], [ -640.052, 690.33, 0]] } + }, + { + "time" : 1528800000, + "value" : [ -678.995, 467.005, 0], + "interp" : { "bezier" : [ [ -633.112, 558.858, 0], [ -669.796, 490.404, 0]] } + }, + { + "time" : 6515040000, + "value" : [ -678.995, 467.005, 0] }, + { + "time" : 7056000000, + "value" : [ -383.375, 372.521, 0], + "interp" : { "bezier" : [ [ -631.636, 426.882, 0], [ -442.499, 391.418, 0]] } + }, + { + "time" : 8161440000, + "value" : [ -383.375, 372.521, 0] }, + { + "time" : 8772960000, + "value" : [ -702.488, 637.186, 0], + "interp" : { "bezier" : [ [ -394.714, 454.659, 0], [ -638.666, 584.253, 0]] } + }, + { + "time" : 9760800000, + "value" : [ -702.488, 637.186, 0] }, + { + "time" : 11266080000, + "value" : [ -681, 679, 0], + "interp" : { "bezier" : [ [ -709.039, 643.931, 0], [ -685.298, 670.637, 0]] } + } + ] + } + }, + "effects" : [ + + ], + "start" : 7761600000, + "duration" : 1881600000, + "mediaStart" : 0, + "mediaDuration" : 1881600000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : false, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 13, + "_type" : "ScreenVMFile", + "src" : 2, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 5" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 0, + "cursorLocation" : { + "ignoreSource" : true, + "edits" : [ + { + "time" : 0, + "value" : [ -691.357, 1080.43, 0] }, + { + "time" : 305760000, + "value" : [ -691.357, 1080.43, 0] }, + { + "time" : 423360000, + "value" : [ -721.6, 1109.4, 0], + "interp" : { "bezier" : [ [ -697.406, 1086.22, 0], [ -715.551, 1103.61, 0]] } + }, + { + "time" : 987840000, + "value" : [ -721.6, 1109.4, 0] }, + { + "time" : 1199520000, + "value" : [ -633, 584, 0], + "interp" : { "bezier" : [ [ -709.159, 1003.57, 0], [ -640.052, 690.33, 0]] } + }, + { + "time" : 1528800000, + "value" : [ -678.995, 467.005, 0], + "interp" : { "bezier" : [ [ -633.112, 558.858, 0], [ -669.796, 490.404, 0]] } + }, + { + "time" : 6515040000, + "value" : [ -678.995, 467.005, 0] }, + { + "time" : 7056000000, + "value" : [ -383.375, 372.521, 0], + "interp" : { "bezier" : [ [ -631.636, 426.882, 0], [ -442.499, 391.418, 0]] } + }, + { + "time" : 8161440000, + "value" : [ -383.375, 372.521, 0] }, + { + "time" : 8772960000, + "value" : [ -702.488, 637.186, 0], + "interp" : { "bezier" : [ [ -394.714, 454.659, 0], [ -638.666, 584.253, 0]] } + }, + { + "time" : 9760800000, + "value" : [ -702.488, 637.186, 0] }, + { + "time" : 11266080000, + "value" : [ -681, 679, 0], + "interp" : { "bezier" : [ [ -709.039, 643.931, 0], [ -685.298, 670.637, 0]] } + } + ] + } + }, + "effects" : [ + + ], + "start" : 9643200000, + "duration" : 1834560000, + "mediaStart" : 1881600000, + "mediaDuration" : 4374720000, + "scalar" : "13/31", + "metadata" : { + "clipSpeedAttribute" : true, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 14, + "_type" : "StitchedMedia", + "minMediaStart" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 5", + "gain" : 1.0, + "mixToMono" : false, + "loudnessNormalization" : true, + "sourceFileOffset" : 0 + }, + "parameters" : { + "sourceCrop0" : 0.0, + "sourceCrop1" : 0.0, + "sourceCrop2" : 0.0, + "sourceCrop3" : 0.0, + "geometryCrop0" : 0.0, + "geometryCrop1" : 0.0, + "geometryCrop2" : 0.0, + "geometryCrop3" : 0.0, + "cursorOpacity" : 1.0, + "cursorScale" : 2.25, + "smoothCursorAcrossEditDuration" : 0 + }, + "medias" : [ + { + "id" : 15, + "_type" : "ScreenVMFile", + "src" : 2, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 5" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 0, + "cursorLocation" : { + "ignoreSource" : true, + "edits" : [ + { + "time" : 0, + "value" : [ -691.357, 1080.43, 0] }, + { + "time" : 305760000, + "value" : [ -691.357, 1080.43, 0] }, + { + "time" : 423360000, + "value" : [ -721.6, 1109.4, 0], + "interp" : { "bezier" : [ [ -697.406, 1086.22, 0], [ -715.551, 1103.61, 0]] } + }, + { + "time" : 987840000, + "value" : [ -721.6, 1109.4, 0] }, + { + "time" : 1199520000, + "value" : [ -633, 584, 0], + "interp" : { "bezier" : [ [ -709.159, 1003.57, 0], [ -640.052, 690.33, 0]] } + }, + { + "time" : 1528800000, + "value" : [ -678.995, 467.005, 0], + "interp" : { "bezier" : [ [ -633.112, 558.858, 0], [ -669.796, 490.404, 0]] } + }, + { + "time" : 6515040000, + "value" : [ -678.995, 467.005, 0] }, + { + "time" : 7056000000, + "value" : [ -383.375, 372.521, 0], + "interp" : { "bezier" : [ [ -631.636, 426.882, 0], [ -442.499, 391.418, 0]] } + }, + { + "time" : 8161440000, + "value" : [ -383.375, 372.521, 0] }, + { + "time" : 8772960000, + "value" : [ -702.488, 637.186, 0], + "interp" : { "bezier" : [ [ -394.714, 454.659, 0], [ -638.666, 584.253, 0]] } + }, + { + "time" : 9760800000, + "value" : [ -702.488, 637.186, 0] }, + { + "time" : 11266080000, + "value" : [ -681, 679, 0], + "interp" : { "bezier" : [ [ -709.039, 643.931, 0], [ -685.298, 670.637, 0]] } + } + ] + } + }, + "effects" : [ + + ], + "start" : 0, + "duration" : 7785120000, + "mediaStart" : 0, + "mediaDuration" : 7785120000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : false, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 16, + "_type" : "ScreenVMFile", + "src" : 2, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 5" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 0, + "cursorLocation" : { + "ignoreSource" : true, + "edits" : [ + { + "time" : 0, + "value" : [ -691.357, 1080.43, 0] }, + { + "time" : 305760000, + "value" : [ -691.357, 1080.43, 0] }, + { + "time" : 423360000, + "value" : [ -721.6, 1109.4, 0], + "interp" : { "bezier" : [ [ -697.406, 1086.22, 0], [ -715.551, 1103.61, 0]] } + }, + { + "time" : 987840000, + "value" : [ -721.6, 1109.4, 0] }, + { + "time" : 1199520000, + "value" : [ -633, 584, 0], + "interp" : { "bezier" : [ [ -709.159, 1003.57, 0], [ -640.052, 690.33, 0]] } + }, + { + "time" : 1528800000, + "value" : [ -678.995, 467.005, 0], + "interp" : { "bezier" : [ [ -633.112, 558.858, 0], [ -669.796, 490.404, 0]] } + }, + { + "time" : 6515040000, + "value" : [ -678.995, 467.005, 0] }, + { + "time" : 7056000000, + "value" : [ -383.375, 372.521, 0], + "interp" : { "bezier" : [ [ -631.636, 426.882, 0], [ -442.499, 391.418, 0]] } + }, + { + "time" : 8161440000, + "value" : [ -383.375, 372.521, 0] }, + { + "time" : 8772960000, + "value" : [ -702.488, 637.186, 0], + "interp" : { "bezier" : [ [ -394.714, 454.659, 0], [ -638.666, 584.253, 0]] } + }, + { + "time" : 9760800000, + "value" : [ -702.488, 637.186, 0] }, + { + "time" : 11266080000, + "value" : [ -681, 679, 0], + "interp" : { "bezier" : [ [ -709.039, 643.931, 0], [ -685.298, 670.637, 0]] } + } + ] + } + }, + "effects" : [ + + ], + "start" : 7785120000, + "duration" : 729120000, + "mediaStart" : 8137920000, + "mediaDuration" : 729120000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : false, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + }, + { + "id" : 17, + "_type" : "ScreenVMFile", + "src" : 2, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-7-2023 5" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 0, + "cursorLocation" : { + "ignoreSource" : true, + "edits" : [ + { + "time" : 0, + "value" : [ -691.357, 1080.43, 0] }, + { + "time" : 305760000, + "value" : [ -691.357, 1080.43, 0] }, + { + "time" : 423360000, + "value" : [ -721.6, 1109.4, 0], + "interp" : { "bezier" : [ [ -697.406, 1086.22, 0], [ -715.551, 1103.61, 0]] } + }, + { + "time" : 987840000, + "value" : [ -721.6, 1109.4, 0] }, + { + "time" : 1199520000, + "value" : [ -633, 584, 0], + "interp" : { "bezier" : [ [ -709.159, 1003.57, 0], [ -640.052, 690.33, 0]] } + }, + { + "time" : 1528800000, + "value" : [ -678.995, 467.005, 0], + "interp" : { "bezier" : [ [ -633.112, 558.858, 0], [ -669.796, 490.404, 0]] } + }, + { + "time" : 6515040000, + "value" : [ -678.995, 467.005, 0] }, + { + "time" : 7056000000, + "value" : [ -383.375, 372.521, 0], + "interp" : { "bezier" : [ [ -631.636, 426.882, 0], [ -442.499, 391.418, 0]] } + }, + { + "time" : 8161440000, + "value" : [ -383.375, 372.521, 0] }, + { + "time" : 8772960000, + "value" : [ -702.488, 637.186, 0], + "interp" : { "bezier" : [ [ -394.714, 454.659, 0], [ -638.666, 584.253, 0]] } + }, + { + "time" : 9760800000, + "value" : [ -702.488, 637.186, 0] }, + { + "time" : 11266080000, + "value" : [ -681, 679, 0], + "interp" : { "bezier" : [ [ -709.039, 643.931, 0], [ -685.298, 670.637, 0]] } + } + ] + } + }, + "effects" : [ + + ], + "start" : 8514240000, + "duration" : 2022720000, + "mediaStart" : 9266880000, + "mediaDuration" : 2022720000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : false, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + } + ], + "effects" : [ + + ], + "start" : 11477760000, + "duration" : 3669120000, + "mediaStart" : 6256320000, + "mediaDuration" : 3669120000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : false, + "default-scale" : "1", + "effectApplied" : "none", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + } + ] + } ] + } + } + ] + }, + "trackAttributes" : [ + { + "ident" : "", + "audioMuted" : false, + "videoHidden" : false, + "magnetic" : false, + "matte" : 0, + "solo" : false, + "metadata" : { + "IsLocked" : "False", + "trackHeight" : "54" + } + }, + { + "ident" : "", + "audioMuted" : false, + "videoHidden" : false, + "magnetic" : false, + "matte" : 0, + "solo" : false, + "metadata" : { + "IsLocked" : "False", + "trackHeight" : "54" + } + } + ], + "captionAttributes" : { + "enabled" : true, + "fontName" : "Arial", + "fontSize" : 32, + "backgroundColor" : [ 0, 0, 0, 204], + "foregroundColor" : [ 255, 255, 255, 255], + "lang" : "en", + "alignment" : 0, + "defaultFontSize" : true, + "opacity" : 0.5, + "backgroundEnabled" : true, + "backgroundOnlyAroundText" : true + }, + "gain" : 1.0, + "legacyAttenuateAudioMix" : false, + "backgroundColor" : [ 0, 0, 0, 255], + "metadata" : { + "RecordingHeight" : "2320", + "RecordingWidth" : "1158" + } + }, + "metadata" : { + "ProjectThumbnail" : "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", + "RulerGuidesX" : [], + "RulerGuidesY" : [], + "RulerShowing" : false, + "activeThemeId" : "e59eeb42-ccf0-4a36-bdf9-e630fdab686d", + "audiateSessionId" : "", + "firstMedia" : true, + "hasNotifiedAboutHFRMedia" : false, + "projectDuration" : "00:21" + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.cmproj/recordings/1678189865.121170/Rec 3-7-2023 2.trec b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.cmproj/recordings/1678189865.121170/Rec 3-7-2023 2.trec new file mode 100644 index 000000000..fb676dd24 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.cmproj/recordings/1678189865.121170/Rec 3-7-2023 2.trec differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.cmproj/recordings/1678190222.501826/Rec 3-7-2023 5.trec b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.cmproj/recordings/1678190222.501826/Rec 3-7-2023 5.trec new file mode 100644 index 000000000..85fc1fadd Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.cmproj/recordings/1678190222.501826/Rec 3-7-2023 5.trec differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.mp4 b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.mp4 new file mode 100644 index 000000000..58867509c Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05.mp4 differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05~dark.mp4 b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05~dark.mp4 new file mode 100644 index 000000000..78f2b4978 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-05-contentview-present-addreminder-05~dark.mp4 differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-06-addreminder-brushup-05@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-06-addreminder-brushup-05@2x.png new file mode 100644 index 000000000..2515fd954 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-06-addreminder-brushup-05@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-06-addreminder-brushup-06@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-06-addreminder-brushup-06@2x.png new file mode 100644 index 000000000..8f3768d9d Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-06-addreminder-brushup-06@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-06-addreminder-brushup-07@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-06-addreminder-brushup-07@2x.png new file mode 100644 index 000000000..beeb13f7d Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-reminder-06-addreminder-brushup-07@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-app-template@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-app-template@2x.png new file mode 100644 index 000000000..4148c4bd2 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-app-template@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-app-template~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-app-template~dark@2x.png new file mode 100644 index 000000000..e88329296 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-app-template~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-new-project@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-new-project@2x.png new file mode 100644 index 000000000..04f5a01ab Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-new-project@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-new-project~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-new-project~dark@2x.png new file mode 100644 index 000000000..2ff497253 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-new-project~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-project-name@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-project-name@2x.png new file mode 100644 index 000000000..ae92a4c53 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-project-name@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-project-name~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-project-name~dark@2x.png new file mode 100644 index 000000000..1c15f3036 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/building-todo-ui-xcode-project-name~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/make-it-so-intro.mov b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/make-it-so-intro.mov new file mode 100644 index 000000000..b8383e1d5 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/make-it-so-intro.mov differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.001@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.001@2x.png new file mode 100644 index 000000000..a6c07b4dc Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.001@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.001~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.001~dark@2x.png new file mode 100644 index 000000000..523a52465 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.001~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.002@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.002@2x.png new file mode 100644 index 000000000..33d573736 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.002@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.002~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.002~dark@2x.png new file mode 100644 index 000000000..cdb93a860 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.002~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.003.mp4 b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.003.mp4 new file mode 100644 index 000000000..04f548e19 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.003.mp4 differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.004.mp4 b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.004.mp4 new file mode 100644 index 000000000..396864118 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.004.mp4 differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.005-01.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.005-01.png new file mode 100644 index 000000000..13f19fcd3 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.005-01.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.005-02.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.005-02.png new file mode 100644 index 000000000..14254ef24 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.005-02.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.005.rotato b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.005.rotato new file mode 100644 index 000000000..818ff139b Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.005.rotato differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.005@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.005@2x.png new file mode 100644 index 000000000..e9addf18c Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.005@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.005~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.005~dark@2x.png new file mode 100644 index 000000000..c85b0e3c9 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.005~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.006@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.006@2x.png new file mode 100644 index 000000000..f9b9bb06f Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.006@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.006~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.006~dark@2x.png new file mode 100644 index 000000000..25195c398 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.006~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.007.mp4 b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.007.mp4 new file mode 100644 index 000000000..c2186acfc Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.007.mp4 differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/bookmarks.plist b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/bookmarks.plist new file mode 100644 index 000000000..0c67376eb --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/bookmarks.plist @@ -0,0 +1,5 @@ + + + + + diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/docPrefs b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/docPrefs new file mode 100644 index 000000000..03a70f9b0 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/docPrefs @@ -0,0 +1,40 @@ + + + + + DocPrefHorizontalScrollBarValue + 10 + DocPrefIsAssetPanelOpen + 1 + DocPrefIsCanvasRulersEnabled + 0 + DocPrefIsCaptionEditorOpen + 0 + DocPrefIsPropertiesOpen + 1 + DocPrefIsTocOpen + 0 + DocPrefMainSplitterValue + 1262.00000000000000000000 + DocPrefPlayheadTime + 15335040000 + DocPrefPreviewAutoFit + 0 + DocPrefPreviewScaleValue + 1.95130434782608697120 + DocPrefTrackHeaderWidth + 80.00000000000000000000 + DocPrefTrackHeights + + 54 + 54 + 54 + + DocPrefWindowSizePos + 17 310 3382 1558 0 0 3840 2135 + DocPrefZoomValue + 2.16551081450017024466 + SaveAsStandaloneProject + 1 + + diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/project.tscproj b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/project.tscproj new file mode 100644 index 000000000..07f4ddcd3 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/project.tscproj @@ -0,0 +1,482 @@ +{ + "title" : "", + "description" : "", + "author" : "", + "targetLoudness" : -18.0, + "shouldApplyLoudnessNormalization" : true, + "videoFormatFrameRate" : 30, + "audioFormatSampleRate" : 44100, + "allowSubFrameEditing" : false, + "width" : 1109.0, + "height" : 575.0, + "version" : "6.0", + "editRate" : 705600000, + "authoringClientName" : { + "name" : "Camtasia", + "platform" : "Mac", + "version" : "2022.6.1" + }, + "sourceBin" : [ + { + "id" : 1, + "src" : "./recordings/1678718535.225374/Rec 3-13-2023 1.trec", + "rect" : [0, 0, 1109, 575], + "lastMod" : "20230313T121244", + "loudnessNormalization" : true, + "sourceTracks" : [ + { + "range" : [0, 7353], + "type" : 0, + "editRate" : 600, + "trackRect" : [0, 0, 1109, 575], + "sampleRate" : "29947/1000", + "bitDepth" : 24, + "numChannels" : 0, + "integratedLUFS" : 100.0, + "peakLevel" : -1.0, + "metaData" : "Rec 3-13-2023 1.trec;2b7b6a05-7a1f-11e2-83d0-0017f200be7f;2b7b6a06-7a1f-11e2-83d0-0017f200be7f;2b7b6a07-7a1f-11e2-83d0-0017f200be7f;2b7b6a08-7a1f-11e2-83d0-0017f200be7f;2b7b6a0a-7a1f-11e2-83d0-0017f200be7f;2b7b6af0-7a1f-11e2-83d0-0017f200be7f;2b7b6af1-7a1f-11e2-83d0-0017f200be7f;2b7b6af2-7a1f-11e2-83d0-0017f200be7f;2b7b6af3-7a1f-11e2-83d0-0017f200be7f;2b7b6af5-7a1f-11e2-83d0-0017f200be7f;2b7b6af6-7a1f-11e2-83d0-0017f200be7f;2b7b6af7-7a1f-11e2-83d0-0017f200be7f;2b7b6af8-7a1f-11e2-83d0-0017f200be7f;2b7b6af9-7a1f-11e2-83d0-0017f200be7f;2b7b6afa-7a1f-11e2-83d0-0017f200be7f;2b7b6afb-7a1f-11e2-83d0-0017f200be7f;2b7b6afc-7a1f-11e2-83d0-0017f200be7f;" + } + ], + "metadata" : { + "timeAdded" : "20230313T121244.878197" + } + }, + { + "id" : 2, + "src" : "./recordings/1678718535.225542/Rec 3-13-2023 2.trec", + "rect" : [0, 0, 1114, 674], + "lastMod" : "20230313T143658", + "loudnessNormalization" : true, + "sourceTracks" : [ + { + "range" : [0, 3680], + "type" : 0, + "editRate" : 600, + "trackRect" : [0, 0, 1114, 674], + "sampleRate" : "149193/5000", + "bitDepth" : 24, + "numChannels" : 0, + "integratedLUFS" : 100.0, + "peakLevel" : -1.0, + "metaData" : "Rec 3-13-2023 2.trec;2b7b6a05-7a1f-11e2-83d0-0017f200be7f;2b7b6a06-7a1f-11e2-83d0-0017f200be7f;2b7b6a07-7a1f-11e2-83d0-0017f200be7f;2b7b6a08-7a1f-11e2-83d0-0017f200be7f;2b7b6a0a-7a1f-11e2-83d0-0017f200be7f;2b7b6af0-7a1f-11e2-83d0-0017f200be7f;2b7b6af1-7a1f-11e2-83d0-0017f200be7f;2b7b6af2-7a1f-11e2-83d0-0017f200be7f;2b7b6af3-7a1f-11e2-83d0-0017f200be7f;2b7b6af5-7a1f-11e2-83d0-0017f200be7f;2b7b6af6-7a1f-11e2-83d0-0017f200be7f;2b7b6af7-7a1f-11e2-83d0-0017f200be7f;2b7b6af8-7a1f-11e2-83d0-0017f200be7f;2b7b6af9-7a1f-11e2-83d0-0017f200be7f;2b7b6afa-7a1f-11e2-83d0-0017f200be7f;2b7b6afb-7a1f-11e2-83d0-0017f200be7f;2b7b6afc-7a1f-11e2-83d0-0017f200be7f;" + } + ], + "metadata" : { + "timeAdded" : "20230313T143658.619452" + } + }, + { + "id" : 3, + "src" : "./recordings/1678719995.362669/Rec 3-13-2023 4.trec", + "rect" : [0, 0, 1164, 552], + "lastMod" : "20230313T150511", + "loudnessNormalization" : true, + "sourceTracks" : [ + { + "range" : [0, 10062], + "type" : 0, + "editRate" : 600, + "trackRect" : [0, 0, 1164, 552], + "sampleRate" : "299939/10000", + "bitDepth" : 24, + "numChannels" : 0, + "integratedLUFS" : 100.0, + "peakLevel" : -1.0, + "metaData" : "Rec 3-13-2023 4.trec;2b7b6a05-7a1f-11e2-83d0-0017f200be7f;2b7b6a06-7a1f-11e2-83d0-0017f200be7f;2b7b6a07-7a1f-11e2-83d0-0017f200be7f;2b7b6a08-7a1f-11e2-83d0-0017f200be7f;2b7b6a0a-7a1f-11e2-83d0-0017f200be7f;2b7b6af0-7a1f-11e2-83d0-0017f200be7f;2b7b6af1-7a1f-11e2-83d0-0017f200be7f;2b7b6af2-7a1f-11e2-83d0-0017f200be7f;2b7b6af3-7a1f-11e2-83d0-0017f200be7f;2b7b6af5-7a1f-11e2-83d0-0017f200be7f;2b7b6af6-7a1f-11e2-83d0-0017f200be7f;2b7b6af7-7a1f-11e2-83d0-0017f200be7f;2b7b6af8-7a1f-11e2-83d0-0017f200be7f;2b7b6af9-7a1f-11e2-83d0-0017f200be7f;2b7b6afa-7a1f-11e2-83d0-0017f200be7f;2b7b6afb-7a1f-11e2-83d0-0017f200be7f;2b7b6afc-7a1f-11e2-83d0-0017f200be7f;" + } + ], + "metadata" : { + "timeAdded" : "20230313T150511.262208" + } + } + ], + "timeline" : { + "id" : 4, + "sceneTrack" : { + "scenes" : [ + { + "csml" : { + "tracks" : [ + { + "trackIndex" : 0, + "medias" : [ + { + "id" : 5, + "_type" : "ScreenVMFile", + "src" : 1, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-13-2023 1" + }, + "parameters" : { + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 235200000 + }, + "effects" : [ + { + "effectName" : "LeftClickRings", + "bypassed" : false, + "category" : "categoryCursorEffects", + "parameters" : { + "clickDuration" : 0.999140625, + "postClickPercent" : 100.0, + "color-red" : 0.137254901960784, + "color-green" : 0.156862745098039, + "color-blue" : 0.184313725490196, + "color-alpha" : 1.0, + "radius" : 50.0, + "scale" : 0.5 + } + } + ], + "start" : 0, + "duration" : 5644800000, + "mediaStart" : 0, + "mediaDuration" : 7244160000, + "scalar" : "60/77", + "metadata" : { + "clipSpeedAttribute" : true, + "default-LeftClickRings-clickDuration" : "1.25", + "default-LeftClickRings-color" : "(255,0,0,255)", + "default-scale" : "1", + "effectApplied" : "LeftClickRings", + "lockAspectRatio" : true + }, + "animationTracks" : { + + } + } + ] + }, + { + "trackIndex" : 1, + "medias" : [ + { + "id" : 6, + "_type" : "ScreenVMFile", + "src" : 2, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-13-2023 2" + }, + "parameters" : { + "translation1" : { + "type" : "double", + "defaultValue" : -47.9874326750448, + "interp" : "eioe" + }, + "scale0" : { + "type" : "double", + "defaultValue" : 0.995511669658887, + "interp" : "eioe" + }, + "scale1" : { + "type" : "double", + "defaultValue" : 0.995511669658887, + "interp" : "eioe" + }, + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 0 + }, + "effects" : [ + + ], + "start" : 5715360000, + "duration" : 2563680000, + "mediaStart" : 0, + "mediaDuration" : 2563680000, + "scalar" : 1, + "metadata" : { + "clipSpeedAttribute" : false, + "default-anchor0" : 0.0, + "default-anchor1" : 0.0, + "default-anchor2" : 0.0, + "default-height" : 575.0, + "default-rotation0" : 0.0, + "default-rotation1" : 0.0, + "default-rotation2" : 0.0, + "default-scale" : "0.853116", + "default-scale0" : 0.853115727002967, + "default-scale1" : 0.853115727002967, + "default-scale2" : 1.0, + "default-shear0" : 0.0, + "default-shear1" : 0.0, + "default-shear2" : 0.0, + "default-translation0" : 0.0, + "default-translation1" : 0.0, + "default-translation2" : 0.0, + "default-width" : 950.370919881306, + "effectApplied" : "none" + }, + "animationTracks" : { + + } + } + ] + }, + { + "trackIndex" : 2, + "medias" : [ + { + "id" : 7, + "_type" : "ScreenVMFile", + "src" : 3, + "trackNumber" : 0, + "attributes" : { + "ident" : "Rec 3-13-2023 4" + }, + "parameters" : { + "scale0" : { + "type" : "double", + "defaultValue" : 0.952749140893471, + "interp" : "eioe" + }, + "scale1" : { + "type" : "double", + "defaultValue" : 0.952749140893471, + "interp" : "eioe" + }, + "sourceCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "sourceCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop0" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop1" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop2" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "geometryCrop3" : { + "type" : "double", + "defaultValue" : 0.0, + "interp" : "eioe" + }, + "cursorScale" : { + "type" : "double", + "defaultValue" : 2.25, + "interp" : "linr" + }, + "cursorOpacity" : { + "type" : "double", + "defaultValue" : 1.0, + "interp" : "linr" + }, + "smoothCursorAcrossEditDuration" : 0 + }, + "effects" : [ + + ], + "start" : 8373120000, + "duration" : 7056000000, + "mediaStart" : 0, + "mediaDuration" : 11830560000, + "scalar" : "300/503", + "metadata" : { + "clipSpeedAttribute" : true, + "default-scale" : "0.952749", + "effectApplied" : "none" + }, + "animationTracks" : { + + } + } + ] + } ] + } + } + ] + }, + "trackAttributes" : [ + { + "ident" : "", + "audioMuted" : false, + "videoHidden" : false, + "magnetic" : false, + "matte" : 0, + "solo" : false, + "metadata" : { + "IsLocked" : "False", + "trackHeight" : "54" + } + }, + { + "ident" : "", + "audioMuted" : false, + "videoHidden" : false, + "magnetic" : false, + "matte" : 0, + "solo" : false, + "metadata" : { + "IsLocked" : "False", + "trackHeight" : "54" + } + }, + { + "ident" : "", + "audioMuted" : false, + "videoHidden" : false, + "magnetic" : false, + "matte" : 0, + "solo" : false, + "metadata" : { + "IsLocked" : "False", + "trackHeight" : "54" + } + } + ], + "captionAttributes" : { + "enabled" : true, + "fontName" : "Arial", + "fontSize" : 32, + "backgroundColor" : [ 0, 0, 0, 204], + "foregroundColor" : [ 255, 255, 255, 255], + "lang" : "en", + "alignment" : 0, + "defaultFontSize" : true, + "opacity" : 0.5, + "backgroundEnabled" : true, + "backgroundOnlyAroundText" : true + }, + "gain" : 1.0, + "legacyAttenuateAudioMix" : false, + "backgroundColor" : [ 0, 0, 0, 255], + "metadata" : { + "RecordingHeight" : "575", + "RecordingWidth" : "1109" + } + }, + "metadata" : { + "ProjectThumbnail" : "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ryMDbTclIAEJSEACEpCAws93QAISkIAEJCABCXSEgMKvIwNtNyUgAQlIQAISkIDCz3dAAhKQgAQkIAEJdISAwq8jA203JSABCUhAAhKQgMLPd0ACEpCABCQgAQl0hIDCryMDbTclIAEJSEACEpCAws93QAISkIAEJCABCXSEgMKvIwNtNyUgAQlIQAISkIDCz3dAAhKQgAQkIAEJdISAwq8jA203JSABCUhAAhKQgMLPd0ACEpCABCQgAQl0hIDCryMDbTclIAEJSEACEpCAws93QAISkIAEJCABCXSEgMKvIwNtNyUgAQlIQAISkIDCz3dAAhKQgAQkIAEJdISAwq8jA203JSABCUhAAhKQgMLPd0ACEpCABCQgAQl0hIDCryMDbTclIAEJSEACEpCAws93QAISkIAEJCABCXSEgMKvIwNtNyUgAQlIQAISkIDCz3dAAhKQgAQkIAEJdISAwq8jA203JSABCUhAAhKQgMLPd0ACEpCABCQgAQl0hIDCryMDbTclIAEJSEACEpCAws93QAISkIAEJCABCXSEgMKvIwNtNyUgAQlIQAISkIDCz3dAAhKQgAQkIAEJdISAwq8jA203JSABCUhAAhKQgMLPd0ACEpCABCQgAQl0hIDCryMDbTclIAEJSEACEpCAws93QAISkIAEJCABCXSEgMKvIwNtNyUgAQlIQAISkIDCz3dAAhKQgAQkIAEJdISAwq8jA203JSABCUhAAhKQgMLPd0ACEpCABCQgAQl0hMDs4uJiR7pqNyUgAQlIQAISkEC3CczOzMx2m4C9l4AEJCABCUhAAh0hMLtp08aOdNVuSkACEpCABCQggW4TmNq02bnebr8C9l4CEpCABCQgga4QmLr61a/hIr+ujLb9lIAEJCABCUig0wSmovcKv06/AnZeAhKQgAQkIIGuEJidm5vrSl/tpwQkIAEJSEACEug0AS1+nR5+Oy8BCUhAAhKQQJcIzE5Nof10EpCABCQgAQlIQAKTTkCL36SPsP2TgAQkIAEJSEACPQJ+ss1XQQISkIAEJCABCXSEgMKvIwNtNyUgAQlIQAISkIDCz3dAAhKQgAQkIAEJdISAwq8jA203JSABCUhAAhKQgMLPd0ACEpCABCQgAQl0hIDCryMDbTclIAEJSEACEpCAws93QAISkIAEJCABCXSEgMKvIwNtNyUgAQlIQAISkMD/B5RScHgmYtNLAAAAAElFTkSuQmCC", + "RulerGuidesX" : [], + "RulerGuidesY" : [], + "RulerShowing" : false, + "activeThemeId" : "e59eeb42-ccf0-4a36-bdf9-e630fdab686d", + "audiateSessionId" : "", + "firstMedia" : true, + "hasNotifiedAboutHFRMedia" : false, + "projectDuration" : "00:21" + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/recordings/1678718535.225374/Rec 3-13-2023 1.trec b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/recordings/1678718535.225374/Rec 3-13-2023 1.trec new file mode 100644 index 000000000..72de450a2 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/recordings/1678718535.225374/Rec 3-13-2023 1.trec differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/recordings/1678718535.225542/Rec 3-13-2023 2.trec b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/recordings/1678718535.225542/Rec 3-13-2023 2.trec new file mode 100644 index 000000000..8d2f64f5f Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/recordings/1678718535.225542/Rec 3-13-2023 2.trec differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/recordings/1678719995.362669/Rec 3-13-2023 4.trec b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/recordings/1678719995.362669/Rec 3-13-2023 4.trec new file mode 100644 index 000000000..8803001d3 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.cmproj/recordings/1678719995.362669/Rec 3-13-2023 4.trec differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.key b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.key new file mode 100755 index 000000000..f06686c66 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/artwork/sectionintros.key differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-01-01.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-01-01.swift new file mode 100644 index 000000000..fbf287572 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-01-01.swift @@ -0,0 +1,2 @@ +import Foundation + diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-01-02.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-01-02.swift new file mode 100644 index 000000000..ba25e3f10 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-01-02.swift @@ -0,0 +1,7 @@ +import Foundation + +struct Reminder { + var title: String + var isCompleted = false +} + diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-01-03.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-01-03.swift new file mode 100644 index 000000000..923f0428e --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-01-03.swift @@ -0,0 +1,15 @@ +import Foundation + +struct Reminder { + var title: String + var isCompleted = false +} + +extension Reminder { + static let samples = [ + Reminder(title: "Build sample app", isCompleted: true), + Reminder(title: "Create tutorial"), + Reminder(title: "???"), + Reminder(title: "PROFIT!"), + ] +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-01.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-01.swift new file mode 100644 index 000000000..b9818144b --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-01.swift @@ -0,0 +1,8 @@ +import SwiftUI + + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-02.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-02.swift new file mode 100644 index 000000000..2a045811a --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-02.swift @@ -0,0 +1,19 @@ +import SwiftUI + +struct ContentView: View { + var body: some View { + VStack { + Image(systemName: "globe") + .imageScale(.large) + .foregroundColor(.accentColor) + Text("Hello, world!") + } + .padding() + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-03.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-03.swift new file mode 100644 index 000000000..9f567ce77 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-03.swift @@ -0,0 +1,19 @@ +import SwiftUI + +struct ContentView: View { + var body: some View { + HStack { + Image(systemName: "globe") + .imageScale(.large) + .foregroundColor(.accentColor) + Text("Hello, world!") + } + .padding() + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-04.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-04.swift new file mode 100644 index 000000000..f80c78528 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-04.swift @@ -0,0 +1,19 @@ +import SwiftUI + +struct ContentView: View { + var body: some View { + HStack { + Image(systemName: "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + Text("Hello, world!") + } + .padding() + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-05.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-05.swift new file mode 100644 index 000000000..361af3b61 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-05.swift @@ -0,0 +1,22 @@ +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + var body: some View { + HStack { + Image(systemName: "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + Text("Hello, world!") + } + .padding() + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-06.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-06.swift new file mode 100644 index 000000000..bbab2787d --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-06.swift @@ -0,0 +1,22 @@ +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + var body: some View { + HStack { + Image(systemName: "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + Text("Hello, world!") + } + // .padding() <-- remove this line + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-07.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-07.swift new file mode 100644 index 000000000..a1cbdc4af --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-07.swift @@ -0,0 +1,23 @@ +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + var body: some View { + List(reminders) { reminder in + HStack { + Image(systemName: "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + Text("Hello, world!") + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-08.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-08.swift new file mode 100644 index 000000000..a1cbdc4af --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-08.swift @@ -0,0 +1,23 @@ +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + var body: some View { + List(reminders) { reminder in + HStack { + Image(systemName: "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + Text("Hello, world!") + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-09.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-09.swift new file mode 100644 index 000000000..98b762a34 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-contentview-09.swift @@ -0,0 +1,25 @@ +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + var body: some View { + List(reminders) { reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + Text(reminder.title) + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-reminder-01.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-reminder-01.swift new file mode 100644 index 000000000..923f0428e --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-reminder-01.swift @@ -0,0 +1,15 @@ +import Foundation + +struct Reminder { + var title: String + var isCompleted = false +} + +extension Reminder { + static let samples = [ + Reminder(title: "Build sample app", isCompleted: true), + Reminder(title: "Create tutorial"), + Reminder(title: "???"), + Reminder(title: "PROFIT!"), + ] +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-reminder-02.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-reminder-02.swift new file mode 100644 index 000000000..167aec066 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-02-reminder-02.swift @@ -0,0 +1,16 @@ +import Foundation + +struct Reminder: Identifiable { + let id = UUID() + var title: String + var isCompleted = false +} + +extension Reminder { + static let samples = [ + Reminder(title: "Build sample app", isCompleted: true), + Reminder(title: "Create tutorial"), + Reminder(title: "???"), + Reminder(title: "PROFIT!"), + ] +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-03-contentview-00.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-03-contentview-00.swift new file mode 100644 index 000000000..30b1cddc6 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-03-contentview-00.swift @@ -0,0 +1,7 @@ +import SwiftUI + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-03-contentview-01.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-03-contentview-01.swift new file mode 100644 index 000000000..98b762a34 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-03-contentview-01.swift @@ -0,0 +1,25 @@ +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + var body: some View { + List(reminders) { reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + Text(reminder.title) + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-03-contentview-02.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-03-contentview-02.swift new file mode 100644 index 000000000..a769bd259 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-03-contentview-02.swift @@ -0,0 +1,28 @@ +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + var body: some View { + List(reminders) { reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + + } + Text(reminder.title) + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-03-contentview-03.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-03-contentview-03.swift new file mode 100644 index 000000000..745ed796f --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-03-contentview-03.swift @@ -0,0 +1,28 @@ +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + var body: some View { + List(reminders) { reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-03-contentview-04.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-03-contentview-04.swift new file mode 100644 index 000000000..4e648ad62 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-03-contentview-04.swift @@ -0,0 +1,28 @@ +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + var body: some View { + List($reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-01.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-01.swift new file mode 100644 index 000000000..2cb71d689 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-01.swift @@ -0,0 +1,13 @@ +import SwiftUI + +struct AddReminderView: View { + var body: some View { + Text("Hello, World!") + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-02.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-02.swift new file mode 100644 index 000000000..822db3855 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-02.swift @@ -0,0 +1,15 @@ +import SwiftUI + +struct AddReminderView: View { + var body: some View { + Form { + Text("Hello, World!") + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-03.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-03.swift new file mode 100644 index 000000000..47000a0f7 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-03.swift @@ -0,0 +1,18 @@ +import SwiftUI + +struct AddReminderView: View { + @State + private var reminder = Reminder(title: "") + + var body: some View { + Form { + Text("Hello, World!") + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-04.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-04.swift new file mode 100644 index 000000000..9f07f36a1 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-04.swift @@ -0,0 +1,18 @@ +import SwiftUI + +struct AddReminderView: View { + @State + private var reminder = Reminder(title: "") + + var body: some View { + Form { + TextField("Title", text: $reminder.title) + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-05.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-05.swift new file mode 100644 index 000000000..cd3a614cc --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-05.swift @@ -0,0 +1,22 @@ +import SwiftUI + +struct AddReminderView: View { + @State + private var reminder = Reminder(title: "") + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + } + .toolbar { + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-06.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-06.swift new file mode 100644 index 000000000..c06eff66c --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-06.swift @@ -0,0 +1,27 @@ +import SwiftUI + +struct AddReminderView: View { + @State + private var reminder = Reminder(title: "") + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + } + .toolbar { + ToolbarItem(placement: .confirmationAction) { + Button(action: {}) { + Text("Add") + } + } + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-07.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-07.swift new file mode 100644 index 000000000..543847c2d --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-07.swift @@ -0,0 +1,31 @@ +import SwiftUI + +struct AddReminderView: View { + @State + private var reminder = Reminder(title: "") + + var onCommit: (_ reminder: Reminder) -> Void + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + } + .toolbar { + ToolbarItem(placement: .confirmationAction) { + Button(action: {}) { + Text("Add") + } + } + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-08.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-08.swift new file mode 100644 index 000000000..958c704c5 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-08.swift @@ -0,0 +1,35 @@ +import SwiftUI + +struct AddReminderView: View { + @State + private var reminder = Reminder(title: "") + + var onCommit: (_ reminder: Reminder) -> Void + + private func commit() { + onCommit(reminder) + } + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + } + .toolbar { + ToolbarItem(placement: .confirmationAction) { + Button(action: commit) { + Text("Add") + } + } + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-09.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-09.swift new file mode 100644 index 000000000..ca549cba1 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-09.swift @@ -0,0 +1,38 @@ +import SwiftUI + +struct AddReminderView: View { + @State + private var reminder = Reminder(title: "") + + @Environment(\.dismiss) + private var dismiss + + var onCommit: (_ reminder: Reminder) -> Void + + private func commit() { + onCommit(reminder) + } + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + } + .toolbar { + ToolbarItem(placement: .confirmationAction) { + Button(action: commit) { + Text("Add") + } + } + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-10.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-10.swift new file mode 100644 index 000000000..7dbc61b55 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-04-addreminderview-10.swift @@ -0,0 +1,39 @@ +import SwiftUI + +struct AddReminderView: View { + @State + private var reminder = Reminder(title: "") + + @Environment(\.dismiss) + private var dismiss + + var onCommit: (_ reminder: Reminder) -> Void + + private func commit() { + onCommit(reminder) + dismiss() + } + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + } + .toolbar { + ToolbarItem(placement: .confirmationAction) { + Button(action: commit) { + Text("Add") + } + } + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-01.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-01.swift new file mode 100644 index 000000000..710940e1f --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-01.swift @@ -0,0 +1,31 @@ +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + @State + private var isAddReminderDialogPresented = false + + var body: some View { + List($reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-02.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-02.swift new file mode 100644 index 000000000..88dbf9191 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-02.swift @@ -0,0 +1,35 @@ +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-03.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-03.swift new file mode 100644 index 000000000..18dea87d9 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-03.swift @@ -0,0 +1,46 @@ +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + Button(action: presentAddReminderView) { + HStack { + Image(systemName: "plus.circle.fill") + Text("New Reminder") + } + } + Spacer() + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-04.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-04.swift new file mode 100644 index 000000000..54b0af277 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-04.swift @@ -0,0 +1,49 @@ +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + Button(action: presentAddReminderView) { + HStack { + Image(systemName: "plus.circle.fill") + Text("New Reminder") + } + } + Spacer() + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + NavigationStack { + ContentView() + .navigationTitle("Reminders") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-05.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-05.swift new file mode 100644 index 000000000..d0326a0da --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-05.swift @@ -0,0 +1,53 @@ +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + Button(action: presentAddReminderView) { + HStack { + Image(systemName: "plus.circle.fill") + Text("New Reminder") + } + } + Spacer() + } + } + .sheet(isPresented: $isAddReminderDialogPresented) { + AddReminderView { reminder in + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + NavigationStack { + ContentView() + .navigationTitle("Reminders") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-06.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-06.swift new file mode 100644 index 000000000..add6fe05e --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-05-contentview-present-addreminder-06.swift @@ -0,0 +1,54 @@ +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + Button(action: presentAddReminderView) { + HStack { + Image(systemName: "plus.circle.fill") + Text("New Reminder") + } + } + Spacer() + } + } + .sheet(isPresented: $isAddReminderDialogPresented) { + AddReminderView { reminder in + reminders.append(reminder) + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + NavigationStack { + ContentView() + .navigationTitle("Reminders") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-01.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-01.swift new file mode 100644 index 000000000..194994a99 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-01.swift @@ -0,0 +1,43 @@ +import SwiftUI + +struct AddReminderView: View { + enum FocusableField: Hashable { + case title + } + + @State + private var reminder = Reminder(title: "") + + @Environment(\.dismiss) + private var dismiss + + var onCommit: (_ reminder: Reminder) -> Void + + private func commit() { + onCommit(reminder) + dismiss() + } + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + } + .toolbar { + ToolbarItem(placement: .confirmationAction) { + Button(action: commit) { + Text("Add") + } + } + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-02.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-02.swift new file mode 100644 index 000000000..bc967fd8d --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-02.swift @@ -0,0 +1,46 @@ +import SwiftUI + +struct AddReminderView: View { + enum FocusableField: Hashable { + case title + } + + @FocusState + private var focusedField: FocusableField? + + @State + private var reminder = Reminder(title: "") + + @Environment(\.dismiss) + private var dismiss + + var onCommit: (_ reminder: Reminder) -> Void + + private func commit() { + onCommit(reminder) + dismiss() + } + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + } + .toolbar { + ToolbarItem(placement: .confirmationAction) { + Button(action: commit) { + Text("Add") + } + } + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-03.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-03.swift new file mode 100644 index 000000000..f61eb6ba9 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-03.swift @@ -0,0 +1,47 @@ +import SwiftUI + +struct AddReminderView: View { + enum FocusableField: Hashable { + case title + } + + @FocusState + private var focusedField: FocusableField? + + @State + private var reminder = Reminder(title: "") + + @Environment(\.dismiss) + private var dismiss + + var onCommit: (_ reminder: Reminder) -> Void + + private func commit() { + onCommit(reminder) + dismiss() + } + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + .focused($focusedField, equals: .title) + } + .toolbar { + ToolbarItem(placement: .confirmationAction) { + Button(action: commit) { + Text("Add") + } + } + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-04.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-04.swift new file mode 100644 index 000000000..66d731198 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-04.swift @@ -0,0 +1,50 @@ +import SwiftUI + +struct AddReminderView: View { + enum FocusableField: Hashable { + case title + } + + @FocusState + private var focusedField: FocusableField? + + @State + private var reminder = Reminder(title: "") + + @Environment(\.dismiss) + private var dismiss + + var onCommit: (_ reminder: Reminder) -> Void + + private func commit() { + onCommit(reminder) + dismiss() + } + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + .focused($focusedField, equals: .title) + } + .toolbar { + ToolbarItem(placement: .confirmationAction) { + Button(action: commit) { + Text("Add") + } + } + } + .onAppear { + focusedField = .title + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-05.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-05.swift new file mode 100644 index 000000000..9fa7f0e65 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-05.swift @@ -0,0 +1,51 @@ +import SwiftUI + +struct AddReminderView: View { + enum FocusableField: Hashable { + case title + } + + @FocusState + private var focusedField: FocusableField? + + @State + private var reminder = Reminder(title: "") + + @Environment(\.dismiss) + private var dismiss + + var onCommit: (_ reminder: Reminder) -> Void + + private func commit() { + onCommit(reminder) + dismiss() + } + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + .focused($focusedField, equals: .title) + } + .toolbar { + ToolbarItem(placement: .confirmationAction) { + Button(action: commit) { + Text("Add") + } + .disabled(reminder.title.isEmpty) + } + } + .onAppear { + focusedField = .title + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-06.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-06.swift new file mode 100644 index 000000000..cc30a845f --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-06.swift @@ -0,0 +1,53 @@ +import SwiftUI + +struct AddReminderView: View { + enum FocusableField: Hashable { + case title + } + + @FocusState + private var focusedField: FocusableField? + + @State + private var reminder = Reminder(title: "") + + @Environment(\.dismiss) + private var dismiss + + var onCommit: (_ reminder: Reminder) -> Void + + private func commit() { + onCommit(reminder) + dismiss() + } + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + .focused($focusedField, equals: .title) + } + .navigationTitle("New Reminder") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .confirmationAction) { + Button(action: commit) { + Text("Add") + } + .disabled(reminder.title.isEmpty) + } + } + .onAppear { + focusedField = .title + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-07.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-07.swift new file mode 100644 index 000000000..ba92472d8 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-07.swift @@ -0,0 +1,57 @@ +import SwiftUI + +struct AddReminderView: View { + enum FocusableField: Hashable { + case title + } + + @FocusState + private var focusedField: FocusableField? + + @State + private var reminder = Reminder(title: "") + + @Environment(\.dismiss) + private var dismiss + + var onCommit: (_ reminder: Reminder) -> Void + + private func commit() { + onCommit(reminder) + dismiss() + } + + private func cancel() { + dismiss() + } + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + .focused($focusedField, equals: .title) + } + .navigationTitle("New Reminder") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .confirmationAction) { + Button(action: commit) { + Text("Add") + } + .disabled(reminder.title.isEmpty) + } + } + .onAppear { + focusedField = .title + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-08.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-08.swift new file mode 100644 index 000000000..cd9110f5b --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/code/building-todo-ui-reminder-06-addreminder-brushup-08.swift @@ -0,0 +1,62 @@ +import SwiftUI + +struct AddReminderView: View { + enum FocusableField: Hashable { + case title + } + + @FocusState + private var focusedField: FocusableField? + + @State + private var reminder = Reminder(title: "") + + @Environment(\.dismiss) + private var dismiss + + var onCommit: (_ reminder: Reminder) -> Void + + private func commit() { + onCommit(reminder) + dismiss() + } + + private func cancel() { + dismiss() + } + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + .focused($focusedField, equals: .title) + } + .navigationTitle("New Reminder") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .cancellationAction) { + Button(action: cancel) { + Text("Cancel") + } + } + ToolbarItem(placement: .confirmationAction) { + Button(action: commit) { + Text("Add") + } + .disabled(reminder.title.isEmpty) + } + } + .onAppear { + focusedField = .title + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/projectfiles/01-building-a-simple-todo-list-ui.zip b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/projectfiles/01-building-a-simple-todo-list-ui.zip new file mode 100644 index 000000000..70e9aa118 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/01-building-a-simple-todo-list-ui/projectfiles/01-building-a-simple-todo-list-ui.zip differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-all-groups@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-all-groups@2x.png new file mode 100644 index 000000000..4f85e7f5e Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-all-groups@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-all-groups~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-all-groups~dark@2x.png new file mode 100644 index 000000000..3a46dd740 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-all-groups~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-group-mvvm@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-group-mvvm@2x.png new file mode 100644 index 000000000..4a62277c6 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-group-mvvm@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-group-mvvm~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-group-mvvm~dark@2x.png new file mode 100644 index 000000000..58b4b0c3d Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-group-mvvm~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-group-reminders@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-group-reminders@2x.png new file mode 100644 index 000000000..bb478fcd3 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-group-reminders@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-group-reminders~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-group-reminders~dark@2x.png new file mode 100644 index 000000000..415caada6 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-group-reminders~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-new-file@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-new-file@2x.png new file mode 100644 index 000000000..9b54785d8 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-new-file@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-new-file~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-new-file~dark@2x.png new file mode 100644 index 000000000..791251370 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-new-file~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-new-group@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-new-group@2x.png new file mode 100644 index 000000000..b3fb57148 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-new-group@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-new-group~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-new-group~dark@2x.png new file mode 100644 index 000000000..ecb0d7471 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-new-group~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-refactor-rename-reminderslistview@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-refactor-rename-reminderslistview@2x.png new file mode 100644 index 000000000..3147d1358 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-refactor-rename-reminderslistview@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-refactor-rename-reminderslistview~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-refactor-rename-reminderslistview~dark@2x.png new file mode 100644 index 000000000..04b8c39c7 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-refactor-rename-reminderslistview~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-refactor-rename@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-refactor-rename@2x.png new file mode 100644 index 000000000..c95be7a84 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-refactor-rename@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-refactor-rename~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-refactor-rename~dark@2x.png new file mode 100644 index 000000000..91021357b Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-01-refactor-rename~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-02-move-files-reminder@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-02-move-files-reminder@2x.png new file mode 100644 index 000000000..126b1dbfa Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-02-move-files-reminder@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-02-move-files-reminder~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-02-move-files-reminder~dark@2x.png new file mode 100644 index 000000000..0e9ae8fb9 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-02-move-files-reminder~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-02-move-files@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-02-move-files@2x.png new file mode 100644 index 000000000..3c07aa0c8 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-02-move-files@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-02-move-files~dark@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-02-move-files~dark@2x.png new file mode 100644 index 000000000..7ccdd1e4a Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/artwork/mvvm-02-move-files~dark@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistview-00.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistview-00.swift new file mode 100644 index 000000000..b70d8aeb1 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistview-00.swift @@ -0,0 +1,45 @@ +import SwiftUI + +struct RemindersListView: View { + @State + private var reminders = Reminder.samples + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + Button(action: presentAddReminderView) { + HStack { + Image(systemName: "plus.circle.fill") + Text("New Reminder") + } + } + Spacer() + } + } + .sheet(isPresented: $isAddReminderDialogPresented) { + AddReminderView { reminder in + reminders.append(reminder) + } + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistview-01.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistview-01.swift new file mode 100644 index 000000000..54ade997f --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistview-01.swift @@ -0,0 +1,48 @@ +import SwiftUI + +struct RemindersListView: View { + @State + private var reminders = Reminder.samples + + @StateObject + private var viewModel = RemindersListViewModel() + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + Button(action: presentAddReminderView) { + HStack { + Image(systemName: "plus.circle.fill") + Text("New Reminder") + } + } + Spacer() + } + } + .sheet(isPresented: $isAddReminderDialogPresented) { + AddReminderView { reminder in + reminders.append(reminder) + } + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistview-02.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistview-02.swift new file mode 100644 index 000000000..a5ddb39c0 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistview-02.swift @@ -0,0 +1,48 @@ +import SwiftUI + +struct RemindersListView: View { +// @State +// private var reminders = Reminder.samples + + @StateObject + private var viewModel = RemindersListViewModel() + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($viewModel.reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + Button(action: presentAddReminderView) { + HStack { + Image(systemName: "plus.circle.fill") + Text("New Reminder") + } + } + Spacer() + } + } + .sheet(isPresented: $isAddReminderDialogPresented) { + AddReminderView { reminder in + viewModel.reminders.append(reminder) + } + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistviewmodel-01.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistviewmodel-01.swift new file mode 100644 index 000000000..b05abecb0 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistviewmodel-01.swift @@ -0,0 +1,4 @@ +import Foundation + +class RemindersListViewModel: ObservableObject { +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistviewmodel-02.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistviewmodel-02.swift new file mode 100644 index 000000000..14f297af5 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistviewmodel-02.swift @@ -0,0 +1,5 @@ +import Foundation + +class RemindersListViewModel: ObservableObject { + var reminders = Reminder.samples +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistviewmodel-03.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistviewmodel-03.swift new file mode 100644 index 000000000..d7bc9b00a --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-02-reminderslistviewmodel-03.swift @@ -0,0 +1,6 @@ +import Foundation + +class RemindersListViewModel: ObservableObject { + @Published + var reminders = Reminder.samples +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-03-reminderslist-00.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-03-reminderslist-00.swift new file mode 100644 index 000000000..819903b13 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-03-reminderslist-00.swift @@ -0,0 +1,45 @@ +import SwiftUI + +struct RemindersListView: View { + @StateObject + private var viewModel = RemindersListViewModel() + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($viewModel.reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + Button(action: presentAddReminderView) { + HStack { + Image(systemName: "plus.circle.fill") + Text("New Reminder") + } + } + Spacer() + } + } + .sheet(isPresented: $isAddReminderDialogPresented) { + AddReminderView { reminder in + viewModel.reminders.append(reminder) + } + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-03-reminderslist-01.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-03-reminderslist-01.swift new file mode 100644 index 000000000..3d364901c --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-03-reminderslist-01.swift @@ -0,0 +1,45 @@ +import SwiftUI + +struct RemindersListView: View { + @StateObject + private var viewModel = RemindersListViewModel() + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($viewModel.reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + Button(action: presentAddReminderView) { + HStack { + Image(systemName: "plus.circle.fill") + Text("New Reminder") + } + } + Spacer() + } + } + .sheet(isPresented: $isAddReminderDialogPresented) { + AddReminderView { reminder in + viewModel.addReminder(reminder) + } + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-03-reminderslistviewmodel-00.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-03-reminderslistviewmodel-00.swift new file mode 100644 index 000000000..9161770d9 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-03-reminderslistviewmodel-00.swift @@ -0,0 +1,7 @@ +import Foundation + +class RemindersListViewModel: ObservableObject { + @Published + var reminders = Reminder.samples + +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-03-reminderslistviewmodel-01.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-03-reminderslistviewmodel-01.swift new file mode 100644 index 000000000..354630246 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-03-reminderslistviewmodel-01.swift @@ -0,0 +1,10 @@ +import Foundation + +class RemindersListViewModel: ObservableObject { + @Published + var reminders = Reminder.samples + + func addReminder(_ reminder: Reminder) { + reminders.append(reminder) + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-04-reminderslist-00.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-04-reminderslist-00.swift new file mode 100644 index 000000000..3d364901c --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-04-reminderslist-00.swift @@ -0,0 +1,45 @@ +import SwiftUI + +struct RemindersListView: View { + @StateObject + private var viewModel = RemindersListViewModel() + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($viewModel.reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + Button(action: presentAddReminderView) { + HStack { + Image(systemName: "plus.circle.fill") + Text("New Reminder") + } + } + Spacer() + } + } + .sheet(isPresented: $isAddReminderDialogPresented) { + AddReminderView { reminder in + viewModel.addReminder(reminder) + } + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-04-reminderslist-01.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-04-reminderslist-01.swift new file mode 100644 index 000000000..77404f273 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-04-reminderslist-01.swift @@ -0,0 +1,45 @@ +import SwiftUI + +struct RemindersListView: View { + @StateObject + private var viewModel = RemindersListViewModel() + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($viewModel.reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + viewModel.toggleCompleted(reminder) + } + Text(reminder.title) + } + } + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + Button(action: presentAddReminderView) { + HStack { + Image(systemName: "plus.circle.fill") + Text("New Reminder") + } + } + Spacer() + } + } + .sheet(isPresented: $isAddReminderDialogPresented) { + AddReminderView { reminder in + viewModel.addReminder(reminder) + } + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-04-reminderslistviewmodel-00.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-04-reminderslistviewmodel-00.swift new file mode 100644 index 000000000..9161770d9 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-04-reminderslistviewmodel-00.swift @@ -0,0 +1,7 @@ +import Foundation + +class RemindersListViewModel: ObservableObject { + @Published + var reminders = Reminder.samples + +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-04-reminderslistviewmodel-01.swift b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-04-reminderslistviewmodel-01.swift new file mode 100644 index 000000000..8ff7223e1 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/code/implementing-mvvm-04-reminderslistviewmodel-01.swift @@ -0,0 +1,16 @@ +import Foundation + +class RemindersListViewModel: ObservableObject { + @Published + var reminders = Reminder.samples + + func addReminder(_ reminder: Reminder) { + reminders.append(reminder) + } + + func toggleCompleted(_ reminder: Reminder) { + if let index = reminders.firstIndex(where: { $0.id == reminder.id} ) { + reminders[index].isCompleted.toggle() + } + } +} \ No newline at end of file diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/projectfiles/02-implementing-mvvm.zip b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/projectfiles/02-implementing-mvvm.zip new file mode 100644 index 000000000..6e45c3419 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/chapter01/02-implementing-mvvm/projectfiles/02-implementing-mvvm.zip differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/chapter1@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/chapter1@2x.png new file mode 100644 index 000000000..e29182407 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/chapter1@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/chapters.key b/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/chapters.key new file mode 100755 index 000000000..74dc2b8c3 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/chapters.key differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/macbook.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/macbook.png new file mode 100644 index 000000000..395d86d4a Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/macbook.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/make-it-so-intro.key b/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/make-it-so-intro.key new file mode 100755 index 000000000..99f624b54 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/make-it-so-intro.key differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/make-it-so-intro.rotato b/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/make-it-so-intro.rotato new file mode 100644 index 000000000..af43a00f9 Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/make-it-so-intro.rotato differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/make-it-so-intro@2x.png b/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/make-it-so-intro@2x.png new file mode 100644 index 000000000..1d533e99d Binary files /dev/null and b/code/frontend/MakeItSo/MakeItSo.docc/Resources/table-of-contents/artwork/make-it-so-intro@2x.png differ diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Tutorials/MakeItSo.tutorial b/code/frontend/MakeItSo/MakeItSo.docc/Tutorials/MakeItSo.tutorial new file mode 100644 index 000000000..622415639 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Tutorials/MakeItSo.tutorial @@ -0,0 +1,18 @@ +@Tutorials(name: "MakeItSo") { + @Intro(title: "SwiftUI and Firebase") { + Learn how to use Firebase in SwiftUI apps by building _Make It So_, a replica of Apple's Reminders app. + + @Image(source: make-it-so-intro.png, alt: "") + } + + @Volume(name: "Creating a Simple Todo List App with SwiftUI and Firebase") { + Start building apps with SwiftUI, a declarative UI framework, and Firebase, Google's app development platform. You will build _Make It So_, a simple todo list application. + @Chapter(name: "Building the UI") { + @Image(source: chapter1.png, alt: "A wireframe of an app interface.") + + In this chapter, you will learn how to use SwiftUI to create a simple UI for a todo list application. + @TutorialReference(tutorial: "doc:01-Building-a-Simple-Todo-List-UI") + @TutorialReference(tutorial: "doc:02-Implementing-MVVM") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Tutorials/chapter01/01 Building a Simple Todo List UI.tutorial b/code/frontend/MakeItSo/MakeItSo.docc/Tutorials/chapter01/01 Building a Simple Todo List UI.tutorial new file mode 100644 index 000000000..509e06dec --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Tutorials/chapter01/01 Building a Simple Todo List UI.tutorial @@ -0,0 +1,479 @@ +@Tutorial(time: 25, projectFiles: 01-building-a-simple-todo-list-ui.zip) { + @XcodeRequirement(title: "Xcode 14", destination: "https://xcodereleases.com/") + @Intro(title: "Building a Simple Todo List UI") { + This tutorial guides you through building _Make It So_, a todo list application. You will start by creating s simple UI for displaying todo list items. + + @Image(source: building-todo-ui-intro.png, alt: "") + } + + @Section(title: "Create a New Project") { + @ContentAndMedia { + Create a new Xcode project that uses SwiftUI. + + To preview and interact with views from the canvas in Xcode, and to use all the latest features described throughout the tutorials, ensure your Mac is running macOS Monterey or later. + + @Video(source: make-it-so-intro.mov, alt: "") + } + + @Steps { + @Step { + Open Xcode and either click _Create a new Xcode project_ in Xcode's startup window, or choose _File > New > Project_. + + @Image(source: building-todo-ui-xcode-new-project.png, alt: "") + } + + @Step { + In the template selector, select _iOS_ as the platform, select the _App_ template, and then click _Next_. + + @Image(source: building-todo-ui-xcode-app-template.png, alt: "") + } + + @Step { + Select _SwiftUI_ from the Interface drop-down menu and _Swift_ from the language drop-down menu, then click _Next_. Choose a location to save the `MakeItSo` project on your Mac. + + @Image(source: building-todo-ui-xcode-project-name.png, alt: "") + } + } + } + + @Section(title: "Create a Reminder Model and Add some Test Data") { + @ContentAndMedia { + + + @Image(source: sectionintros.001.png, alt: "") + } + + @Steps { + @Step { + Choose _File > New > File_ to create a new Swift file in your project and name it `Reminder.swift`. + + @Image(source: building-todo-ui-new-swift-file.png, alt: "") + } + + @Step { + Define the data model for a reminder. + + @Code(name: "Reminder.swift", file: building-todo-ui-reminder-01-02.swift, previousFile: building-todo-ui-reminder-01-01.swift) + } + + @Step { + Create a Swift extension for the `Reminder` struct and declare a static constant `samples`. Add a couple of todo items. Later in this tutorial, you will use this sample data to display a list of todo items. + + @Code(name: "Reminder.swift", file: building-todo-ui-reminder-01-03.swift) + } + + } + } + + @Section(title: "Display a List of Reminders") { + @ContentAndMedia { + + + @Image(source: sectionintros.002.png, alt: "") + } + + @Steps { + @Step { + In the _Project_ navigator, select `ContentView.swift`. + + By default, SwiftUI view files declare two structures. The first structure conforms to the `View` protocol and describes the view’s content and layout. The second structure declares a preview for that view. + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-02-contentview-02.swift, previousFile: building-todo-ui-reminder-02-contentview-01.swift) { + @Image(source: building-todo-ui-reminder-02-contentview-02.png, alt: "") + } + } + + @Step { + Inside the `body` property, change the vertical stack to a horizontal stack. + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-02-contentview-03.swift) { + @Image(source: building-todo-ui-reminder-02-contentview-03.png, alt: "") + } + } + + @Step { + Change the icon to a circle. + + > Note: In a later step in this tutorial, you will use a filled circle and a unfilled circle to indicate the `isCompleted` status of todo items + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-02-contentview-04.swift) { + @Image(source: building-todo-ui-reminder-02-contentview-04.png, alt: "") + } + } + + @Step { + Add a private `@State` property to hold a list of reminders. + + > Note: It is a good practice to mark properties that you don't plan to access from outside a view as `private`. This prevents leaking information, and helps to keep the views initialiser clean, as you will see in a future step. + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-02-contentview-05.swift) { + @Image(source: building-todo-ui-reminder-02-contentview-04.png, alt: "") + } + } + + @Step { + Remove the `.padding()` view modifier. + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-02-contentview-06.swift) { + @Image(source: building-todo-ui-reminder-02-contentview-04.png, alt: "") + } + } + + @Step { + Wrap the `HStack` in a `List`. + + > Warning: This will result in a compile error saying that `Reminder` is not `Identifiable`. You will fix this in the next step. + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-02-contentview-07.swift) { + @Image(source: building-todo-ui-reminder-02-contentview-06.png, alt: "") + } + } + + @Step { + Mark `Reminder` as `Identifiable`, and add a constant property `id`. + + > Note: SwiftUI will use the `id` property of the `Reminder` struct to determine the identity of the list rows inside the `List` view. It is important to keep a view's identity stable, as this will help SwiftUI determine which parts of the UI to update when the data model changes. + + @Code(name: "Reminder.swift", file: building-todo-ui-reminder-02-reminder-02.swift, previousFile: building-todo-ui-reminder-02-reminder-01.swift) + } + + @Step { + Navigate back to `ContentView.swift`. The compile error should now be resolved, and the error message will disappear. + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-02-contentview-08.swift) { + @Image(source: building-todo-ui-reminder-02-contentview-07.png, alt: "") + } + } + + The `List` view iterates over all elements of the collection you pass in as the first parameter - in this case, `reminders`. Inside the `List` view's closure, you can access the individual elements of the collection using the closure parameter, `reminder`. + + @Step { + Update the views inside the `List` view to display the `title` and `isCompleted` state of the current collection element. + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-02-contentview-09.swift) { + @Image(source: building-todo-ui-reminder-02-contentview-08.png, alt: "") + } + } + + } + } + + @Section(title: "Mark Reminders as isCompleted") { + @ContentAndMedia { + The main purpose of a todo list app is to allow users to get things done. In this step, you will turn the static `Image` view into an interactive component that allows users to mark tasks as `isCompleted`. + + @Video(source: sectionintros.003.mp4, alt: "") + } + + @Steps { + @Step { + In the _Project_ navigator, select `ContentView.swift`. + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-03-contentview-01.swift, previousFile: building-todo-ui-reminder-03-contentview-00.swift) { + @Image(source: building-todo-ui-reminder-03-contentview-01.png, alt: "") + } + } + + @Step { + Use the `onTapGesture` view modifier to register an event handler that gets called when the user taps on the `Image` view. + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-03-contentview-02.swift) + } + + @Step { + Toogle the `isCompleted` status of the respective reminder. + + > Warning: This will result in a compiler error saying that you _cannot use mutating member on immutable value: 'reminder' is a 'let' constant._. You will fix this in the next step. + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-03-contentview-03.swift) { + @Image(source: building-todo-ui-reminder-03-contentview-03.png, alt: "") + } + } + + @Step { + Create a list binding by turning the `List` parameter into a `Binding` of type `Array` of `Reminder`, and then accessing the individual elements of the collection as a `Binding` inside the `List` closure. + + The compile error should now be resolved, and the error message will disappear. + + > Tip: You can learn more about `List` bindings in this blog post: [SwiftUI List Bindings - Behind the Scenes](https://peterfriese.dev/posts/swiftui-list-item-bindings-behind-the-scenes/) + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-03-contentview-04.swift) + } + + @Step { + Use the live preview and try out this new functionality by tapping the check boxes. + + @Video(source: building-todo-ui-reminder-03-contentview-05.mp4) + } + + } + } + + @Section(title: "Create a Dialog for Adding New Reminders") { + @ContentAndMedia { + Adding new reminders is another key feature of any todo list application. In this step, you will create a dialog that allows users to add new reminders. + + @Video(source: sectionintros.004.mp4, alt: "") + } + + @Steps { + @Step { + Choose _File > New > File_ to create a new SwiftUI file in your project and name it `AddReminderView.swift`. + + @Image(source: building-todo-ui-new-swiftui-file.png, alt: "") + } + + @Step { + Wrap the greeting `Text("Hello, World!")` inside a `Form`. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-04-addreminderview-02.swift, previousFile: building-todo-ui-reminder-04-addreminderview-01.swift) { + @Image(source: building-todo-ui-reminder-04-addreminderview-01.png, alt: "") + } + } + + @Step { + Define a new local state variable to contain the new `Reminder`. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-04-addreminderview-03.swift) { + @Image(source: building-todo-ui-reminder-04-addreminderview-01.png, alt: "") + } + } + + @Step { + Replace the `Text` view with a `TextField`. Set its `title` property to `"Title"`, and bind its `text` property to the `title` property of the `reminder` property. + + > Note: Since the `title` property of the `reminder` is empty, the `TextField` will display a placeholder text. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-04-addreminderview-04.swift) { + @Image(source: building-todo-ui-reminder-04-addreminderview-04.png, alt: "") + } + } + + To allow the user to add the reminder to their list, you will next create a toolbar that contains an _Add_ button. + + @Step { + Wrap the `Form` inside a `NavigationStack`, and the `toolbar` view modifier to add a toolbar to the `Form` + + > Note: To make the toolbar visible, the view needs to be wrapped inside a navigation. Once you add a button to the toolbar, it will become visible. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-04-addreminderview-05.swift) { + @Image(source: building-todo-ui-reminder-04-addreminderview-04.png, alt: "") + } + } + + @Step { + Add a button for the _Add_ action to the toolbar. + + > Note: By specifying the `.confirmationAction` placement, the button will be placed on the right side of the toolbar on iOS. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-04-addreminderview-06.swift) { + @Image(source: building-todo-ui-reminder-04-addreminderview-06.png, alt: "") + } + } + + } + } + + @Section(title: "Pass Data From the Child View") { + @ContentAndMedia { + When the user taps on the _Add_ button in the _Add Reminder_ dialog, the new reminder needs to be passed to the calling view so it can be added to the list of reminders. + + A common way to implement this is by using a completion handler. In this section, you will implement a completion handler and present the _AddReminderView_ from the parent view. + + @Image(source: sectionintros.005.png, alt: "") + } + + @Steps { + @Step { + Define a property `onCommit` for the completion handler. This handler has one parameter for passing the `Reminder` to the calling view. + + Adjust the preview provider to make use of the completion handler. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-04-addreminderview-07.swift, previousFile: building-todo-ui-reminder-04-addreminderview-06) { + @Image(source: building-todo-ui-reminder-04-addreminderview-06.png, alt: "") + } + } + + @Step { + Add a new private function `commit`. Inside this function, call the `onCommit` completion handler, passing the `reminder` property. + + Call the `commit` function when the user taps on the _Add_ button. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-04-addreminderview-08.swift) { + @Image(source: building-todo-ui-reminder-04-addreminderview-06.png, alt: "") + } + } + + @Step { + Add a new private variable `dismiss` at the top of `AddReminderView`, and use the `@Environment` property wrapper to connect it to the `dismiss` action from the SwiftUI environment. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-04-addreminderview-09.swift) { + @Image(source: building-todo-ui-reminder-04-addreminderview-06.png, alt: "") + } + } + + @Step { + Call `dismiss()` at the end of the `commit` function, after passing the new reminder to the calling view. This will dismiss the `Add Reminder` dialog after the data has been passed. + + > Note: This works because the `dismiss` environment value makes use of `callAsFunction`. To learn more about this, check out [How and when to use callAsFunction in Swift 5.2](https://www.donnywals.com/how-and-when-to-use-callasfunction-in-swift-5-2/) or [Callable values of user-defined nominal types – available from Swift 5.2](https://www.hackingwithswift.com/swift/5.2/callasfunction). + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-04-addreminderview-10.swift) { + @Image(source: building-todo-ui-reminder-04-addreminderview-06.png, alt: "") + } + } + } + } + + @Section(title: "Present the Add Reminder Dialog") { + @ContentAndMedia { + Open the dialog from the reminders lit. + + @Image(source: sectionintros.006, alt: "") + } + + @Steps { + @Step { + Go back to the `ContentView.swift` file, and add a new boolean property `isAddReminderDialogPresented`. + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-05-contentview-present-addreminder-01.swift, previousFile: building-todo-ui-reminder-03-contentview-04.swift) + } + + @Step { + Add a helper function for toggling the state of `isAddReminderDialogPresented` + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-05-contentview-present-addreminder-02.swift) + } + + @Step { + Add a toobar with the _New Reminder_ button. In the `action` of the button, call the helper function you created in the previous step. + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-05-contentview-present-addreminder-03.swift) + } + + @Step { + To be able to see the toolbar, wrap `ContentView` in a `NavigationStack` in the preview provider. + + > Note: Keep in mind that you own the preview, so you can adjust it to your needs to make it easier to see the view you're working on in the context it will later be used in. + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-05-contentview-present-addreminder-04.swift) { + @Image(source: building-todo-ui-reminder-05-contentview-present-addreminder-04.png, alt: "") + } + } + + @Step { + Use the `sheet` view modifier to present the `AddReminderView` dialog. Bind the `isPresented` parameter to the `isAddReminderPresented` property you defined in an earlier step. + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-05-contentview-present-addreminder-05.swift) { + @Image(source: building-todo-ui-reminder-05-contentview-present-addreminder-04.png, alt: "") + } + } + + @Step { + Inside the `onCommit` closure of the `AddReminderView` view, take the `reminder` parameter and append the new reminder to the list of reminders. + + @Code(name: "ContentView.swift", file: building-todo-ui-reminder-05-contentview-present-addreminder-06.swift) { + @Image(source: building-todo-ui-reminder-05-contentview-present-addreminder-04.png, alt: "") + } + } + + @Step { + Use the live preview and try out this new functionality by tapping the _New Reminder_ button to add a new reminder to the list of reminders. + + @Video(source: building-todo-ui-reminder-05-contentview-present-addreminder-05.mp4) + } + } + } + + @Section(title: "Brush up the UI") { + @ContentAndMedia { + To finish this first chapter, refine the UI: + + * Make sure the `title` input field is active + * Make sure the _Add_ button is only active if the reminder input field is not empty + * Add a _Cancel_ button + * Add a title to the dialog + + @Video(source: sectionintros.007.mp4, alt: "") + } + + @Steps { + You might have noticed that the input field was not active when the dialog appears. This is inconvenient, especially on larger phones, when the input field might be hard to reach. In the next few steps, you will use SwiftUI's `@FocusState` property wrapper to place the cursor in the first input field when the dialog appears. + @Step { + Go back to the `AddReminderView.swift` file, and define an enum `FocusableField` whith a single case `title`. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-06-addreminder-brushup-01.swift, previousFile: building-todo-ui-reminder-04-addreminderview-10.swift) + } + + @Step { + Add a new private property `focusedField` as an optional `FocusedField` and mark it using the [`@FocusState`](https://developer.apple.com/documentation/swiftui/focusstate) property wrapper. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-06-addreminder-brushup-02.swift) + } + + @Step { + Use the `focused` view modifier to bind the focus state `focusedField` to the `TextField`. By using the `.title` enum case in the equality check, you tell SwiftUI to focus this field whenever `focusedField` is equal to `.title`. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-06-addreminder-brushup-03.swift) + } + + @Step { + In the final step, add an `onAppear` view modifier to the `Form` and set the `focusedField` property to `.title`. + + > Note: This makes sure the cursor will be placed inside the _Title_ `TextField` whenever the view appears. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-06-addreminder-brushup-04.swift) + } + + In the next step, you will make sure the _Add_ button is only active if the title of the reminder is not empty. This prevents adding empty reminders. + + @Step { + Add a `disabled` view modifier to the _Add_ button and bind it to the the `isEmpty` state of the `title` property of the reminder. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-06-addreminder-brushup-05.swift) { + @Image(source: building-todo-ui-reminder-06-addreminder-brushup-05.png, alt: "") + } + } + + @Step { + Add the `navigationTitle` view modifier to the `Form` to set the dialog title, and set the `navigationBarTitleDisplayMode` to `.inline`. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-06-addreminder-brushup-06.swift) { + @Image(source: building-todo-ui-reminder-06-addreminder-brushup-06.png, alt: "") + } + } + + @Step { + Add a private function `cancel`, and call `dismiss()` to dismiss the dialog. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-06-addreminder-brushup-07.swift) { + @Image(source: building-todo-ui-reminder-06-addreminder-brushup-06.png, alt: "") + } + } + + @Step { + Add a _Cancel_ button to toolbar, and use `.cancellationAction` to place it in the cancellation area of the toolbar. Call the `cancel` function you just created. + + @Code(name: "AddReminderView.swift", file: building-todo-ui-reminder-06-addreminder-brushup-08.swift) { + @Image(source: building-todo-ui-reminder-06-addreminder-brushup-07.png, alt: "") + } + } + } + } + + @Section(title: "Wrap Up") { + @ContentAndMedia { + Congratulations! + + You've implemented a fully functional UI for a todo list application in less than 150 lines of SwiftUI code. + } + + @Steps { + @Step { + Use the live preview and try out this new functionality by tapping the _New Reminder_ button to add a new reminder to the list of reminders. + + @Video(source: building-todo-ui-07-finale.mp4) + } + } + } + +} diff --git a/code/frontend/MakeItSo/MakeItSo.docc/Tutorials/chapter01/02 Implementing MVVM.tutorial b/code/frontend/MakeItSo/MakeItSo.docc/Tutorials/chapter01/02 Implementing MVVM.tutorial new file mode 100644 index 000000000..dd57ff16a --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo.docc/Tutorials/chapter01/02 Implementing MVVM.tutorial @@ -0,0 +1,160 @@ +@Tutorial(time: 20, projectFiles: 02-implementing-mvvm.zip) { + @XcodeRequirement(title: "Xcode 14", destination: "https://xcodereleases.com/") + @Intro(title: "Implementing Model, View, ViewModel (MVVM)") { + With the basic views for displaying and adding todo items set up, it is time to think about the architecture of the app. + + You will refactor the application to make use of the MVVM (**M**odel, **V**iew, **V**iew **M**odel) pattern. + + Download the project files to begin building this project, and follow the steps below. + + @Image(source: building-todo-ui-intro.png, alt: "") + } + + @Section(title: "Organise the Project Files") { + @ContentAndMedia { + In the first tutorial, you implemented the basic todo list view inside `ContentView.swift`, and created a couple of new files in the root folder of the project. That's fine for a simple project, but as this project will grow in complexity, it is important to keep things nicely organised. + + To get started, use the completed project from the previous tutorial. Alternatively, download the project files for this tutorial and use the project in the _starter_ folder. + + @Comment { + Screenshot of neatly organised project folder + } + } + + @Steps { + In this first step, you will create a number of folders to organise the files in your project. The top level folder will contain sub folders for the individual features of the app. Inside those features, you will create sub folders for organising files according to their architectural role: _Models_, _View Models_, and _Views_. + + @Step { + Select the root folder of your project (named _MakeItSo_), and then create a new folder by selecting _New Group_ in the context menu. + + Name the folder `Features`. + + @Image(source: mvvm-01-new-group.png, alt: "") + } + + @Step { + Select the `Features` folder, and create a new group named `Reminders` as a child of `Features`. + + @Image(source: mvvm-01-group-reminders.png, alt: "") + } + + @Step { + Inside the `Reminders` folder, create three new groups, naming them `Models`, `ViewModels`, and `Views`. + + @Image(source: mvvm-01-group-mvvm.png, alt: "") + } + + @Step { + The project layout in the _Project Navigator_ should now look like this. + + @Image(source: mvvm-01-all-groups.png, alt: "") + } + + In the next step, you will move the existing files into the new folders. + + @Step { + Drag and drop `Reminder.swift` into the _Models_ folder. + + @Image(source: mvvm-02-move-files-reminder.png, alt: "") + } + + @Step { + Drag and drop the views `ContentView.swift` and `AddReminderView.swift` into the _Views_ folder. + + The project structure should now look like this. + + @Image(source: mvvm-02-move-files.png, alt: "") + } + + So far, you've built the main UI of the app in a file named `ContentView.swift`. However, since this view displays a list of `Reminder`s, it might a better idea to name it `RemindersListView`. In the next step, you will use Xcode's refactoring tools to rename `ContentView` and all its occurrences to `RemindersListView`. + + @Step { + Open `ContentView.swift`, and select the view's name. Open the context menu, and choose _Refactor > Rename_. + + @Image(source: mvvm-01-refactor-rename.png, alt: "") + } + + @Step { + Xcode will find all occurrences of `ContentView` and show them in the _refactoring editor_. Type in the new name for the view, `RemindersListView`. + + > Tip: If you receive an error message saying that refactoring failed, try building the project first (⌘ + B), and resolve any compilation errors. Then try running the refactoring again. + + @Image(source: mvvm-01-refactor-rename-reminderslistview.png, alt: "") + } + } + } + + @Section(title: "Create a View Model and connect it to the RemindersListView") { + @ContentAndMedia { + } + + @Steps { + @Step { + Select the `ViewModels` folder, and create a Swift file named `RemindersListViewModel` as a child of `ViewModels`. + @Image(source: mvvm-01-new-file.png, alt: "") + } + + @Step { + Create a class named `RemindersListViewModel`, and conform it to the `ObservableObject` protocol. + @Code(name: "RemindersListViewModel.swift", file: implementing-mvvm-02-reminderslistviewmodel-01.swift) + } + + @Step { + Add a new property `reminders`, and assign some sample values from `Reminder.samples`. + @Code(name: "RemindersListViewModel.swift", file: implementing-mvvm-02-reminderslistviewmodel-02.swift) + } + + @Step { + Add the `@Published` property wrapper to mark this property as published. + @Code(name: "RemindersListViewModel.swift", file: implementing-mvvm-02-reminderslistviewmodel-03.swift) + } + + @Step { + Add a new property `viewModel` to `RemindersListView`, and instantiate `RemindersListViewModel`. Mark the property as `@StateObject`. + + > Note: SwiftUI will manage the lifecycle of any properties marked as `@StateObject`, and ensure that they are instantiated only once. This is important, as SwiftUI will create new instances of any view whenever any of the properties it observes change. + @Code(name: "RemindersListView.swift", file: implementing-mvvm-02-reminderslistview-01.swift, previousFile: implementing-mvvm-02-reminderslistview-00.swift) + } + + @Step { + Uncomment (or remove) the `reminders` property and its `@State` property wrapper. Then, replace all accesses to `reminders` in `RemindersListView` with an access to the `reminders` property on `viewModel`. + @Code(name: "RemindersListView.swift", file: implementing-mvvm-02-reminderslistview-02.swift) + } + } + } + + @Section(title: "Add a method to the View Model for adding new reminders") { + @ContentAndMedia { + One of the purposes of view models is to encapsulate any code that manipulates the model. So far, you are only using the view model to access the list of `Reminder`s via the `reminders` property. For addings new reminders, you directly access the `reminders` property. This works, but violates encapsulation. In the next step, you will introduce a method for addings new `Reminder`s to the model. + } + + @Steps { + @Step { + Add a new method `addReminder` to `RemindersListViewModel`. Calling this method will add the passed `Reminder` to the `reminders` array. + @Code(name: "RemindersListViewModel.swift", file: implementing-mvvm-03-reminderslistviewmodel-01.swift, previousFile: implementing-mvvm-03-reminderslistviewmodel-00.swift) + } + @Step { + In `RemindersListView`, replace the call to `viewModel.reminders.append(reminder)` with a call to `viewModel.addReminder(_ reminder:)` + @Code(name: "RemindersListView.swift", file: implementing-mvvm-03-reminderslist-01.swift, previousFile: implementing-mvvm-03-reminderslist-00.swift) + } + } + } + + @Section(title: "Add a method to the View Model for toggling the completion state of a reminder") { + @ContentAndMedia { + In the next step, you will introduce a method for toggling the completion state of a reminder. + } + + @Steps { + @Step { + Add a new method `toggleCompleted` to `RemindersListViewModel`. Calling this method will toggle the `isCompleted` state of the reminder. + @Code(name: "RemindersListViewModel.swift", file: implementing-mvvm-03-reminderslistviewmodel-01.swift, previousFile: implementing-mvvm-04-reminderslistviewmodel-00.swift) + } + @Step { + In `RemindersListView`, replace the call to `reminder.isCompleted.toggle()` with a call to `viewModel.toggleCompleted(_ reminder:)` + @Code(name: "RemindersListView.swift", file: implementing-mvvm-04-reminderslist-01.swift, previousFile: implementing-mvvm-04-reminderslist-00.swift) + } + } + } + +} diff --git a/code/frontend/MakeItSo/MakeItSo.xcodeproj/project.pbxproj b/code/frontend/MakeItSo/MakeItSo.xcodeproj/project.pbxproj index 4bf044ec6..e215a8e3e 100644 --- a/code/frontend/MakeItSo/MakeItSo.xcodeproj/project.pbxproj +++ b/code/frontend/MakeItSo/MakeItSo.xcodeproj/project.pbxproj @@ -3,128 +3,34 @@ archiveVersion = 1; classes = { }; - objectVersion = 55; + objectVersion = 56; objects = { /* Begin PBXBuildFile section */ - 881EF5BD272DC399004761E5 /* View+Focus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 881EF5BC272DC399004761E5 /* View+Focus.swift */; }; - 88700F74276B4DE10088F006 /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 88700F73276B4DE10088F006 /* FirebaseAnalytics */; }; - 88700F76276B4DE10088F006 /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 88700F75276B4DE10088F006 /* FirebaseAuth */; }; - 88700F78276B4DE10088F006 /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = 88700F77276B4DE10088F006 /* FirebaseFirestore */; }; - 88700F7A276B4DE10088F006 /* FirebaseFirestoreSwift-Beta in Frameworks */ = {isa = PBXBuildFile; productRef = 88700F79276B4DE10088F006 /* FirebaseFirestoreSwift-Beta */; }; - 88700F7D276B4FF90088F006 /* RemindersRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88700F7C276B4FF90088F006 /* RemindersRepository.swift */; }; - 88700F7E276B4FF90088F006 /* RemindersRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88700F7C276B4FF90088F006 /* RemindersRepository.swift */; }; - 88700F82276B517F0088F006 /* AuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88700F81276B517F0088F006 /* AuthenticationService.swift */; }; - 88700F83276B517F0088F006 /* AuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88700F81276B517F0088F006 /* AuthenticationService.swift */; }; - 88700F86276B52150088F006 /* Resolver in Frameworks */ = {isa = PBXBuildFile; productRef = 88700F85276B52150088F006 /* Resolver */; }; - 88700F88276B54810088F006 /* MakeItSoApp+Injection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88700F87276B54810088F006 /* MakeItSoApp+Injection.swift */; }; - 88700F89276B54810088F006 /* MakeItSoApp+Injection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88700F87276B54810088F006 /* MakeItSoApp+Injection.swift */; }; - 8873A5D2281BDF46000ED21B /* Reminder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FEECEF2727FEFF00ED368C /* Reminder.swift */; }; - 8873A5D3281BDF46000ED21B /* View+ConfirmationDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FA998C274D63A400670474 /* View+ConfirmationDialog.swift */; }; - 8873A5D4281BDF46000ED21B /* MakeItSoApp+Injection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88700F87276B54810088F006 /* MakeItSoApp+Injection.swift */; }; - 8873A5D5281BDF46000ED21B /* ReminderListRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FEECF927280F3D00ED368C /* ReminderListRowView.swift */; }; - 8873A5D6281BDF46000ED21B /* ReminderListRowViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A1B7422756541400DB0494 /* ReminderListRowViewModel.swift */; }; - 8873A5D7281BDF46000ED21B /* Font+Rounded.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88E25438275E494900341C5C /* Font+Rounded.swift */; }; - 8873A5D8281BDF46000ED21B /* View+InteractiveDismissDisable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FA99912750090200670474 /* View+InteractiveDismissDisable.swift */; }; - 8873A5D9281BDF46000ED21B /* EmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887B6FA9273ED4180028263D /* EmptyStateView.swift */; }; - 8873A5DA281BDF46000ED21B /* ReminderDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88E7B7BD274CF30A00AF477D /* ReminderDetailsView.swift */; }; - 8873A5DB281BDF46000ED21B /* ReminderDetailsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C30CD5274D1B4500E6694D /* ReminderDetailsViewModel.swift */; }; - 8873A5DC281BDF46000ED21B /* AuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88700F81276B517F0088F006 /* AuthenticationService.swift */; }; - 8873A5DD281BDF46000ED21B /* MakeItSoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FEECCA27275ABC00ED368C /* MakeItSoApp.swift */; }; - 8873A5DE281BDF46000ED21B /* View+Focus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 881EF5BC272DC399004761E5 /* View+Focus.swift */; }; - 8873A5DF281BDF46000ED21B /* RemindersRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88700F7C276B4FF90088F006 /* RemindersRepository.swift */; }; - 8873A5E0281BDF46000ED21B /* RemindersListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FEECF22728044100ED368C /* RemindersListView.swift */; }; - 8873A5E1281BDF46000ED21B /* RemindersListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FEECF62728072D00ED368C /* RemindersListViewModel.swift */; }; - 8873A5E3281BDF46000ED21B /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 8873A5CA281BDF46000ED21B /* FirebaseAnalytics */; }; - 8873A5E4281BDF46000ED21B /* FirebaseFirestoreSwift-Beta in Frameworks */ = {isa = PBXBuildFile; productRef = 8873A5CE281BDF46000ED21B /* FirebaseFirestoreSwift-Beta */; }; - 8873A5E5281BDF46000ED21B /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 8873A5CC281BDF46000ED21B /* FirebaseAuth */; }; - 8873A5E6281BDF46000ED21B /* Resolver in Frameworks */ = {isa = PBXBuildFile; productRef = 8873A5CF281BDF46000ED21B /* Resolver */; }; - 8873A5E7281BDF46000ED21B /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = 8873A5CD281BDF46000ED21B /* FirebaseFirestore */; }; - 8873A5E9281BDF46000ED21B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 88FEECCC27275ABD00ED368C /* Assets.xcassets */; }; - 8873A5F3281BE353000ED21B /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8873A5F2281BE353000ED21B /* GoogleService-Info.plist */; }; - 8873A5F8281BE3F0000ED21B /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8873A5F7281BE3F0000ED21B /* GoogleService-Info.plist */; }; - 8873A5F9281BE3F0000ED21B /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8873A5F7281BE3F0000ED21B /* GoogleService-Info.plist */; }; - 8873A609281BEEAF000ED21B /* KeychainAccessGroupHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8873A608281BEEAF000ED21B /* KeychainAccessGroupHelper.swift */; }; - 8873A60A281BEEAF000ED21B /* KeychainAccessGroupHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8873A608281BEEAF000ED21B /* KeychainAccessGroupHelper.swift */; }; - 8873A60B281BEEAF000ED21B /* KeychainAccessGroupHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8873A608281BEEAF000ED21B /* KeychainAccessGroupHelper.swift */; }; - 887B6FAD273ED4180028263D /* EmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887B6FA9273ED4180028263D /* EmptyStateView.swift */; }; - 887B6FAE273ED4180028263D /* EmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887B6FA9273ED4180028263D /* EmptyStateView.swift */; }; - 88A1B7432756541400DB0494 /* ReminderListRowViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A1B7422756541400DB0494 /* ReminderListRowViewModel.swift */; }; - 88A1B7442756541400DB0494 /* ReminderListRowViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A1B7422756541400DB0494 /* ReminderListRowViewModel.swift */; }; - 88C30CD6274D1B4500E6694D /* ReminderDetailsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C30CD5274D1B4500E6694D /* ReminderDetailsViewModel.swift */; }; - 88C30CD7274D1B4500E6694D /* ReminderDetailsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C30CD5274D1B4500E6694D /* ReminderDetailsViewModel.swift */; }; - 88E25439275E494900341C5C /* Font+Rounded.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88E25438275E494900341C5C /* Font+Rounded.swift */; }; - 88E7B7BE274CF30A00AF477D /* ReminderDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88E7B7BD274CF30A00AF477D /* ReminderDetailsView.swift */; }; - 88E7B7BF274CF30A00AF477D /* ReminderDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88E7B7BD274CF30A00AF477D /* ReminderDetailsView.swift */; }; - 88FA998D274D63A400670474 /* View+ConfirmationDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FA998C274D63A400670474 /* View+ConfirmationDialog.swift */; }; - 88FA99922750090200670474 /* View+InteractiveDismissDisable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FA99912750090200670474 /* View+InteractiveDismissDisable.swift */; }; - 88FEECDA27275ABD00ED368C /* MakeItSoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FEECCA27275ABC00ED368C /* MakeItSoApp.swift */; }; - 88FEECDB27275ABD00ED368C /* MakeItSoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FEECCA27275ABC00ED368C /* MakeItSoApp.swift */; }; - 88FEECDE27275ABD00ED368C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 88FEECCC27275ABD00ED368C /* Assets.xcassets */; }; - 88FEECDF27275ABD00ED368C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 88FEECCC27275ABD00ED368C /* Assets.xcassets */; }; - 88FEECF02727FEFF00ED368C /* Reminder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FEECEF2727FEFF00ED368C /* Reminder.swift */; }; - 88FEECF12727FEFF00ED368C /* Reminder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FEECEF2727FEFF00ED368C /* Reminder.swift */; }; - 88FEECF32728044100ED368C /* RemindersListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FEECF22728044100ED368C /* RemindersListView.swift */; }; - 88FEECF42728044100ED368C /* RemindersListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FEECF22728044100ED368C /* RemindersListView.swift */; }; - 88FEECF72728072D00ED368C /* RemindersListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FEECF62728072D00ED368C /* RemindersListViewModel.swift */; }; - 88FEECF82728072D00ED368C /* RemindersListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FEECF62728072D00ED368C /* RemindersListViewModel.swift */; }; - 88FEECFA27280F3D00ED368C /* ReminderListRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FEECF927280F3D00ED368C /* ReminderListRowView.swift */; }; - 88FEECFB27280F3D00ED368C /* ReminderListRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FEECF927280F3D00ED368C /* ReminderListRowView.swift */; }; + 8842941329AFEEA8002B16B9 /* MakeItSoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842941229AFEEA8002B16B9 /* MakeItSoApp.swift */; }; + 8842941529AFEEA8002B16B9 /* RemindersListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842941429AFEEA8002B16B9 /* RemindersListView.swift */; }; + 8842941729AFEEA9002B16B9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8842941629AFEEA9002B16B9 /* Assets.xcassets */; }; + 8842941A29AFEEA9002B16B9 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8842941929AFEEA9002B16B9 /* Preview Assets.xcassets */; }; + 8842942529AFF792002B16B9 /* Reminder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842942429AFF792002B16B9 /* Reminder.swift */; }; + 8842942729B275B9002B16B9 /* AddReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842942629B275B9002B16B9 /* AddReminderView.swift */; }; + 886FAA722A1278FF004ACF43 /* ReminderListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886FAA712A1278FF004ACF43 /* ReminderListViewModel.swift */; }; + 88AE85682A12951B0040C93D /* MakeItSo.docc in Sources */ = {isa = PBXBuildFile; fileRef = 88AE85672A12951B0040C93D /* MakeItSo.docc */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 881EF5BC272DC399004761E5 /* View+Focus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Focus.swift"; sourceTree = ""; }; - 88700F7C276B4FF90088F006 /* RemindersRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemindersRepository.swift; sourceTree = ""; }; - 88700F81276B517F0088F006 /* AuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationService.swift; sourceTree = ""; }; - 88700F87276B54810088F006 /* MakeItSoApp+Injection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MakeItSoApp+Injection.swift"; sourceTree = ""; }; - 8873A5EE281BDF46000ED21B /* Make It So.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Make It So.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 8873A5F2281BE353000ED21B /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; - 8873A5F7281BE3F0000ED21B /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; - 8873A608281BEEAF000ED21B /* KeychainAccessGroupHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainAccessGroupHelper.swift; sourceTree = ""; }; - 887B6FA9273ED4180028263D /* EmptyStateView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyStateView.swift; sourceTree = ""; }; - 88A1B7422756541400DB0494 /* ReminderListRowViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReminderListRowViewModel.swift; sourceTree = ""; }; - 88C30CD5274D1B4500E6694D /* ReminderDetailsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReminderDetailsViewModel.swift; sourceTree = ""; }; - 88E25438275E494900341C5C /* Font+Rounded.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Font+Rounded.swift"; sourceTree = ""; }; - 88E7B7BD274CF30A00AF477D /* ReminderDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReminderDetailsView.swift; sourceTree = ""; }; - 88FA998C274D63A400670474 /* View+ConfirmationDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+ConfirmationDialog.swift"; sourceTree = ""; }; - 88FA99912750090200670474 /* View+InteractiveDismissDisable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+InteractiveDismissDisable.swift"; sourceTree = ""; }; - 88FEECCA27275ABC00ED368C /* MakeItSoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeItSoApp.swift; sourceTree = ""; }; - 88FEECCC27275ABD00ED368C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 88FEECD127275ABD00ED368C /* MakeItSo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MakeItSo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 88FEECD727275ABD00ED368C /* MakeItSo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MakeItSo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 88FEECD927275ABD00ED368C /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = ""; }; - 88FEECEF2727FEFF00ED368C /* Reminder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reminder.swift; sourceTree = ""; }; - 88FEECF22728044100ED368C /* RemindersListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemindersListView.swift; sourceTree = ""; }; - 88FEECF62728072D00ED368C /* RemindersListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemindersListViewModel.swift; sourceTree = ""; }; - 88FEECF927280F3D00ED368C /* ReminderListRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReminderListRowView.swift; sourceTree = ""; }; + 8842940F29AFEEA8002B16B9 /* MakeItSo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MakeItSo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 8842941229AFEEA8002B16B9 /* MakeItSoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeItSoApp.swift; sourceTree = ""; }; + 8842941429AFEEA8002B16B9 /* RemindersListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemindersListView.swift; sourceTree = ""; }; + 8842941629AFEEA9002B16B9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 8842941929AFEEA9002B16B9 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 8842942429AFF792002B16B9 /* Reminder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reminder.swift; sourceTree = ""; }; + 8842942629B275B9002B16B9 /* AddReminderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddReminderView.swift; sourceTree = ""; }; + 886FAA712A1278FF004ACF43 /* ReminderListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReminderListViewModel.swift; sourceTree = ""; }; + 88AE85672A12951B0040C93D /* MakeItSo.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = MakeItSo.docc; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 8873A5E2281BDF46000ED21B /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 8873A5E3281BDF46000ED21B /* FirebaseAnalytics in Frameworks */, - 8873A5E4281BDF46000ED21B /* FirebaseFirestoreSwift-Beta in Frameworks */, - 8873A5E5281BDF46000ED21B /* FirebaseAuth in Frameworks */, - 8873A5E6281BDF46000ED21B /* Resolver in Frameworks */, - 8873A5E7281BDF46000ED21B /* FirebaseFirestore in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 88FEECCE27275ABD00ED368C /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 88700F74276B4DE10088F006 /* FirebaseAnalytics in Frameworks */, - 88700F7A276B4DE10088F006 /* FirebaseFirestoreSwift-Beta in Frameworks */, - 88700F76276B4DE10088F006 /* FirebaseAuth in Frameworks */, - 88700F86276B52150088F006 /* Resolver in Frameworks */, - 88700F78276B4DE10088F006 /* FirebaseFirestore in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 88FEECD427275ABD00ED368C /* Frameworks */ = { + 8842940C29AFEEA8002B16B9 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( @@ -134,469 +40,174 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 881EF5BB272DC366004761E5 /* Extensions */ = { - isa = PBXGroup; - children = ( - 88E25438275E494900341C5C /* Font+Rounded.swift */, - 881EF5BC272DC399004761E5 /* View+Focus.swift */, - 88FA998C274D63A400670474 /* View+ConfirmationDialog.swift */, - 88FA99912750090200670474 /* View+InteractiveDismissDisable.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 88700F7B276B4F8F0088F006 /* Repositories */ = { - isa = PBXGroup; - children = ( - 88700F7C276B4FF90088F006 /* RemindersRepository.swift */, - ); - path = Repositories; - sourceTree = ""; - }; - 88700F7F276B514F0088F006 /* Authentication */ = { - isa = PBXGroup; - children = ( - 88700F80276B516F0088F006 /* Services */, - ); - path = Authentication; - sourceTree = ""; - }; - 88700F80276B516F0088F006 /* Services */ = { - isa = PBXGroup; - children = ( - 88700F81276B517F0088F006 /* AuthenticationService.swift */, - ); - path = Services; - sourceTree = ""; - }; - 8873A5C4281BDCB3000ED21B /* Configuration */ = { - isa = PBXGroup; - children = ( - 8873A5C5281BDCBC000ED21B /* Firebase */, - ); - path = Configuration; - sourceTree = ""; - }; - 8873A5C5281BDCBC000ED21B /* Firebase */ = { - isa = PBXGroup; - children = ( - 8873A5C7281BDCCC000ED21B /* Development */, - 8873A5C6281BDCC5000ED21B /* Production */, - ); - path = Firebase; - sourceTree = ""; - }; - 8873A5C6281BDCC5000ED21B /* Production */ = { - isa = PBXGroup; - children = ( - 8873A5F2281BE353000ED21B /* GoogleService-Info.plist */, - ); - path = Production; - sourceTree = ""; - }; - 8873A5C7281BDCCC000ED21B /* Development */ = { - isa = PBXGroup; - children = ( - 8873A5F7281BE3F0000ED21B /* GoogleService-Info.plist */, - ); - path = Development; - sourceTree = ""; - }; - 8873A5FE281BE78F000ED21B /* Utilities */ = { - isa = PBXGroup; - children = ( - 8873A608281BEEAF000ED21B /* KeychainAccessGroupHelper.swift */, - ); - path = Utilities; - sourceTree = ""; - }; - 887B6FA6273ED4180028263D /* Common */ = { - isa = PBXGroup; - children = ( - 887B6FA7273ED4180028263D /* Views */, - ); - path = Common; - sourceTree = ""; - }; - 887B6FA7273ED4180028263D /* Views */ = { - isa = PBXGroup; - children = ( - 887B6FA9273ED4180028263D /* EmptyStateView.swift */, - ); - path = Views; - sourceTree = ""; - }; - 88FEECC427275ABC00ED368C = { + 8842940629AFEEA8002B16B9 = { isa = PBXGroup; children = ( - 8873A5C4281BDCB3000ED21B /* Configuration */, - 88FEECC927275ABC00ED368C /* Shared */, - 88FEECD827275ABD00ED368C /* macOS */, - 88FEECD227275ABD00ED368C /* Products */, + 88AE85672A12951B0040C93D /* MakeItSo.docc */, + 8842941129AFEEA8002B16B9 /* MakeItSo */, + 8842941029AFEEA8002B16B9 /* Products */, ); sourceTree = ""; }; - 88FEECC927275ABC00ED368C /* Shared */ = { + 8842941029AFEEA8002B16B9 /* Products */ = { isa = PBXGroup; children = ( - 8873A5FE281BE78F000ED21B /* Utilities */, - 887B6FA6273ED4180028263D /* Common */, - 881EF5BB272DC366004761E5 /* Extensions */, - 88FEECEB2727FEC100ED368C /* Features */, - 88FEECCA27275ABC00ED368C /* MakeItSoApp.swift */, - 88700F87276B54810088F006 /* MakeItSoApp+Injection.swift */, - 88FEECCC27275ABD00ED368C /* Assets.xcassets */, + 8842940F29AFEEA8002B16B9 /* MakeItSo.app */, ); - path = Shared; + name = Products; sourceTree = ""; }; - 88FEECD227275ABD00ED368C /* Products */ = { + 8842941129AFEEA8002B16B9 /* MakeItSo */ = { isa = PBXGroup; children = ( - 88FEECD127275ABD00ED368C /* MakeItSo.app */, - 88FEECD727275ABD00ED368C /* MakeItSo.app */, - 8873A5EE281BDF46000ED21B /* Make It So.app */, + 886FAA6C2A127422004ACF43 /* Features */, + 8842941229AFEEA8002B16B9 /* MakeItSoApp.swift */, + 8842941629AFEEA9002B16B9 /* Assets.xcassets */, + 8842941829AFEEA9002B16B9 /* Preview Content */, ); - name = Products; + path = MakeItSo; sourceTree = ""; }; - 88FEECD827275ABD00ED368C /* macOS */ = { + 8842941829AFEEA9002B16B9 /* Preview Content */ = { isa = PBXGroup; children = ( - 88FEECD927275ABD00ED368C /* macOS.entitlements */, + 8842941929AFEEA9002B16B9 /* Preview Assets.xcassets */, ); - path = macOS; + path = "Preview Content"; sourceTree = ""; }; - 88FEECEB2727FEC100ED368C /* Features */ = { + 886FAA6C2A127422004ACF43 /* Features */ = { isa = PBXGroup; children = ( - 88700F7F276B514F0088F006 /* Authentication */, - 88FEECEC2727FECA00ED368C /* ReminderList */, + 886FAA6D2A12742C004ACF43 /* Reminders */, ); path = Features; sourceTree = ""; }; - 88FEECEC2727FECA00ED368C /* ReminderList */ = { + 886FAA6D2A12742C004ACF43 /* Reminders */ = { isa = PBXGroup; children = ( - 88700F7B276B4F8F0088F006 /* Repositories */, - 88FEECED2727FED500ED368C /* Models */, - 88FEECF52728070600ED368C /* ViewModels */, - 88FEECEE2727FEDE00ED368C /* Views */, + 886FAA6E2A12743E004ACF43 /* Models */, + 886FAA6F2A127444004ACF43 /* ViewModels */, + 886FAA702A12744A004ACF43 /* Views */, ); - path = ReminderList; + path = Reminders; sourceTree = ""; }; - 88FEECED2727FED500ED368C /* Models */ = { + 886FAA6E2A12743E004ACF43 /* Models */ = { isa = PBXGroup; children = ( - 88FEECEF2727FEFF00ED368C /* Reminder.swift */, + 8842942429AFF792002B16B9 /* Reminder.swift */, ); path = Models; sourceTree = ""; }; - 88FEECEE2727FEDE00ED368C /* Views */ = { + 886FAA6F2A127444004ACF43 /* ViewModels */ = { isa = PBXGroup; children = ( - 88FEECF22728044100ED368C /* RemindersListView.swift */, - 88FEECF927280F3D00ED368C /* ReminderListRowView.swift */, - 88E7B7BD274CF30A00AF477D /* ReminderDetailsView.swift */, + 886FAA712A1278FF004ACF43 /* ReminderListViewModel.swift */, ); - path = Views; + path = ViewModels; sourceTree = ""; }; - 88FEECF52728070600ED368C /* ViewModels */ = { + 886FAA702A12744A004ACF43 /* Views */ = { isa = PBXGroup; children = ( - 88FEECF62728072D00ED368C /* RemindersListViewModel.swift */, - 88C30CD5274D1B4500E6694D /* ReminderDetailsViewModel.swift */, - 88A1B7422756541400DB0494 /* ReminderListRowViewModel.swift */, + 8842941429AFEEA8002B16B9 /* RemindersListView.swift */, + 8842942629B275B9002B16B9 /* AddReminderView.swift */, ); - path = ViewModels; + path = Views; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 8873A5C9281BDF46000ED21B /* MakeItSo (iOS) PROD */ = { - isa = PBXNativeTarget; - buildConfigurationList = 8873A5EB281BDF46000ED21B /* Build configuration list for PBXNativeTarget "MakeItSo (iOS) PROD" */; - buildPhases = ( - 8873A5D1281BDF46000ED21B /* Sources */, - 8873A5E2281BDF46000ED21B /* Frameworks */, - 8873A5E8281BDF46000ED21B /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "MakeItSo (iOS) PROD"; - packageProductDependencies = ( - 8873A5CA281BDF46000ED21B /* FirebaseAnalytics */, - 8873A5CC281BDF46000ED21B /* FirebaseAuth */, - 8873A5CD281BDF46000ED21B /* FirebaseFirestore */, - 8873A5CE281BDF46000ED21B /* FirebaseFirestoreSwift-Beta */, - 8873A5CF281BDF46000ED21B /* Resolver */, - ); - productName = "MakeItSo (iOS)"; - productReference = 8873A5EE281BDF46000ED21B /* Make It So.app */; - productType = "com.apple.product-type.application"; - }; - 88FEECD027275ABD00ED368C /* MakeItSo (iOS) DEV */ = { - isa = PBXNativeTarget; - buildConfigurationList = 88FEECE227275ABD00ED368C /* Build configuration list for PBXNativeTarget "MakeItSo (iOS) DEV" */; - buildPhases = ( - 88FEECCD27275ABD00ED368C /* Sources */, - 88FEECCE27275ABD00ED368C /* Frameworks */, - 88FEECCF27275ABD00ED368C /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "MakeItSo (iOS) DEV"; - packageProductDependencies = ( - 88700F73276B4DE10088F006 /* FirebaseAnalytics */, - 88700F75276B4DE10088F006 /* FirebaseAuth */, - 88700F77276B4DE10088F006 /* FirebaseFirestore */, - 88700F79276B4DE10088F006 /* FirebaseFirestoreSwift-Beta */, - 88700F85276B52150088F006 /* Resolver */, - ); - productName = "MakeItSo (iOS)"; - productReference = 88FEECD127275ABD00ED368C /* MakeItSo.app */; - productType = "com.apple.product-type.application"; - }; - 88FEECD627275ABD00ED368C /* MakeItSo (macOS) DEV */ = { + 8842940E29AFEEA8002B16B9 /* MakeItSo */ = { isa = PBXNativeTarget; - buildConfigurationList = 88FEECE527275ABD00ED368C /* Build configuration list for PBXNativeTarget "MakeItSo (macOS) DEV" */; + buildConfigurationList = 8842941D29AFEEA9002B16B9 /* Build configuration list for PBXNativeTarget "MakeItSo" */; buildPhases = ( - 88FEECD327275ABD00ED368C /* Sources */, - 88FEECD427275ABD00ED368C /* Frameworks */, - 88FEECD527275ABD00ED368C /* Resources */, + 8842940B29AFEEA8002B16B9 /* Sources */, + 8842940C29AFEEA8002B16B9 /* Frameworks */, + 8842940D29AFEEA8002B16B9 /* Resources */, ); buildRules = ( ); dependencies = ( ); - name = "MakeItSo (macOS) DEV"; - productName = "MakeItSo (macOS)"; - productReference = 88FEECD727275ABD00ED368C /* MakeItSo.app */; + name = MakeItSo; + productName = MakeItSo; + productReference = 8842940F29AFEEA8002B16B9 /* MakeItSo.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ - 88FEECC527275ABC00ED368C /* Project object */ = { + 8842940729AFEEA8002B16B9 /* Project object */ = { isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1310; - LastUpgradeCheck = 1310; + LastSwiftUpdateCheck = 1420; + LastUpgradeCheck = 1420; TargetAttributes = { - 88FEECD027275ABD00ED368C = { - CreatedOnToolsVersion = 13.1; - }; - 88FEECD627275ABD00ED368C = { - CreatedOnToolsVersion = 13.1; + 8842940E29AFEEA8002B16B9 = { + CreatedOnToolsVersion = 14.2; }; }; }; - buildConfigurationList = 88FEECC827275ABC00ED368C /* Build configuration list for PBXProject "MakeItSo" */; - compatibilityVersion = "Xcode 13.0"; + buildConfigurationList = 8842940A29AFEEA8002B16B9 /* Build configuration list for PBXProject "MakeItSo" */; + compatibilityVersion = "Xcode 14.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); - mainGroup = 88FEECC427275ABC00ED368C; - packageReferences = ( - 88700F72276B4DE10088F006 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, - 88700F84276B52150088F006 /* XCRemoteSwiftPackageReference "Resolver" */, - ); - productRefGroup = 88FEECD227275ABD00ED368C /* Products */; + mainGroup = 8842940629AFEEA8002B16B9; + productRefGroup = 8842941029AFEEA8002B16B9 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( - 88FEECD027275ABD00ED368C /* MakeItSo (iOS) DEV */, - 88FEECD627275ABD00ED368C /* MakeItSo (macOS) DEV */, - 8873A5C9281BDF46000ED21B /* MakeItSo (iOS) PROD */, + 8842940E29AFEEA8002B16B9 /* MakeItSo */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 8873A5E8281BDF46000ED21B /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 8873A5E9281BDF46000ED21B /* Assets.xcassets in Resources */, - 8873A5F3281BE353000ED21B /* GoogleService-Info.plist in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 88FEECCF27275ABD00ED368C /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 88FEECDE27275ABD00ED368C /* Assets.xcassets in Resources */, - 8873A5F8281BE3F0000ED21B /* GoogleService-Info.plist in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 88FEECD527275ABD00ED368C /* Resources */ = { + 8842940D29AFEEA8002B16B9 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 88FEECDF27275ABD00ED368C /* Assets.xcassets in Resources */, - 8873A5F9281BE3F0000ED21B /* GoogleService-Info.plist in Resources */, + 8842941A29AFEEA9002B16B9 /* Preview Assets.xcassets in Resources */, + 8842941729AFEEA9002B16B9 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 8873A5D1281BDF46000ED21B /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 8873A5D2281BDF46000ED21B /* Reminder.swift in Sources */, - 8873A5D3281BDF46000ED21B /* View+ConfirmationDialog.swift in Sources */, - 8873A5D4281BDF46000ED21B /* MakeItSoApp+Injection.swift in Sources */, - 8873A5D5281BDF46000ED21B /* ReminderListRowView.swift in Sources */, - 8873A5D6281BDF46000ED21B /* ReminderListRowViewModel.swift in Sources */, - 8873A5D7281BDF46000ED21B /* Font+Rounded.swift in Sources */, - 8873A5D8281BDF46000ED21B /* View+InteractiveDismissDisable.swift in Sources */, - 8873A60B281BEEAF000ED21B /* KeychainAccessGroupHelper.swift in Sources */, - 8873A5D9281BDF46000ED21B /* EmptyStateView.swift in Sources */, - 8873A5DA281BDF46000ED21B /* ReminderDetailsView.swift in Sources */, - 8873A5DB281BDF46000ED21B /* ReminderDetailsViewModel.swift in Sources */, - 8873A5DC281BDF46000ED21B /* AuthenticationService.swift in Sources */, - 8873A5DD281BDF46000ED21B /* MakeItSoApp.swift in Sources */, - 8873A5DE281BDF46000ED21B /* View+Focus.swift in Sources */, - 8873A5DF281BDF46000ED21B /* RemindersRepository.swift in Sources */, - 8873A5E0281BDF46000ED21B /* RemindersListView.swift in Sources */, - 8873A5E1281BDF46000ED21B /* RemindersListViewModel.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 88FEECCD27275ABD00ED368C /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 88FEECF02727FEFF00ED368C /* Reminder.swift in Sources */, - 88FA998D274D63A400670474 /* View+ConfirmationDialog.swift in Sources */, - 88700F88276B54810088F006 /* MakeItSoApp+Injection.swift in Sources */, - 88FEECFA27280F3D00ED368C /* ReminderListRowView.swift in Sources */, - 88A1B7432756541400DB0494 /* ReminderListRowViewModel.swift in Sources */, - 88E25439275E494900341C5C /* Font+Rounded.swift in Sources */, - 88FA99922750090200670474 /* View+InteractiveDismissDisable.swift in Sources */, - 8873A609281BEEAF000ED21B /* KeychainAccessGroupHelper.swift in Sources */, - 887B6FAD273ED4180028263D /* EmptyStateView.swift in Sources */, - 88E7B7BE274CF30A00AF477D /* ReminderDetailsView.swift in Sources */, - 88C30CD6274D1B4500E6694D /* ReminderDetailsViewModel.swift in Sources */, - 88700F82276B517F0088F006 /* AuthenticationService.swift in Sources */, - 88FEECDA27275ABD00ED368C /* MakeItSoApp.swift in Sources */, - 881EF5BD272DC399004761E5 /* View+Focus.swift in Sources */, - 88700F7D276B4FF90088F006 /* RemindersRepository.swift in Sources */, - 88FEECF32728044100ED368C /* RemindersListView.swift in Sources */, - 88FEECF72728072D00ED368C /* RemindersListViewModel.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 88FEECD327275ABD00ED368C /* Sources */ = { + 8842940B29AFEEA8002B16B9 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 88FEECF12727FEFF00ED368C /* Reminder.swift in Sources */, - 88700F7E276B4FF90088F006 /* RemindersRepository.swift in Sources */, - 88700F89276B54810088F006 /* MakeItSoApp+Injection.swift in Sources */, - 88C30CD7274D1B4500E6694D /* ReminderDetailsViewModel.swift in Sources */, - 88FEECFB27280F3D00ED368C /* ReminderListRowView.swift in Sources */, - 88700F83276B517F0088F006 /* AuthenticationService.swift in Sources */, - 88FEECDB27275ABD00ED368C /* MakeItSoApp.swift in Sources */, - 88FEECF42728044100ED368C /* RemindersListView.swift in Sources */, - 88FEECF82728072D00ED368C /* RemindersListViewModel.swift in Sources */, - 88A1B7442756541400DB0494 /* ReminderListRowViewModel.swift in Sources */, - 8873A60A281BEEAF000ED21B /* KeychainAccessGroupHelper.swift in Sources */, - 887B6FAE273ED4180028263D /* EmptyStateView.swift in Sources */, - 88E7B7BF274CF30A00AF477D /* ReminderDetailsView.swift in Sources */, + 8842942529AFF792002B16B9 /* Reminder.swift in Sources */, + 88AE85682A12951B0040C93D /* MakeItSo.docc in Sources */, + 8842941529AFEEA8002B16B9 /* RemindersListView.swift in Sources */, + 886FAA722A1278FF004ACF43 /* ReminderListViewModel.swift in Sources */, + 8842942729B275B9002B16B9 /* AddReminderView.swift in Sources */, + 8842941329AFEEA8002B16B9 /* MakeItSoApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ - 8873A5EC281BDF46000ED21B /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-Prod"; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = YGAZHQXHH4; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchScreen_Generation = YES; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.peterfriese.MakeItSo.prod; - PRODUCT_NAME = "Make It So"; - SDKROOT = iphoneos; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 8873A5ED281BDF46000ED21B /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-Prod"; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = YGAZHQXHH4; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchScreen_Generation = YES; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.peterfriese.MakeItSo.prod; - PRODUCT_NAME = "Make It So"; - SDKROOT = iphoneos; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 88FEECE027275ABD00ED368C /* Debug */ = { + 8842941B29AFEEA9002B16B9 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CLANG_CXX_LIBRARY = "libc++"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; @@ -640,22 +251,23 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; - 88FEECE127275ABD00ED368C /* Release */ = { + 8842941C29AFEEA9002B16B9 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CLANG_CXX_LIBRARY = "libc++"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; @@ -693,22 +305,25 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; + SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; }; name = Release; }; - 88FEECE327275ABD00ED368C /* Debug */ = { + 8842941E29AFEEA9002B16B9 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-Dev"; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = YGAZHQXHH4; + DEVELOPMENT_ASSET_PATHS = "\"MakeItSo/Preview Content\""; + DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; @@ -716,30 +331,28 @@ INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.peterfriese.MakeItSo.dev; - PRODUCT_NAME = MakeItSo; - SDKROOT = iphoneos; + PRODUCT_BUNDLE_IDENTIFIER = com.example.MakeItSo; + PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; - 88FEECE427275ABD00ED368C /* Release */ = { + 8842941F29AFEEA9002B16B9 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-Dev"; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = YGAZHQXHH4; + DEVELOPMENT_ASSET_PATHS = "\"MakeItSo/Preview Content\""; + DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; @@ -747,206 +360,41 @@ INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.peterfriese.MakeItSo.dev; - PRODUCT_NAME = MakeItSo; - SDKROOT = iphoneos; + PRODUCT_BUNDLE_IDENTIFIER = com.example.MakeItSo; + PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 88FEECE627275ABD00ED368C /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-Dev"; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = YGAZHQXHH4; - ENABLE_HARDENED_RUNTIME = YES; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.peterfriese.MakeItSo.dev; - PRODUCT_NAME = MakeItSo; - SDKROOT = macosx; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 88FEECE727275ABD00ED368C /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-Dev"; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = YGAZHQXHH4; - ENABLE_HARDENED_RUNTIME = YES; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.peterfriese.MakeItSo.dev; - PRODUCT_NAME = MakeItSo; - SDKROOT = macosx; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 8873A5EB281BDF46000ED21B /* Build configuration list for PBXNativeTarget "MakeItSo (iOS) PROD" */ = { + 8842940A29AFEEA8002B16B9 /* Build configuration list for PBXProject "MakeItSo" */ = { isa = XCConfigurationList; buildConfigurations = ( - 8873A5EC281BDF46000ED21B /* Debug */, - 8873A5ED281BDF46000ED21B /* Release */, + 8842941B29AFEEA9002B16B9 /* Debug */, + 8842941C29AFEEA9002B16B9 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 88FEECC827275ABC00ED368C /* Build configuration list for PBXProject "MakeItSo" */ = { + 8842941D29AFEEA9002B16B9 /* Build configuration list for PBXNativeTarget "MakeItSo" */ = { isa = XCConfigurationList; buildConfigurations = ( - 88FEECE027275ABD00ED368C /* Debug */, - 88FEECE127275ABD00ED368C /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 88FEECE227275ABD00ED368C /* Build configuration list for PBXNativeTarget "MakeItSo (iOS) DEV" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 88FEECE327275ABD00ED368C /* Debug */, - 88FEECE427275ABD00ED368C /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 88FEECE527275ABD00ED368C /* Build configuration list for PBXNativeTarget "MakeItSo (macOS) DEV" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 88FEECE627275ABD00ED368C /* Debug */, - 88FEECE727275ABD00ED368C /* Release */, + 8842941E29AFEEA9002B16B9 /* Debug */, + 8842941F29AFEEA9002B16B9 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - 88700F72276B4DE10088F006 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 8.0.0; - }; - }; - 88700F84276B52150088F006 /* XCRemoteSwiftPackageReference "Resolver" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/hmlongco/Resolver"; - requirement = { - branch = master; - kind = branch; - }; - }; - 8873A5CB281BDF46000ED21B /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 8.0.0; - }; - }; - 8873A5D0281BDF46000ED21B /* XCRemoteSwiftPackageReference "Resolver" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/hmlongco/Resolver"; - requirement = { - branch = master; - kind = branch; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 88700F73276B4DE10088F006 /* FirebaseAnalytics */ = { - isa = XCSwiftPackageProductDependency; - package = 88700F72276B4DE10088F006 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseAnalytics; - }; - 88700F75276B4DE10088F006 /* FirebaseAuth */ = { - isa = XCSwiftPackageProductDependency; - package = 88700F72276B4DE10088F006 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseAuth; - }; - 88700F77276B4DE10088F006 /* FirebaseFirestore */ = { - isa = XCSwiftPackageProductDependency; - package = 88700F72276B4DE10088F006 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseFirestore; - }; - 88700F79276B4DE10088F006 /* FirebaseFirestoreSwift-Beta */ = { - isa = XCSwiftPackageProductDependency; - package = 88700F72276B4DE10088F006 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = "FirebaseFirestoreSwift-Beta"; - }; - 88700F85276B52150088F006 /* Resolver */ = { - isa = XCSwiftPackageProductDependency; - package = 88700F84276B52150088F006 /* XCRemoteSwiftPackageReference "Resolver" */; - productName = Resolver; - }; - 8873A5CA281BDF46000ED21B /* FirebaseAnalytics */ = { - isa = XCSwiftPackageProductDependency; - package = 8873A5CB281BDF46000ED21B /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseAnalytics; - }; - 8873A5CC281BDF46000ED21B /* FirebaseAuth */ = { - isa = XCSwiftPackageProductDependency; - package = 8873A5CB281BDF46000ED21B /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseAuth; - }; - 8873A5CD281BDF46000ED21B /* FirebaseFirestore */ = { - isa = XCSwiftPackageProductDependency; - package = 8873A5CB281BDF46000ED21B /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseFirestore; - }; - 8873A5CE281BDF46000ED21B /* FirebaseFirestoreSwift-Beta */ = { - isa = XCSwiftPackageProductDependency; - package = 8873A5CB281BDF46000ED21B /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = "FirebaseFirestoreSwift-Beta"; - }; - 8873A5CF281BDF46000ED21B /* Resolver */ = { - isa = XCSwiftPackageProductDependency; - package = 8873A5D0281BDF46000ED21B /* XCRemoteSwiftPackageReference "Resolver" */; - productName = Resolver; - }; -/* End XCSwiftPackageProductDependency section */ }; - rootObject = 88FEECC527275ABC00ED368C /* Project object */; + rootObject = 8842940729AFEEA8002B16B9 /* Project object */; } diff --git a/code/frontend/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/xcshareddata/IDETemplateMacros.plist b/code/frontend/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/xcshareddata/IDETemplateMacros.plist deleted file mode 100644 index 2fa16a1a5..000000000 --- a/code/frontend/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/xcshareddata/IDETemplateMacros.plist +++ /dev/null @@ -1,27 +0,0 @@ - - - - - COPYRIGHT - Copyright © 2021 Google LLC. All rights reserved. - FILEHEADER - -// ___FILENAME___ -// ___PACKAGENAME___ -// -// Created by ___FULLUSERNAME___ on ___DATE___. -// ___COPYRIGHT___ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - diff --git a/code/frontend/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/code/frontend/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index f2c0f241e..000000000 --- a/code/frontend/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,122 +0,0 @@ -{ - "pins" : [ - { - "identity" : "abseil-cpp-swiftpm", - "kind" : "remoteSourceControl", - "location" : "https://github.com/firebase/abseil-cpp-SwiftPM.git", - "state" : { - "revision" : "d302de612e3d57c6f4afaf087da18fba8eac72a7", - "version" : "0.20220203.1" - } - }, - { - "identity" : "boringssl-swiftpm", - "kind" : "remoteSourceControl", - "location" : "https://github.com/firebase/boringssl-SwiftPM.git", - "state" : { - "revision" : "79db6516894a932d0ddaff3b05b9da1e4f6c4069", - "version" : "0.9.0" - } - }, - { - "identity" : "firebase-ios-sdk", - "kind" : "remoteSourceControl", - "location" : "https://github.com/firebase/firebase-ios-sdk", - "state" : { - "revision" : "111d8d6ad1a1afd6c8e9561d26e55ab1e74fcb42", - "version" : "8.15.0" - } - }, - { - "identity" : "googleappmeasurement", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/GoogleAppMeasurement.git", - "state" : { - "revision" : "ef819db8c58657a6ca367322e73f3b6322afe0a2", - "version" : "8.15.0" - } - }, - { - "identity" : "googledatatransport", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/GoogleDataTransport.git", - "state" : { - "revision" : "15ccdfd25ac55b9239b82809531ff26605e7556e", - "version" : "9.1.2" - } - }, - { - "identity" : "googleutilities", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/GoogleUtilities.git", - "state" : { - "revision" : "f4abe56ce62a779e64b525eb133c8fc2a84bbc1f", - "version" : "7.7.1" - } - }, - { - "identity" : "grpc-ios", - "kind" : "remoteSourceControl", - "location" : "https://github.com/grpc/grpc-ios.git", - "state" : { - "revision" : "abd2d5a4347efa0454606a788678a5d8ec223738", - "version" : "1.44.0-grpc" - } - }, - { - "identity" : "gtm-session-fetcher", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/gtm-session-fetcher.git", - "state" : { - "revision" : "4e9bbf2808b8fee444e84a48f5f3c12641987d3e", - "version" : "1.7.2" - } - }, - { - "identity" : "leveldb", - "kind" : "remoteSourceControl", - "location" : "https://github.com/firebase/leveldb.git", - "state" : { - "revision" : "0706abcc6b0bd9cedfbb015ba840e4a780b5159b", - "version" : "1.22.2" - } - }, - { - "identity" : "nanopb", - "kind" : "remoteSourceControl", - "location" : "https://github.com/firebase/nanopb.git", - "state" : { - "revision" : "7ee9ef9f627d85cbe1b8c4f49a3ed26eed216c77", - "version" : "2.30908.0" - } - }, - { - "identity" : "promises", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/promises.git", - "state" : { - "revision" : "46c1e6b5ac09d8f82c991061c659f67e573d425d", - "version" : "2.1.0" - } - }, - { - "identity" : "resolver", - "kind" : "remoteSourceControl", - "location" : "https://github.com/hmlongco/Resolver", - "state" : { - "branch" : "master", - "revision" : "bd565aae33a08dd4e10747bfb98e2bf8a63bfa28" - } - }, - { - "identity" : "swift-protobuf", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-protobuf.git", - "state" : { - "revision" : "e1499bc69b9040b29184f7f2996f7bab467c1639", - "version" : "1.19.0" - } - } - ], - "version" : 2 -} diff --git a/code/frontend/MakeItSo/MakeItSo.xcodeproj/xcshareddata/xcschemes/MakeItSo (iOS) DEV.xcscheme b/code/frontend/MakeItSo/MakeItSo.xcodeproj/xcshareddata/xcschemes/MakeItSo (iOS) DEV.xcscheme deleted file mode 100644 index 1af7fad33..000000000 --- a/code/frontend/MakeItSo/MakeItSo.xcodeproj/xcshareddata/xcschemes/MakeItSo (iOS) DEV.xcscheme +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/frontend/MakeItSo/MakeItSo.xcodeproj/xcshareddata/xcschemes/MakeItSo (iOS) PROD.xcscheme b/code/frontend/MakeItSo/MakeItSo.xcodeproj/xcshareddata/xcschemes/MakeItSo (iOS) PROD.xcscheme deleted file mode 100644 index 8cca6e13b..000000000 --- a/code/frontend/MakeItSo/MakeItSo.xcodeproj/xcshareddata/xcschemes/MakeItSo (iOS) PROD.xcscheme +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/frontend/MakeItSo/MakeItSo.xcodeproj/xcshareddata/xcschemes/MakeItSo (macOS) DEV.xcscheme b/code/frontend/MakeItSo/MakeItSo.xcodeproj/xcshareddata/xcschemes/MakeItSo (macOS) DEV.xcscheme deleted file mode 100644 index eb242f4f3..000000000 --- a/code/frontend/MakeItSo/MakeItSo.xcodeproj/xcshareddata/xcschemes/MakeItSo (macOS) DEV.xcscheme +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AccentColor.colorset/Contents.json b/code/frontend/MakeItSo/MakeItSo/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from code/frontend/MakeItSo/Shared/Assets.xcassets/AccentColor.colorset/Contents.json rename to code/frontend/MakeItSo/MakeItSo/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/code/frontend/MakeItSo/MakeItSo/Assets.xcassets/AppIcon.appiconset/Contents.json b/code/frontend/MakeItSo/MakeItSo/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..13613e3ee --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/Contents.json b/code/frontend/MakeItSo/MakeItSo/Assets.xcassets/Contents.json similarity index 100% rename from code/frontend/MakeItSo/Shared/Assets.xcassets/Contents.json rename to code/frontend/MakeItSo/MakeItSo/Assets.xcassets/Contents.json diff --git a/code/frontend/MakeItSo/MakeItSo/Features/Reminders/Models/Reminder.swift b/code/frontend/MakeItSo/MakeItSo/Features/Reminders/Models/Reminder.swift new file mode 100644 index 000000000..54734c9fd --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo/Features/Reminders/Models/Reminder.swift @@ -0,0 +1,34 @@ +// +// Reminder.swift +// MakeItSo +// +// Created by Peter Friese on 01.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +struct Reminder: Identifiable { + let id = UUID() + var title: String + var isCompleted = false +} + +extension Reminder { + static let samples = [ + Reminder(title: "Build sample app", isCompleted: true), + Reminder(title: "Create tutorial"), + Reminder(title: "???"), + Reminder(title: "PROFIT!"), + ] +} diff --git a/code/frontend/MakeItSo/MakeItSo/Features/Reminders/ViewModels/ReminderListViewModel.swift b/code/frontend/MakeItSo/MakeItSo/Features/Reminders/ViewModels/ReminderListViewModel.swift new file mode 100644 index 000000000..0656656e9 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo/Features/Reminders/ViewModels/ReminderListViewModel.swift @@ -0,0 +1,34 @@ +// +// ReminderListViewModel.swift +// MakeItSo +// +// Created by Peter Friese on 15.05.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +class RemindersListViewModel: ObservableObject { + @Published + var reminders = Reminder.samples + + func addReminder(_ reminder: Reminder) { + reminders.append(reminder) + } + + func toggleCompleted(_ reminder: Reminder) { + if let index = reminders.firstIndex(where: { $0.id == reminder.id} ) { + reminders[index].isCompleted.toggle() + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo/Features/Reminders/Views/AddReminderView.swift b/code/frontend/MakeItSo/MakeItSo/Features/Reminders/Views/AddReminderView.swift new file mode 100644 index 000000000..5197fc71c --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo/Features/Reminders/Views/AddReminderView.swift @@ -0,0 +1,80 @@ +// +// AddReminderView.swift +// MakeItSo +// +// Created by Peter Friese on 03.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftUI + +struct AddReminderView: View { + enum FocusableField: Hashable { + case title + } + + @FocusState + private var focusedField: FocusableField? + + @State + private var reminder = Reminder(title: "") + + @Environment(\.dismiss) + private var dismiss + + let onCommit: (_ reminder: Reminder) -> Void + + private func commit() { + onCommit(reminder) + dismiss() + } + + private func cancel() { + dismiss() + } + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + .focused($focusedField, equals: .title) + } + .navigationTitle("New Reminder") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .cancellationAction) { + Button(action: cancel) { + Text("Cancel") + } + } + ToolbarItem(placement: .confirmationAction) { + Button(action: commit) { + Text("Add") + } + .disabled(reminder.title.isEmpty) + } + } + .onAppear { + focusedField = .title + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo/Features/Reminders/Views/RemindersListView.swift b/code/frontend/MakeItSo/MakeItSo/Features/Reminders/Views/RemindersListView.swift new file mode 100644 index 000000000..c5596c929 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo/Features/Reminders/Views/RemindersListView.swift @@ -0,0 +1,72 @@ +// +// ContentView.swift +// MakeItSo +// +// Created by Peter Friese on 01.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftUI + +struct RemindersListView: View { + @StateObject + private var viewModel = RemindersListViewModel() + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($viewModel.reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + viewModel.toggleCompleted(reminder) + } + Text(reminder.title) + } + } + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + Button(action: presentAddReminderView) { + HStack { + Image(systemName: "plus.circle.fill") + Text("New Reminder") + } + } + Spacer() + } + } + .sheet(isPresented: $isAddReminderDialogPresented) { + AddReminderView { reminder in + viewModel.addReminder(reminder) + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + NavigationStack { + RemindersListView() + .navigationTitle("Reminders") + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo/MakeItSoApp.swift b/code/frontend/MakeItSo/MakeItSo/MakeItSoApp.swift new file mode 100644 index 000000000..921abac96 --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo/MakeItSoApp.swift @@ -0,0 +1,31 @@ +// +// MakeItSoApp.swift +// MakeItSo +// +// Created by Peter Friese on 01.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftUI + +@main +struct MakeItSoApp: App { + var body: some Scene { + WindowGroup { + NavigationStack { + RemindersListView() + .navigationTitle("Reminders") + } + } + } +} diff --git a/code/frontend/MakeItSo/MakeItSo/Preview Content/Preview Assets.xcassets/Contents.json b/code/frontend/MakeItSo/MakeItSo/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/code/frontend/MakeItSo/MakeItSo/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/Contents.json b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/Contents.json deleted file mode 100644 index dfcf46615..000000000 --- a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/Contents.json +++ /dev/null @@ -1,176 +0,0 @@ -{ - "images" : [ - { - "filename" : "notification40.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "filename" : "notification60.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "filename" : "settings58.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "filename" : "settings87.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "filename" : "spotlight80.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "filename" : "spotlight120.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "filename" : "iphone120.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "filename" : "iphone180.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "filename" : "ipadNotification20.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "filename" : "ipadNotification40.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "filename" : "ipadSettings29.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "filename" : "ipadSettings58.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "filename" : "ipadSpotlight40.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "40x40" - }, - { - "filename" : "ipadSpotlight80.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "40x40" - }, - { - "filename" : "ipad76.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" - }, - { - "filename" : "ipad152.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "76x76" - }, - { - "filename" : "ipadPro167.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "83.5x83.5" - }, - { - "filename" : "appstore1024.png", - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - }, - { - "filename" : "mac16.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "16x16" - }, - { - "filename" : "mac32.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "16x16" - }, - { - "filename" : "mac32.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "32x32" - }, - { - "filename" : "mac64.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "32x32" - }, - { - "filename" : "mac128.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "128x128" - }, - { - "filename" : "mac256.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "128x128" - }, - { - "filename" : "mac256.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "256x256" - }, - { - "filename" : "mac512.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "256x256" - }, - { - "filename" : "mac512.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "512x512" - }, - { - "filename" : "mac1024.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "512x512" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/appstore1024.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/appstore1024.png deleted file mode 100644 index 5158c65dd..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/appstore1024.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipad152.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipad152.png deleted file mode 100644 index 2a66a2f22..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipad152.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipad76.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipad76.png deleted file mode 100644 index 73a9a780a..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipad76.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadNotification20.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadNotification20.png deleted file mode 100644 index 335b2b77a..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadNotification20.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadNotification40.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadNotification40.png deleted file mode 100644 index 70b583efc..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadNotification40.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadPro167.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadPro167.png deleted file mode 100644 index 1c23e9d5f..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadPro167.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadSettings29.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadSettings29.png deleted file mode 100644 index ade61424f..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadSettings29.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadSettings58.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadSettings58.png deleted file mode 100644 index 1b75901f2..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadSettings58.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadSpotlight40.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadSpotlight40.png deleted file mode 100644 index 70b583efc..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadSpotlight40.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadSpotlight80.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadSpotlight80.png deleted file mode 100644 index 182d3536e..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/ipadSpotlight80.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/iphone120.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/iphone120.png deleted file mode 100644 index e0a8289ce..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/iphone120.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/iphone180.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/iphone180.png deleted file mode 100644 index cbea445b5..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/iphone180.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac1024.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac1024.png deleted file mode 100644 index 56959aea2..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac1024.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac128.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac128.png deleted file mode 100644 index 482ced789..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac128.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac16.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac16.png deleted file mode 100644 index 8045fe2c9..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac16.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac256.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac256.png deleted file mode 100644 index ee8926403..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac256.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac32.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac32.png deleted file mode 100644 index 602659f03..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac32.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac512.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac512.png deleted file mode 100644 index 8e0dbb670..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac512.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac64.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac64.png deleted file mode 100644 index 7c28cae13..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/mac64.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/notification40.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/notification40.png deleted file mode 100644 index 70b583efc..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/notification40.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/notification60.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/notification60.png deleted file mode 100644 index fbbb433ce..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/notification60.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/settings58.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/settings58.png deleted file mode 100644 index 1b75901f2..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/settings58.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/settings87.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/settings87.png deleted file mode 100644 index 554636488..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/settings87.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/spotlight120.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/spotlight120.png deleted file mode 100644 index e0a8289ce..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/spotlight120.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/spotlight80.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/spotlight80.png deleted file mode 100644 index 182d3536e..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Dev.appiconset/spotlight80.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/Contents.json b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/Contents.json deleted file mode 100644 index dfcf46615..000000000 --- a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/Contents.json +++ /dev/null @@ -1,176 +0,0 @@ -{ - "images" : [ - { - "filename" : "notification40.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "filename" : "notification60.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "filename" : "settings58.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "filename" : "settings87.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "filename" : "spotlight80.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "filename" : "spotlight120.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "filename" : "iphone120.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "filename" : "iphone180.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "filename" : "ipadNotification20.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "filename" : "ipadNotification40.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "filename" : "ipadSettings29.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "filename" : "ipadSettings58.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "filename" : "ipadSpotlight40.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "40x40" - }, - { - "filename" : "ipadSpotlight80.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "40x40" - }, - { - "filename" : "ipad76.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" - }, - { - "filename" : "ipad152.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "76x76" - }, - { - "filename" : "ipadPro167.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "83.5x83.5" - }, - { - "filename" : "appstore1024.png", - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - }, - { - "filename" : "mac16.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "16x16" - }, - { - "filename" : "mac32.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "16x16" - }, - { - "filename" : "mac32.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "32x32" - }, - { - "filename" : "mac64.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "32x32" - }, - { - "filename" : "mac128.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "128x128" - }, - { - "filename" : "mac256.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "128x128" - }, - { - "filename" : "mac256.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "256x256" - }, - { - "filename" : "mac512.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "256x256" - }, - { - "filename" : "mac512.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "512x512" - }, - { - "filename" : "mac1024.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "512x512" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/appstore1024.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/appstore1024.png deleted file mode 100644 index b75924c3a..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/appstore1024.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipad152.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipad152.png deleted file mode 100644 index c370caa54..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipad152.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipad76.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipad76.png deleted file mode 100644 index d1db46bb4..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipad76.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadNotification20.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadNotification20.png deleted file mode 100644 index e0af5dbe8..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadNotification20.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadNotification40.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadNotification40.png deleted file mode 100644 index 2eda23b45..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadNotification40.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadPro167.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadPro167.png deleted file mode 100644 index aa44638a7..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadPro167.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadSettings29.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadSettings29.png deleted file mode 100644 index 1da8d853d..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadSettings29.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadSettings58.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadSettings58.png deleted file mode 100644 index 8a7efa5e1..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadSettings58.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadSpotlight40.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadSpotlight40.png deleted file mode 100644 index 2eda23b45..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadSpotlight40.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadSpotlight80.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadSpotlight80.png deleted file mode 100644 index 10a942ff4..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/ipadSpotlight80.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/iphone120.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/iphone120.png deleted file mode 100644 index d52c1d4d9..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/iphone120.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/iphone180.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/iphone180.png deleted file mode 100644 index 1d9ac7bd8..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/iphone180.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac1024.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac1024.png deleted file mode 100644 index 17a44ab04..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac1024.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac128.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac128.png deleted file mode 100644 index a4a369643..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac128.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac16.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac16.png deleted file mode 100644 index e52661f86..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac16.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac256.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac256.png deleted file mode 100644 index 52a8a040f..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac256.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac32.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac32.png deleted file mode 100644 index f8664641c..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac32.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac512.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac512.png deleted file mode 100644 index 46646c478..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac512.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac64.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac64.png deleted file mode 100644 index ca43724eb..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/mac64.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/notification40.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/notification40.png deleted file mode 100644 index 2eda23b45..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/notification40.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/notification60.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/notification60.png deleted file mode 100644 index 16a65cc73..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/notification60.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/settings58.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/settings58.png deleted file mode 100644 index 8a7efa5e1..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/settings58.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/settings87.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/settings87.png deleted file mode 100644 index 4d0242944..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/settings87.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/spotlight120.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/spotlight120.png deleted file mode 100644 index d52c1d4d9..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/spotlight120.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/spotlight80.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/spotlight80.png deleted file mode 100644 index 10a942ff4..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon-Prod.appiconset/spotlight80.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index dfcf46615..000000000 --- a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,176 +0,0 @@ -{ - "images" : [ - { - "filename" : "notification40.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "filename" : "notification60.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "filename" : "settings58.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "filename" : "settings87.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "filename" : "spotlight80.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "filename" : "spotlight120.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "filename" : "iphone120.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "filename" : "iphone180.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "filename" : "ipadNotification20.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "filename" : "ipadNotification40.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "filename" : "ipadSettings29.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "filename" : "ipadSettings58.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "filename" : "ipadSpotlight40.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "40x40" - }, - { - "filename" : "ipadSpotlight80.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "40x40" - }, - { - "filename" : "ipad76.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" - }, - { - "filename" : "ipad152.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "76x76" - }, - { - "filename" : "ipadPro167.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "83.5x83.5" - }, - { - "filename" : "appstore1024.png", - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - }, - { - "filename" : "mac16.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "16x16" - }, - { - "filename" : "mac32.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "16x16" - }, - { - "filename" : "mac32.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "32x32" - }, - { - "filename" : "mac64.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "32x32" - }, - { - "filename" : "mac128.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "128x128" - }, - { - "filename" : "mac256.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "128x128" - }, - { - "filename" : "mac256.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "256x256" - }, - { - "filename" : "mac512.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "256x256" - }, - { - "filename" : "mac512.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "512x512" - }, - { - "filename" : "mac1024.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "512x512" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/appstore1024.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/appstore1024.png deleted file mode 100644 index 3136e5b29..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/appstore1024.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipad152.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipad152.png deleted file mode 100644 index 6fb4ff12c..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipad152.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipad76.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipad76.png deleted file mode 100644 index 44020028e..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipad76.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadNotification20.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadNotification20.png deleted file mode 100644 index 301c87f22..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadNotification20.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadNotification40.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadNotification40.png deleted file mode 100644 index 3b5552c07..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadNotification40.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadPro167.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadPro167.png deleted file mode 100644 index 0eeae1465..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadPro167.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadSettings29.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadSettings29.png deleted file mode 100644 index da2e88574..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadSettings29.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadSettings58.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadSettings58.png deleted file mode 100644 index ecf358a4f..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadSettings58.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadSpotlight40.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadSpotlight40.png deleted file mode 100644 index 3b5552c07..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadSpotlight40.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadSpotlight80.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadSpotlight80.png deleted file mode 100644 index 370101d7b..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/ipadSpotlight80.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/iphone120.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/iphone120.png deleted file mode 100644 index 61980089b..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/iphone120.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/iphone180.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/iphone180.png deleted file mode 100644 index 07632ad76..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/iphone180.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac1024.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac1024.png deleted file mode 100644 index a5ca57a37..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac1024.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac128.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac128.png deleted file mode 100644 index 087e5375e..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac128.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac16.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac16.png deleted file mode 100644 index 1f07c15d6..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac16.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac256.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac256.png deleted file mode 100644 index 01d0bc100..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac256.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac32.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac32.png deleted file mode 100644 index 84dd32c1d..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac32.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac512.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac512.png deleted file mode 100644 index cf4bbc46c..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac512.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac64.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac64.png deleted file mode 100644 index 1a201c6b8..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/mac64.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/notification40.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/notification40.png deleted file mode 100644 index 3b5552c07..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/notification40.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/notification60.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/notification60.png deleted file mode 100644 index 6d30f63d9..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/notification60.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/settings58.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/settings58.png deleted file mode 100644 index ecf358a4f..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/settings58.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/settings87.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/settings87.png deleted file mode 100644 index 3cba1f2ef..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/settings87.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/spotlight120.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/spotlight120.png deleted file mode 100644 index 61980089b..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/spotlight120.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/spotlight80.png b/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/spotlight80.png deleted file mode 100644 index 370101d7b..000000000 Binary files a/code/frontend/MakeItSo/Shared/Assets.xcassets/AppIcon.appiconset/spotlight80.png and /dev/null differ diff --git a/code/frontend/MakeItSo/Shared/Common/Views/EmptyStateView.swift b/code/frontend/MakeItSo/Shared/Common/Views/EmptyStateView.swift deleted file mode 100644 index 1d07d6afd..000000000 --- a/code/frontend/MakeItSo/Shared/Common/Views/EmptyStateView.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// EmptyStateView.swift -// MakeItSo (iOS) -// -// Created by Peter Friese on 12.11.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import SwiftUI - -extension View { - func debug() -> Self { - print(Mirror(reflecting: self).subjectType) - return self - } -} - -struct EmptyStateViewModifier: ViewModifier where EmptyContent: View { - var isEmpty: Bool - let emptyContent: () -> EmptyContent - - func body(content: Content) -> some View { - if isEmpty { - emptyContent() - } - else { - content - } - } -} - -extension View { - func emptyState(_ isEmpty: Bool, - emptyContent: @escaping () -> EmptyContent) -> some View where EmptyContent: View { - modifier(EmptyStateViewModifier(isEmpty: isEmpty, emptyContent: emptyContent)) - } -} - -struct EmptyStateView_Previews: PreviewProvider { - static var previews: some View { - Label("Content", systemImage: "heart") - .emptyState(true) { - Text("We don't have any content, sorry 😔") - } - } -} diff --git a/code/frontend/MakeItSo/Shared/Extensions/Font+Rounded.swift b/code/frontend/MakeItSo/Shared/Extensions/Font+Rounded.swift deleted file mode 100644 index 5927b9811..000000000 --- a/code/frontend/MakeItSo/Shared/Extensions/Font+Rounded.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// Appearance.swift -// MakeItSo (iOS) -// -// Created by Peter Friese on 06.12.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import SwiftUI - -extension UIFontDescriptor { - static func largeTitle() -> UIFontDescriptor? { - UIFontDescriptor.preferredFontDescriptor(withTextStyle: .largeTitle).withSymbolicTraits(.traitBold) - } - - static func headline() -> UIFontDescriptor? { - UIFontDescriptor.preferredFontDescriptor(withTextStyle: .headline).withSymbolicTraits(.traitBold) - } - - func rounded() -> UIFontDescriptor? { - self.withDesign(.rounded) - } -} - - -// see https://gist.github.com/darrensapalo/bd6dddab6a70ae0a2d6cf8ac5aeb6b1a for more -extension UIFont { - static func roundedLargeTitle() -> UIFont? { - guard let descriptor = UIFontDescriptor.largeTitle()?.rounded() else { return nil } - return UIFont(descriptor: descriptor, size: 0) - } - - static func roundedHeadline() -> UIFont? { - guard let descriptor = UIFontDescriptor.headline()?.rounded() else { return nil } - return UIFont(descriptor: descriptor, size: 0) - } -} - -extension View { -} - diff --git a/code/frontend/MakeItSo/Shared/Extensions/View+ConfirmationDialog.swift b/code/frontend/MakeItSo/Shared/Extensions/View+ConfirmationDialog.swift deleted file mode 100644 index 6e221ecf6..000000000 --- a/code/frontend/MakeItSo/Shared/Extensions/View+ConfirmationDialog.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// View+ConfirmationDialog.swift -// MakeItSo (iOS) -// -// Created by Peter Friese on 23.11.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import SwiftUI - -struct ConfirmationDialog: ViewModifier { - @Environment(\.dismiss) private var dismiss - @State private var presentingConfirmationDialog: Bool = false - - var isModified: Bool - var onCancel: (() -> Void)? - var onCommit: () -> Void - - private func doCancel() { - onCancel?() - dismiss() - } - - private func doCommit() { - onCommit() - dismiss() - } - - func body(content: Content) -> some View { - NavigationView { - content - .toolbar { - ToolbarItem(placement: .cancellationAction) { - Button("Cancel", role: .cancel) { - if isModified { - presentingConfirmationDialog.toggle() - } - else { - doCancel() - } - } - } - ToolbarItem(placement: .confirmationAction) { - Button("Done", action: doCommit) - } - } - .confirmationDialog("", isPresented: $presentingConfirmationDialog) { - Button("Discard Changes", role: .destructive, action: doCancel) - Button("Cancel", role: .cancel, action: { }) - } - } - // Option 1: use a closure to handle the attempt to dismiss -// .interactiveDismissDisabled(isModified) { -// presentingConfirmationDialog.toggle() -// } - // Option 2: bind attempt to dismiss to a boolean state variable that drives the UI - .interactiveDismissDisabled(isModified, attemptToDismiss: $presentingConfirmationDialog) - } -} - -extension View { - func confirmationDialog(isModified: Bool, onCancel: (() -> Void)? = nil, onCommit: @escaping () -> Void) -> some View { - self.modifier(ConfirmationDialog(isModified: isModified, onCancel: onCancel, onCommit: onCommit)) - } -} - diff --git a/code/frontend/MakeItSo/Shared/Extensions/View+Focus.swift b/code/frontend/MakeItSo/Shared/Extensions/View+Focus.swift deleted file mode 100644 index 259875786..000000000 --- a/code/frontend/MakeItSo/Shared/Extensions/View+Focus.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// View+Focus.swift -// MakeItSo (iOS) -// -// Created by Peter Friese on 30.10.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import SwiftUI - -/// Used to manage focus in a `List` view -enum Focusable: Hashable { - case none - case row(id: String?) -} - -extension View { - /// Mirror changes between an @Published variable (typically in your View Model) and - /// an @FocusedState variable in a view - func sync(_ field1: Binding, _ field2: FocusState.Binding ) -> some View { - self - .onChange(of: field1.wrappedValue) { field2.wrappedValue = $0 } - .onChange(of: field2.wrappedValue) { field1.wrappedValue = $0 } - } -} diff --git a/code/frontend/MakeItSo/Shared/Extensions/View+InteractiveDismissDisable.swift b/code/frontend/MakeItSo/Shared/Extensions/View+InteractiveDismissDisable.swift deleted file mode 100644 index 5c18d13f8..000000000 --- a/code/frontend/MakeItSo/Shared/Extensions/View+InteractiveDismissDisable.swift +++ /dev/null @@ -1,141 +0,0 @@ -// -// View+InteractiveDismissDisable.swift -// MakeItSo (iOS) -// -// Created by Peter Friese on 25.11.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import SwiftUI - -extension View { - public func interactiveDismissDisabled(_ isDisabled: Bool = true, onAttemptToDismiss: (() -> Void)? = nil) -> some View { - InteractiveDismissableView(view: self, isDisabled: isDisabled, onAttemptToDismiss: onAttemptToDismiss) - } - - public func interactiveDismissDisabled(_ isDisabled: Bool = true, attemptToDismiss: Binding) -> some View { - InteractiveDismissableView(view: self, isDisabled: isDisabled) { - attemptToDismiss.wrappedValue.toggle() - } - } -} - -private struct InteractiveDismissableView: UIViewControllerRepresentable { - let view: T - let isDisabled: Bool - let onAttemptToDismiss: (() -> Void)? - - func makeUIViewController(context: Context) -> UIHostingController { - UIHostingController(rootView: view) - } - - func updateUIViewController(_ uiViewController: UIHostingController, context: Context) { - context.coordinator.dismissableView = self - uiViewController.rootView = view - uiViewController.parent?.presentationController?.delegate = context.coordinator - } - - func makeCoordinator() -> Coordinator { - Coordinator(self) - } - - class Coordinator: NSObject, UIAdaptivePresentationControllerDelegate { - var dismissableView: InteractiveDismissableView - - init(_ dismissableView: InteractiveDismissableView) { - self.dismissableView = dismissableView - } - - func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool { - !dismissableView.isDisabled - } - - func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) { - dismissableView.onAttemptToDismiss?() - } - } -} - -struct ContentView: View { - @State var showingSheet = false - @State var name: String = "Johnny Appleseed" - var body: some View { - Form { - Section("User Profile") { - Text(name) - } - Button("Edit", action: { showingSheet.toggle() }) - } - .sheet(isPresented: $showingSheet) { - EditView(name: $name) - } - } -} - -private class ViewModel: ObservableObject { - @Published var name: String - private var original: String - - var isModified: Bool { - print("\(name) - \(original)") - return name != original - } - - init(name: String) { - self.name = name - self.original = name - } -} - -private struct EditView: View { - @Environment(\.dismiss) var dismiss - @Binding var name: String - - @StateObject private var viewModel: ViewModel - @State var showingConfirmationDialog = false - - init(name: Binding) { - self._name = name - self._viewModel = StateObject(wrappedValue: ViewModel(name: name.wrappedValue)) - } - - var body: some View { - NavigationView { - Form { - TextField("Enter your name", text: $viewModel.name) - } - .navigationTitle("Edit") - .navigationBarTitleDisplayMode(.inline) - } - .interactiveDismissDisabled(viewModel.isModified) { - showingConfirmationDialog.toggle() - } - .confirmationDialog("", isPresented: $showingConfirmationDialog) { - Button("Save") { - name = viewModel.name - dismiss() - } - Button("Discard", role: .destructive) { - dismiss() - } - Button("Cancel", role: .cancel) { } - } - } -} - -struct ContentView_Previews: PreviewProvider { - static var previews: some View { - ContentView() - } -} diff --git a/code/frontend/MakeItSo/Shared/Features/Authentication/Services/AuthenticationService.swift b/code/frontend/MakeItSo/Shared/Features/Authentication/Services/AuthenticationService.swift deleted file mode 100644 index 54aa5dd31..000000000 --- a/code/frontend/MakeItSo/Shared/Features/Authentication/Services/AuthenticationService.swift +++ /dev/null @@ -1,113 +0,0 @@ -// -// AuthenticationService.swift -// MakeItSo -// -// Created by Peter Friese on 16.12.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation -import Firebase -import os -import AuthenticationServices -import CryptoKit -import Resolver - -public class AuthenticationService: ObservableObject { - private let logger = Logger(subsystem: "dev.peterfriese.MakeItSo", category: "authentication") - - @Published public var user: User? - - private var handle: AuthStateDidChangeListenerHandle? - - public init() { - setupKeychainSharing() - registerStateListener() - } - - public func signIn() { - if Auth.auth().currentUser == nil { - Auth.auth().signInAnonymously() - } - } - - public func signOut() { - do { - try Auth.auth().signOut() - } - catch { - print("error when trying to sign out: \(error.localizedDescription)") - } - } - - func updateDisplayName(displayName: String, completionHandler: @escaping (Result) -> Void) { - if let user = Auth.auth().currentUser { - let changeRequest = user.createProfileChangeRequest() - changeRequest.displayName = displayName - changeRequest.commitChanges { error in - if let error = error { - completionHandler(.failure(error)) - } - else { - if let updatedUser = Auth.auth().currentUser { - print("Successfully updated display name for user [\(user.uid)] to [\(updatedUser.displayName ?? "(empty)")]") - // force update the local user to trigger the publisher - self.user = updatedUser - completionHandler(.success(updatedUser)) - } - } - } - } - } - - private var accessGroup: String { - get { - let info = KeyChainAccessGroupHelper.getAccessGroupInfo() - let prefix = info?.prefix ?? "unknown" - return prefix + "." + (Bundle.main.bundleIdentifier ?? "unknown") - } - } - - private func setupKeychainSharing() { - do { - let auth = Auth.auth() - auth.shareAuthStateAcrossDevices = true - try auth.useUserAccessGroup(accessGroup) - } - catch let error as NSError { - print("Error changing user access group: %@", error) - } - } - - private func registerStateListener() { - if handle == nil { - handle = Auth.auth().addStateDidChangeListener({ (auth, user) in - self.user = user - - if let user = user { - if user.isAnonymous { - self.logger.debug("User signed in anonymously with user ID \(user.uid).") - } - else { - self.logger.debug("User signed in with user ID \(user.uid). Email: \(user.email ?? "(empty)"), display name: [\(user.displayName ?? "(empty)")]") - } - } - else { - self.logger.debug("User signed out.") - self.signIn() - } - }) - } - } -} diff --git a/code/frontend/MakeItSo/Shared/Features/ReminderList/Models/Reminder.swift b/code/frontend/MakeItSo/Shared/Features/ReminderList/Models/Reminder.swift deleted file mode 100644 index 7b6f3ea53..000000000 --- a/code/frontend/MakeItSo/Shared/Features/ReminderList/Models/Reminder.swift +++ /dev/null @@ -1,120 +0,0 @@ -// -// Reminder.swift -// MakeItSo -// -// Created by Peter Friese on 26.10.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation -import FirebaseFirestoreSwift - -enum Priority: String { - case none - case low - case medium - case high -} - -struct Tag { - var title: String -} - -struct Location { -} - -struct Reminder { - /// We need the Firestore document ID so we can update / delete the document - @DocumentID var docId: String? - - /// The `id` is required to make the `Reminder` identifiable. We also need to persist this, otherwise - /// it would get lost when round-tripping to Firestore, which would result in the item losing focus. - var id: String? = UUID().uuidString - var title: String - var notes: String? - var url: String? - - var dueDate: Date? - var hasDueTime: Bool = false - - var tags: [Tag]? - - var location: Location? - - // TODO: when messaging - - var flagged: Bool = false - - var priority: Priority = .none - // TODO: parent list - - // TODO: subtasks (it's interesting to note that these are actually called "subtasks" in the UI of Apple's Reminders app! - - // TOOD: images - - var completed: Bool = false - var order: Int = 0 - - var userId: String? -} - -extension Priority: Codable, Equatable, Identifiable { - var id: Priority { self } -} - -extension Priority: Comparable { - static func < (lhs: Priority, rhs: Priority) -> Bool { - guard let l = lhs.index, let r = rhs.index else { return false } - return l < r - } -} - -// Conforming Priority to CaseIterable allows us to use it inside a `Picker` view -extension Priority: CaseIterable { } - -// This allows us to determine the index of a case inside an enum. -// For example, this is used to compute the representation of a -// task priority (!, !!, !!!, or en empty string for "no priority"). -extension CaseIterable where Self: Equatable { - var index: Self.AllCases.Index? { - return Self.allCases.firstIndex { self == $0 } - } -} - -extension Tag: Codable, Equatable { -} - -extension Location: Codable, Equatable { -} - -extension Reminder: Codable, Identifiable, Equatable { -} - -// so we can use Array.difference -extension Reminder: Hashable { - func hash(into hasher: inout Hasher) { - hasher.combine(id) - } -} - -extension Reminder { - static let samples = [ - Reminder(title: "Build sample app", dueDate: Date.now, priority: .high), - Reminder(title: "Tweet about surprising findings", dueDate: Date.now, flagged: true), - Reminder(title: "Write newsletter", priority: .medium), - Reminder(title: "Run YouTube video series"), - Reminder(title: "???"), -// Reminder(title: "PROFIT!!") - ] -} diff --git a/code/frontend/MakeItSo/Shared/Features/ReminderList/Repositories/RemindersRepository.swift b/code/frontend/MakeItSo/Shared/Features/ReminderList/Repositories/RemindersRepository.swift deleted file mode 100644 index 0e425d163..000000000 --- a/code/frontend/MakeItSo/Shared/Features/ReminderList/Repositories/RemindersRepository.swift +++ /dev/null @@ -1,147 +0,0 @@ -// -// RemindersRepository.swift -// MakeItSo -// -// Created by Peter Friese on 16.12.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation -import Combine -import Firebase -import FirebaseFirestoreSwift -import Resolver -import os - -class RemindersRepository: ObservableObject { - // MARK: - Dependencies - @Injected var db: Firestore - @Injected var authenticationService: AuthenticationService - - // MARK: - Publishers - @Published public var reminders = [Reminder]() - - // MARK: - Private attributes - private var userId: String = "unknown" - private var listenerRegistration: ListenerRegistration? - private var cancellables = Set() - - let logger = Logger(subsystem: "dev.peterfriese.MakeItSo", category: "persistence") - - init() { - // observe user ID - authenticationService.$user - .compactMap { user in - user?.uid - } - .assign(to: \.userId, on: self) - .store(in: &cancellables) - - authenticationService.$user - .receive(on: DispatchQueue.main) - .sink { [weak self] user in - if self?.listenerRegistration != nil { - self?.unsubscribe() - self?.subscribe() - } - } - .store(in: &cancellables) - } - - deinit { - unsubscribe() - } - - func unsubscribe() { - if listenerRegistration != nil { - listenerRegistration?.remove() - listenerRegistration = nil - } - } - - func subscribe() { - if listenerRegistration != nil { - unsubscribe() - } - let query = db.collection("reminders") - .whereField("userId", isEqualTo: userId) - - listenerRegistration = query - .addSnapshotListener { [weak self] (querySnapshot, error) in - guard let documents = querySnapshot?.documents else { - self?.logger.debug("No documents in 'reminders' collection") - return - } - - self?.reminders = documents.compactMap { queryDocumentSnapshot in - let result = Result { try queryDocumentSnapshot.data(as: Reminder.self) } - - switch result { - case .success(let reminder): - // A `Reminder` value was successfully initialized from the DocumentSnapshot. - return reminder - case .failure(let error): - // A `Reminder` value could not be initialized from the DocumentSnapshot. - switch error { - case DecodingError.typeMismatch(_, let context): - self?.logger.error("\(error.localizedDescription): \(context.debugDescription)") - case DecodingError.valueNotFound(_, let context): - self?.logger.error("\(error.localizedDescription): \(context.debugDescription)") - case DecodingError.keyNotFound(_, let context): - self?.logger.error("\(error.localizedDescription): \(context.debugDescription)") - case DecodingError.dataCorrupted(let key): - self?.logger.error("\(error.localizedDescription): \(key.debugDescription)") - default: - self?.logger.error("Error decoding document: \(error.localizedDescription)") - } - return nil - } - } - } - } - - func addReminder(_ reminder: Reminder) { - do { - var userReminder = reminder - userReminder.userId = userId - logger.debug("Adding reminder '\(userReminder.title)' for user \(self.userId)") - let _ = try db.collection("reminders").addDocument(from: userReminder) - } - catch { - logger.error("Error: \(error.localizedDescription)") - } - } - - func updateReminder(_ reminder: Reminder) { - if let documentId = reminder.docId { - do { - try db.collection("reminders").document(documentId).setData(from: reminder) - } - catch { - self.logger.debug("Unable to update document \(documentId): \(error.localizedDescription)") - } - } - } - - func removeReminder(_ reminder: Reminder) { - if let documentId = reminder.docId { - db.collection("reminders").document(documentId).delete() { error in - if let error = error { - self.logger.debug("Unable to remove document \(error.localizedDescription)") - } - } - } - } - -} diff --git a/code/frontend/MakeItSo/Shared/Features/ReminderList/ViewModels/ReminderDetailsViewModel.swift b/code/frontend/MakeItSo/Shared/Features/ReminderList/ViewModels/ReminderDetailsViewModel.swift deleted file mode 100644 index 6ae3ccd49..000000000 --- a/code/frontend/MakeItSo/Shared/Features/ReminderList/ViewModels/ReminderDetailsViewModel.swift +++ /dev/null @@ -1,174 +0,0 @@ -// -// ReminderDetailsViewModel.swift -// MakeItSo -// -// Created by Peter Friese on 23.11.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation -import Combine - -extension Date { - func formattedRelativeToday() -> String { - if Calendar.autoupdatingCurrent.isDateInToday(self) - || Calendar.autoupdatingCurrent.isDateInYesterday(self) - || Calendar.autoupdatingCurrent.isDateInTomorrow(self) { - - let formatStyle = Date.RelativeFormatStyle( - presentation: .named, - unitsStyle: .wide, - capitalizationContext: .beginningOfSentence) - - return self.formatted(formatStyle) - } - else { - return self.formatted(date: .complete, time: .omitted) - } - } - - func nearestHour() -> Date? { - var components = NSCalendar.current.dateComponents([.minute], from: self) - let minute = components.minute ?? 0 - components.minute = minute >= 30 ? 60 - minute : -minute - return Calendar.current.date(byAdding: components, to: self) - } - - func nextHour(basedOn date: Date? = nil) -> Date? { - let other = date ?? self - - var timeComponents = Calendar.current.dateComponents([.hour, .minute], from: other) - let minute = timeComponents.minute ?? 0 - timeComponents.minute = minute >= 0 ? 60 : 0 - - let dateComponents = Calendar.current.dateComponents([.year, .month, .day], from: self) - - let newDateComponents = DateComponents(calendar: Calendar.current, - year: dateComponents.year, - month: dateComponents.month, - day: dateComponents.day, - hour: timeComponents.hour, - minute: timeComponents.minute) - - return Calendar.current.date(from: newDateComponents) - } - - func startOfDay() -> Date { - Calendar.current.startOfDay(for: self) - } -} - - -class ReminderDetailsViewModel: ObservableObject { - @Published var reminder: Reminder - private var original: Reminder - - init(reminder: Reminder) { - self.reminder = reminder - original = reminder - } - - var isModified: Bool { - original != reminder - } - - // The `notes` attribute on the Reminder model is optional. - // Using this approach allows us to bind the notes to SwiftUI - // views. - var notes: String { - get { - reminder.notes ?? "" - } - set { - reminder.notes = newValue - } - } - - var url: String { - get { - reminder.url ?? "" - } - set { - reminder.url = newValue - } - } - - var dueDate: Date { - get { - return reminder.dueDate ?? Date() - } - set { - reminder.dueDate = newValue - } - } - - var dueTime: Date { - get { - return dueDate - } - set { - dueDate = newValue - } - } - - var hasDueDate: Bool { - get { - reminder.dueDate != nil - } - set { - if newValue == true { - reminder.dueDate = Date() - isShowingDatePicker = true - } - else { - hasDueTime = false - reminder.dueDate = nil - isShowingDatePicker = false - } - } - } - - var hasDueTime: Bool { - get { - reminder.hasDueTime - } - set { - if newValue == true { - guard let nearestHour = dueDate.nextHour(basedOn: Date()) else { return } - dueDate = nearestHour - reminder.hasDueTime = true - isShowingTimePicker = true - } - else { - dueDate = dueDate.startOfDay() - reminder.hasDueTime = false - isShowingTimePicker = false - } - } - } - - @Published var isShowingDatePicker: Bool = false - @Published var isShowingTimePicker: Bool = false - - func toggleTimePicker() { - isShowingTimePicker.toggle() - isShowingDatePicker = false - } - - func toggleDatePicker() { - isShowingDatePicker.toggle() - isShowingTimePicker = false - } - -} diff --git a/code/frontend/MakeItSo/Shared/Features/ReminderList/ViewModels/ReminderListRowViewModel.swift b/code/frontend/MakeItSo/Shared/Features/ReminderList/ViewModels/ReminderListRowViewModel.swift deleted file mode 100644 index 67992432d..000000000 --- a/code/frontend/MakeItSo/Shared/Features/ReminderList/ViewModels/ReminderListRowViewModel.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// ReminderListRowViewModel.swift -// MakeItSo -// -// Created by Peter Friese on 30.11.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import SwiftUI - -class ReminderListRowViewModel: ObservableObject { - @Binding var reminder: Reminder - - init(reminder: Binding) { - self._reminder = reminder - } - - var priorityAdornment: String { - String(repeating: "!", count: (reminder.priority.index ?? 0)) - } - - var hasDueDate: Bool { - reminder.dueDate != nil - } - - var hasDueTime: Bool { - reminder.hasDueTime - } - - var dueDate: Date { - reminder.dueDate ?? Date() - } - - var formattedDueDate: String { - guard let dueDate = reminder.dueDate else { return "" } - return dueDate.formattedRelativeToday() - } -} diff --git a/code/frontend/MakeItSo/Shared/Features/ReminderList/ViewModels/RemindersListViewModel.swift b/code/frontend/MakeItSo/Shared/Features/ReminderList/ViewModels/RemindersListViewModel.swift deleted file mode 100644 index 2ff5f0b52..000000000 --- a/code/frontend/MakeItSo/Shared/Features/ReminderList/ViewModels/RemindersListViewModel.swift +++ /dev/null @@ -1,211 +0,0 @@ -// -// RemindersListViewModel.swift -// MakeItSo -// -// Created by Peter Friese on 26.10.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation -import Combine -import SwiftUI -import Resolver - -enum SortingMode { - case manual - case byDeadline - case byCreationDate - case byPriority - case byTitle - - func sorted(lhs: Reminder, rhs: Reminder) -> Bool { - return lhs.order < rhs.order - } -} - -extension Array where Element == Reminder { - func computeOrder(for reminder: Reminder) -> Int { - let index = self.endIndex == 0 ? 0 : self.endIndex - 1 - return self.computeOrder(for: reminder, after: index) - } - - func computeOrder(for reminder: Reminder, after index: Int) -> Int { - guard self.count > 0 else { return 0 } - let currentOrder = self[index].order - - let nextIndex = self.index(after: index) - let nextOrder = nextIndex < self.endIndex ? self[nextIndex].order : currentOrder + 1_000 - - return (currentOrder + nextOrder) / 2 - } -} - -class RemindersListViewModel: ObservableObject { - @Published var remindersRepository: RemindersRepository - - @Published var sortingMode: SortingMode = .manual - - @Published var reminders: [Reminder] - @Published var selectedReminder: Reminder? - @Published var focusedReminder: Focusable? - var previousFocusedReminder: Focusable? - - private var cancellables = Set() - - init(reminders: [Reminder]) { - self.reminders = reminders - - remindersRepository = Resolver.resolve() - remindersRepository.subscribe() - remindersRepository.$reminders - .combineLatest($sortingMode) - .map { reminders, sortingMode in - reminders.sorted(by: sortingMode.sorted) - } - .assign(to: &$reminders) - - // This is the beginning of some magic Firestore sauce - // $reminders.sink { newValue in - // self.dump(newValue) - // self.performUpdates(newValue) - // } - // .store(in: &cancellables) - - // the following pipeline removes empty reminder when the respective row in the list view loses focus - $focusedReminder - .removeDuplicates() - .compactMap { focusedReminder -> Int? in - defer { self.previousFocusedReminder = focusedReminder } - - guard focusedReminder != nil else { return nil } - guard case .row(let previousId) = self.previousFocusedReminder else { return nil } - guard let previousIndex = self.reminders.firstIndex(where: { $0.id == previousId } ) else { return nil } - guard self.reminders[previousIndex].title.isEmpty else { return nil } - - return previousIndex - } - .delay(for: 0.01, scheduler: RunLoop.main) // <-- this helps reduce the visual jank - .sink { index in - self.remindersRepository.removeReminder(self.reminders[index]) - self.reminders.remove(at: index) - } - .store(in: &cancellables) - -// This is the unoptimised version. It results in visual jank. -// $focusedReminder -// .removeDuplicates() -// .sink { focusedReminder in -// if case .row(let previousId) = self.previousFocusedReminder, case .row(let currentId) = focusedReminder { -// print("Previous: \(previousId)") -// print("Current: \(currentId)") -// if let previousIndex = self.reminders.firstIndex(where: { $0.id == previousId } ) { -// if self.remindersa[previousIndex].title.isEmpty { -// self.reminders.remove(at: previousIndex) -// } -// } -// } -// self.previousFocusedReminder = focusedReminder -// } -// .store(in: &cancellables) - } - - func createNewReminder() { - var newReminder = Reminder(title: "") - - // if any row is focused, insert the new reminder after the focused row - if case .row(let id) = focusedReminder { - if let index = reminders.firstIndex(where: { $0.id == id } ) { - - // If the currently selected reminder is empty, unfocus it. - // This will kick off the pipeline that removes empty reminders. - let currentReminder = reminders[index] - guard !currentReminder.title.isEmpty else { - focusedReminder = Focusable.none - return - } - - // compute median of the elements before and after the new one - newReminder.order = reminders.computeOrder(for: newReminder, after: index) - - reminders.insert(newReminder, at: index + 1) - } - } - // no row focused: append at the end of the list - else { - newReminder.order = reminders.computeOrder(for: newReminder) - reminders.append(newReminder) - } - remindersRepository.addReminder(newReminder) - - // focus the new reminder - if let reminderId = newReminder.id { - focusedReminder = .row(id: reminderId) - } - } - - func deleteReminder(_ reminder: Reminder) { - Just(reminder) - .delay(for: .seconds(0.25), scheduler: RunLoop.main) - .sink { reminder in - if let index = self.reminders.firstIndex(of: reminder) { - self.reminders.remove(at: index) - self.remindersRepository.removeReminder(reminder) - } - } - .store(in: &cancellables) - } - - func updateReminder(_ reminder: Reminder) { - if let index = reminders.firstIndex(where: { $0.id == reminder.id} ) { - reminders[index] = reminder - remindersRepository.updateReminder(reminder) - } - } - - func flagReminder(_ reminder: Reminder) { - if let index = reminders.firstIndex(of: reminder) { - reminders[index].flagged.toggle() - } - } - - func unfocus() { - self.focusedReminder = nil - } - -} - - -extension RemindersListViewModel { - func dump(_ newValue: [Reminder]) { - print("--->>>") - print("Object value") - print(self.reminders) - print("Closure value") - print(newValue) - print("<<<---") - } - - func performUpdates(_ newValue: [Reminder]) { - let difference = newValue.difference(from: self.reminders) - let moves = difference.inferringMoves() - for update in moves { - switch update { - case .remove(let offset, let letter, let move): - print("Removed \(letter) at idx \(offset) and moved to \(String(describing: move))") - case .insert(let offset, let letter, let move): - print("Inserted \(letter) at idx \(offset) from \(String(describing: move))") - } - } - } -} diff --git a/code/frontend/MakeItSo/Shared/Features/ReminderList/Views/ReminderDetailsView.swift b/code/frontend/MakeItSo/Shared/Features/ReminderList/Views/ReminderDetailsView.swift deleted file mode 100644 index 934770fc2..000000000 --- a/code/frontend/MakeItSo/Shared/Features/ReminderList/Views/ReminderDetailsView.swift +++ /dev/null @@ -1,136 +0,0 @@ -// -// ReminderDetailsView.swift -// MakeItSo -// -// Created by Peter Friese on 23.11.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import SwiftUI - -struct ReminderDetailsView: View { - @ObservedObject private var viewModel: ReminderDetailsViewModel - - private var onCancel: (() -> Void)? - private var onCommit: (Reminder) -> Void - - init(reminder: Reminder, onCancel: (() -> Void)? = nil, onCommit: @escaping (Reminder) -> Void) { - self.viewModel = ReminderDetailsViewModel(reminder: reminder) - self.onCommit = onCommit - } - - var body: some View { - Form { - Section { - TextField("Title", text: $viewModel.reminder.title) - TextField("Notes", text: $viewModel.notes) - TextField("URL", text: $viewModel.url) - } - Section { - Toggle(isOn: $viewModel.hasDueDate) { - HStack { - Image(systemName: "calendar") - .frame(width: 26, height: 26, alignment: .center) - .background(.red) - .foregroundColor(.white) - .cornerRadius(4) - VStack(alignment: .leading) { - Text("Date") - if viewModel.hasDueDate { - Text(viewModel.dueDate.formattedRelativeToday()) - .font(.caption2) - .foregroundColor(.blue) - } } - } - } - .contentShape(Rectangle()) - .onTapGesture { - withAnimation { - viewModel.toggleDatePicker() - } - } - if viewModel.hasDueDate && viewModel.isShowingDatePicker { - DatePicker("Date", selection: $viewModel.dueDate, displayedComponents: .date) - .datePickerStyle(.graphical) - } - - Toggle(isOn: $viewModel.hasDueTime) { - HStack { - Image(systemName: "clock") - .frame(width: 26, height: 26, alignment: .center) - .background(.blue) - .foregroundColor(.white) - .cornerRadius(4) - VStack(alignment: .leading) { - Text("Time") - if (viewModel.hasDueTime) { - Text(viewModel.dueTime, style: .time) - .font(.caption2) - .foregroundColor(.blue) - } } - } - } - .contentShape(Rectangle()) - .onTapGesture { - withAnimation { - viewModel.toggleTimePicker() - } - } - if viewModel.hasDueTime && viewModel.isShowingTimePicker { - DatePicker("Date", selection: $viewModel.dueTime, displayedComponents: .hourAndMinute) - .datePickerStyle(.wheel) - } - } - Section { - Toggle(isOn: $viewModel.reminder.flagged) { - HStack { - Image(systemName: "flag.fill") - .frame(width: 26, height: 26, alignment: .center) - .background(.orange) - .foregroundColor(.white) - .cornerRadius(4) - Text("Flag") - } - } - } - Section { - Picker("Priority", selection: $viewModel.reminder.priority) { - ForEach(Priority.allCases) { prio in - Text(prio.rawValue.capitalized) - } - } - } - } - .animation(.default, value: viewModel.reminder) - .navigationTitle("Details") - .navigationBarTitleDisplayMode(.inline) - .confirmationDialog(isModified: viewModel.isModified) { - onCommit(viewModel.reminder) - } - } -} - -struct ReminderDetailsView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - Text("Dummy screen content") - .navigationTitle("Dummy screen") - .sheet(isPresented: .constant(true)) { - ReminderDetailsView(reminder: Reminder.samples[0]) { updatedReminder in - print(updatedReminder) - } - } - } - } -} diff --git a/code/frontend/MakeItSo/Shared/Features/ReminderList/Views/ReminderListRowView.swift b/code/frontend/MakeItSo/Shared/Features/ReminderList/Views/ReminderListRowView.swift deleted file mode 100644 index 52f5abb35..000000000 --- a/code/frontend/MakeItSo/Shared/Features/ReminderList/Views/ReminderListRowView.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// ReminderListRowView.swift -// MakeItSo -// -// Created by Peter Friese on 26.10.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import SwiftUI - -struct ReminderListRowView: View { - @ObservedObject var viewModel: ReminderListRowViewModel - - init(reminder: Binding) { - viewModel = ReminderListRowViewModel(reminder: reminder) - } - - var body: some View { - HStack(alignment: .top) { - Image(systemName: viewModel.reminder.completed ? "checkmark.circle.fill" : "circle") - .foregroundColor(viewModel.reminder.completed ? Color(UIColor.systemRed) : .gray) - .font(.title3) - .onTapGesture { - viewModel.reminder.completed.toggle() - } - VStack(alignment: .leading) { - HStack { - if viewModel.reminder.priority > .none { - Text(viewModel.priorityAdornment) - .foregroundColor(.accentColor) - } - TextField("", text: $viewModel.reminder.title) - .padding(.trailing, viewModel.reminder.flagged ? 20 : 0) - .overlay { - if viewModel.reminder.flagged { - HStack { - Spacer() - Image(systemName: "flag.fill") - .foregroundColor(Color(UIColor.systemOrange)) - } - } - } - } - if viewModel.hasDueDate { - Text(viewModel.formattedDueDate) - .font(.caption) - .foregroundColor(Color(UIColor.systemGray)) - } - } - } - } -} - -struct ReminderListRowView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - List { - ReminderListRowView(reminder: .constant(Reminder.samples[0])) - ReminderListRowView(reminder: .constant(Reminder.samples[1])) - ReminderListRowView(reminder: .constant(Reminder.samples[2])) - } - .listStyle(.plain) - .navigationTitle("Reminders") - } - } -} diff --git a/code/frontend/MakeItSo/Shared/Features/ReminderList/Views/RemindersListView.swift b/code/frontend/MakeItSo/Shared/Features/ReminderList/Views/RemindersListView.swift deleted file mode 100644 index 3130e72fc..000000000 --- a/code/frontend/MakeItSo/Shared/Features/ReminderList/Views/RemindersListView.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// RemindersListView.swift -// MakeItSo -// -// Created by Peter Friese on 26.10.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import SwiftUI - -struct RemindersListView: View { - @EnvironmentObject - var viewModel: RemindersListViewModel - - @FocusState - var focusedReminder: Focusable? - - var body: some View { - List { - ForEach($viewModel.reminders) { $reminder in - ReminderListRowView(reminder: $reminder) - .focused($focusedReminder, equals: .row(id: reminder.id)) - .onSubmit { - viewModel.createNewReminder() - } - .onChange(of: reminder) { value in - viewModel.updateReminder(reminder) - } - .swipeActions { - Button(role: .destructive, action: { viewModel.deleteReminder(reminder) }) { - Label("Delete", systemImage: "trash") - } - Button(action: { viewModel.flagReminder(reminder) }) { - Label("Flag", systemImage: "flag") - } - .tint(Color(UIColor.systemOrange)) - Button(action: { viewModel.selectedReminder = reminder }) { - Label("Details", systemImage: "ellipsis") - } - .tint(Color(UIColor.systemGray)) - } - } - } - .emptyState($viewModel.reminders.isEmpty) { - Text("No Reminders") - .font(.title3) - .foregroundColor(Color.secondary) - } - .sync($viewModel.focusedReminder, $focusedReminder) - .animation(.default, value: viewModel.reminders) - .listStyle(.plain) - .navigationTitle("Reminders") - .sheet(item: $viewModel.selectedReminder) { reminder in - ReminderDetailsView(reminder: reminder) { updatedReminder in - viewModel.updateReminder(updatedReminder) - } - } - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - if focusedReminder != nil { - Button(action: viewModel.unfocus ) { - Text("Done") - } - } - } - ToolbarItemGroup(placement: .bottomBar) { - Button(action: { viewModel.createNewReminder() }) { - HStack { - Image(systemName: "plus.circle.fill") - Text("New Reminder") - } - } - // needed to push the button to the left - Spacer() - } - } - } -} - -struct ReminderssListView_Previews: PreviewProvider { - static var viewModel = RemindersListViewModel(reminders: Reminder.samples) - - static var previews: some View { - NavigationView { - RemindersListView() - .environmentObject(viewModel) - } - } -} diff --git a/code/frontend/MakeItSo/Shared/MakeItSoApp+Injection.swift b/code/frontend/MakeItSo/Shared/MakeItSoApp+Injection.swift deleted file mode 100644 index 73a845961..000000000 --- a/code/frontend/MakeItSo/Shared/MakeItSoApp+Injection.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// MakeItSoApp+Injection.swift -// MakeItSo -// -// Created by Peter Friese on 16.12.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation -import Resolver -import Firebase - -extension Resolver: ResolverRegistering { - public static func registerAllServices() { - // register Firebase services - register { Firestore.firestore().enableLogging(on: true) }.scope(.application) - - // register application components - register { AuthenticationService() }.scope(.application) - register { RemindersRepository() }.scope(.application) - } -} - -extension Firestore { - func enableLogging(on: Bool = true) -> Firestore { - Self.enableLogging(on) - return self - } -} - diff --git a/code/frontend/MakeItSo/Shared/MakeItSoApp.swift b/code/frontend/MakeItSo/Shared/MakeItSoApp.swift deleted file mode 100644 index 8336ca138..000000000 --- a/code/frontend/MakeItSo/Shared/MakeItSoApp.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// MakeItSoApp.swift -// MakeItSo -// -// Created by Peter Friese on 25.10.21. -// Copyright © 2021 Google LLC. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import SwiftUI -import Firebase -import Resolver - -@main -struct MakeItSoApp: App { - @LazyInjected - var authenticationService: AuthenticationService - - @StateObject - var viewModel = RemindersListViewModel(reminders: Reminder.samples) - - init() { - let navBarAppearance = UINavigationBarAppearance() - - navBarAppearance.largeTitleTextAttributes[.font] = UIFont.roundedLargeTitle() - navBarAppearance.largeTitleTextAttributes[.foregroundColor] = UIColor(Color.accentColor) - navBarAppearance.titleTextAttributes[.font] = UIFont.roundedHeadline() - // Purposefully don't set the foreground color for normal text nav bar - - // in Reminders.app, this isn't tinted as well! - // navBarAppearance.titleTextAttributes[.foregroundColor] = foregroundColor - - UINavigationBar.appearance().standardAppearance = navBarAppearance - - FirebaseConfiguration.shared.setLoggerLevel(.min) - FirebaseApp.configure() - authenticationService.signIn() - } - - var body: some Scene { - WindowGroup { - NavigationView { - RemindersListView() - .font(.system(.body, design: .rounded)) - .environmentObject(viewModel) - } - .accentColor(.red) - } - } -} diff --git a/code/frontend/MakeItSo/Shared/Utilities/KeychainAccessGroupHelper.swift b/code/frontend/MakeItSo/Shared/Utilities/KeychainAccessGroupHelper.swift deleted file mode 100644 index 34b556d04..000000000 --- a/code/frontend/MakeItSo/Shared/Utilities/KeychainAccessGroupHelper.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// KeyStorage - Simplifying securely saving key information -// -// KeyChainAccessGroupHelper.swift -// Created by Ben Bahrenburg on 12/30/16. -// Copyright © 2017 bencoding.com. All rights reserved. -// -// See https://bencoding.com/2016/12/31/simplifying-using-keychain-access-groups/ - -import Foundation -import Security - -public struct KeyChainAccessGroupInfo { - public var prefix: String - public var keyChainGroup: String - public var rawValue: String -} - -open class KeyChainAccessGroupHelper { - - public class func getAccessGroupInfo() -> KeyChainAccessGroupInfo? { - let query: [String:Any] = [ - kSecClass as String : kSecClassGenericPassword, - kSecAttrAccount as String : "detectAppIdentifierForKeyChainGroupIdUsage", - kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, - kSecReturnAttributes as String : kCFBooleanTrue! - ] - - var dataTypeRef: AnyObject? - var status = withUnsafeMutablePointer(to: &dataTypeRef) { SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0)) } - - if status == errSecItemNotFound { - let createStatus = SecItemAdd(query as CFDictionary, nil) - guard createStatus == errSecSuccess else { return nil } - status = withUnsafeMutablePointer(to: &dataTypeRef) { SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0)) } - } - - guard status == errSecSuccess else { return nil } - - let accessGroup = ((dataTypeRef as! [AnyHashable: Any])[(kSecAttrAccessGroup as String)] as! String) - - if accessGroup.components(separatedBy: ".").count > 0 { - let components = accessGroup.components(separatedBy: ".") - let prefix = components.first! - let elements = components.filter() { $0 != prefix } - let keyChainGroup = elements.joined(separator: ".") - - return KeyChainAccessGroupInfo(prefix: prefix, keyChainGroup: keyChainGroup, rawValue: accessGroup) - } - return nil - } -} diff --git a/tutorial/chapter01/01-building-a-simple-todo-list-ui/README.md b/tutorial/chapter01/01-building-a-simple-todo-list-ui/README.md new file mode 100644 index 000000000..1631d7d82 --- /dev/null +++ b/tutorial/chapter01/01-building-a-simple-todo-list-ui/README.md @@ -0,0 +1,3 @@ +# Project Files: Building a Simple Todo List UI + +To follow the [Building a Simple Todo List UI](https://peterfriese.github.io/MakeItSo/tutorials/makeitso/building-a-simple-todo-list-ui) tutorial, you'll create a new Xcode project as described in the first section of the tutorial. To explore on your own, open the Xcode project in the **final** folder and browse the project's code. diff --git a/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo.xcodeproj/project.pbxproj b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo.xcodeproj/project.pbxproj new file mode 100644 index 000000000..d95cd2b0a --- /dev/null +++ b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo.xcodeproj/project.pbxproj @@ -0,0 +1,352 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 8842941329AFEEA8002B16B9 /* MakeItSoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842941229AFEEA8002B16B9 /* MakeItSoApp.swift */; }; + 8842941529AFEEA8002B16B9 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842941429AFEEA8002B16B9 /* ContentView.swift */; }; + 8842941729AFEEA9002B16B9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8842941629AFEEA9002B16B9 /* Assets.xcassets */; }; + 8842941A29AFEEA9002B16B9 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8842941929AFEEA9002B16B9 /* Preview Assets.xcassets */; }; + 8842942529AFF792002B16B9 /* Reminder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842942429AFF792002B16B9 /* Reminder.swift */; }; + 8842942729B275B9002B16B9 /* AddReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842942629B275B9002B16B9 /* AddReminderView.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 8842940F29AFEEA8002B16B9 /* MakeItSo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MakeItSo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 8842941229AFEEA8002B16B9 /* MakeItSoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeItSoApp.swift; sourceTree = ""; }; + 8842941429AFEEA8002B16B9 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 8842941629AFEEA9002B16B9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 8842941929AFEEA9002B16B9 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 8842942429AFF792002B16B9 /* Reminder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reminder.swift; sourceTree = ""; }; + 8842942629B275B9002B16B9 /* AddReminderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddReminderView.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8842940C29AFEEA8002B16B9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 8842940629AFEEA8002B16B9 = { + isa = PBXGroup; + children = ( + 8842941129AFEEA8002B16B9 /* MakeItSo */, + 8842941029AFEEA8002B16B9 /* Products */, + ); + sourceTree = ""; + }; + 8842941029AFEEA8002B16B9 /* Products */ = { + isa = PBXGroup; + children = ( + 8842940F29AFEEA8002B16B9 /* MakeItSo.app */, + ); + name = Products; + sourceTree = ""; + }; + 8842941129AFEEA8002B16B9 /* MakeItSo */ = { + isa = PBXGroup; + children = ( + 8842941229AFEEA8002B16B9 /* MakeItSoApp.swift */, + 8842941429AFEEA8002B16B9 /* ContentView.swift */, + 8842941629AFEEA9002B16B9 /* Assets.xcassets */, + 8842941829AFEEA9002B16B9 /* Preview Content */, + 8842942429AFF792002B16B9 /* Reminder.swift */, + 8842942629B275B9002B16B9 /* AddReminderView.swift */, + ); + path = MakeItSo; + sourceTree = ""; + }; + 8842941829AFEEA9002B16B9 /* Preview Content */ = { + isa = PBXGroup; + children = ( + 8842941929AFEEA9002B16B9 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8842940E29AFEEA8002B16B9 /* MakeItSo */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8842941D29AFEEA9002B16B9 /* Build configuration list for PBXNativeTarget "MakeItSo" */; + buildPhases = ( + 8842940B29AFEEA8002B16B9 /* Sources */, + 8842940C29AFEEA8002B16B9 /* Frameworks */, + 8842940D29AFEEA8002B16B9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MakeItSo; + productName = MakeItSo; + productReference = 8842940F29AFEEA8002B16B9 /* MakeItSo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 8842940729AFEEA8002B16B9 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1420; + LastUpgradeCheck = 1420; + TargetAttributes = { + 8842940E29AFEEA8002B16B9 = { + CreatedOnToolsVersion = 14.2; + }; + }; + }; + buildConfigurationList = 8842940A29AFEEA8002B16B9 /* Build configuration list for PBXProject "MakeItSo" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 8842940629AFEEA8002B16B9; + productRefGroup = 8842941029AFEEA8002B16B9 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8842940E29AFEEA8002B16B9 /* MakeItSo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8842940D29AFEEA8002B16B9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8842941A29AFEEA9002B16B9 /* Preview Assets.xcassets in Resources */, + 8842941729AFEEA9002B16B9 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8842940B29AFEEA8002B16B9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8842942529AFF792002B16B9 /* Reminder.swift in Sources */, + 8842941529AFEEA8002B16B9 /* ContentView.swift in Sources */, + 8842942729B275B9002B16B9 /* AddReminderView.swift in Sources */, + 8842941329AFEEA8002B16B9 /* MakeItSoApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 8842941B29AFEEA9002B16B9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 8842941C29AFEEA9002B16B9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 8842941E29AFEEA9002B16B9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"MakeItSo/Preview Content\""; + DEVELOPMENT_TEAM = ""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.MakeItSo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 8842941F29AFEEA9002B16B9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"MakeItSo/Preview Content\""; + DEVELOPMENT_TEAM = ""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.MakeItSo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 8842940A29AFEEA8002B16B9 /* Build configuration list for PBXProject "MakeItSo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8842941B29AFEEA9002B16B9 /* Debug */, + 8842941C29AFEEA9002B16B9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8842941D29AFEEA9002B16B9 /* Build configuration list for PBXNativeTarget "MakeItSo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8842941E29AFEEA9002B16B9 /* Debug */, + 8842941F29AFEEA9002B16B9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 8842940729AFEEA8002B16B9 /* Project object */; +} diff --git a/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/code/frontend/MakeItSo/macOS/macOS.entitlements b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 58% rename from code/frontend/MakeItSo/macOS/macOS.entitlements rename to tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist index f2ef3ae02..18d981003 100644 --- a/code/frontend/MakeItSo/macOS/macOS.entitlements +++ b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -2,9 +2,7 @@ - com.apple.security.app-sandbox - - com.apple.security.files.user-selected.read-only - + IDEDidComputeMac32BitWarning + diff --git a/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/AddReminderView.swift b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/AddReminderView.swift new file mode 100644 index 000000000..5197fc71c --- /dev/null +++ b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/AddReminderView.swift @@ -0,0 +1,80 @@ +// +// AddReminderView.swift +// MakeItSo +// +// Created by Peter Friese on 03.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftUI + +struct AddReminderView: View { + enum FocusableField: Hashable { + case title + } + + @FocusState + private var focusedField: FocusableField? + + @State + private var reminder = Reminder(title: "") + + @Environment(\.dismiss) + private var dismiss + + let onCommit: (_ reminder: Reminder) -> Void + + private func commit() { + onCommit(reminder) + dismiss() + } + + private func cancel() { + dismiss() + } + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + .focused($focusedField, equals: .title) + } + .navigationTitle("New Reminder") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .cancellationAction) { + Button(action: cancel) { + Text("Cancel") + } + } + ToolbarItem(placement: .confirmationAction) { + Button(action: commit) { + Text("Add") + } + .disabled(reminder.title.isEmpty) + } + } + .onAppear { + focusedField = .title + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/Assets.xcassets/AccentColor.colorset/Contents.json b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 000000000..eb8789700 --- /dev/null +++ b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/Assets.xcassets/AppIcon.appiconset/Contents.json b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..13613e3ee --- /dev/null +++ b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/Assets.xcassets/Contents.json b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/ContentView.swift b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/ContentView.swift new file mode 100644 index 000000000..ab5a811d8 --- /dev/null +++ b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/ContentView.swift @@ -0,0 +1,72 @@ +// +// ContentView.swift +// MakeItSo +// +// Created by Peter Friese on 01.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + Button(action: presentAddReminderView) { + HStack { + Image(systemName: "plus.circle.fill") + Text("New Reminder") + } + } + Spacer() + } + } + .sheet(isPresented: $isAddReminderDialogPresented) { + AddReminderView { reminder in + reminders.append(reminder) + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + NavigationStack { + ContentView() + .navigationTitle("Reminders") + } + } +} diff --git a/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/MakeItSoApp.swift b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/MakeItSoApp.swift new file mode 100644 index 000000000..9bf564661 --- /dev/null +++ b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/MakeItSoApp.swift @@ -0,0 +1,31 @@ +// +// MakeItSoApp.swift +// MakeItSo +// +// Created by Peter Friese on 01.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftUI + +@main +struct MakeItSoApp: App { + var body: some Scene { + WindowGroup { + NavigationStack { + ContentView() + .navigationTitle("Reminders") + } + } + } +} diff --git a/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/Preview Content/Preview Assets.xcassets/Contents.json b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/Reminder.swift b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/Reminder.swift new file mode 100644 index 000000000..54734c9fd --- /dev/null +++ b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/MakeItSo/MakeItSo/Reminder.swift @@ -0,0 +1,34 @@ +// +// Reminder.swift +// MakeItSo +// +// Created by Peter Friese on 01.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +struct Reminder: Identifiable { + let id = UUID() + var title: String + var isCompleted = false +} + +extension Reminder { + static let samples = [ + Reminder(title: "Build sample app", isCompleted: true), + Reminder(title: "Create tutorial"), + Reminder(title: "???"), + Reminder(title: "PROFIT!"), + ] +} diff --git a/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/README.md b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/README.md new file mode 100644 index 000000000..a7c76612d --- /dev/null +++ b/tutorial/chapter01/01-building-a-simple-todo-list-ui/final/README.md @@ -0,0 +1,3 @@ +# Building a Simple Todo List UI - Final + +This folder contains the _final_ state for the _Building a Simple Todo List UI_ part of the _Make It So_ tutorial. \ No newline at end of file diff --git a/tutorial/chapter01/01-building-a-simple-todo-list-ui/starter/README.md b/tutorial/chapter01/01-building-a-simple-todo-list-ui/starter/README.md new file mode 100644 index 000000000..38557367c --- /dev/null +++ b/tutorial/chapter01/01-building-a-simple-todo-list-ui/starter/README.md @@ -0,0 +1,5 @@ +# Building a Simple Todo List UI - Starter + +This folder contains the starter files for the _Building a Simple Todo List UI_ part of the _Make It So_ tutorial. + +The folder is intentionally empty - you will start out in a completely empty folder after all! \ No newline at end of file diff --git a/tutorial/chapter01/02-implementing-mvvm/README.md b/tutorial/chapter01/02-implementing-mvvm/README.md new file mode 100644 index 000000000..1ddb2e215 --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/README.md @@ -0,0 +1,3 @@ +# Project Files: Implementing Model, View, ViewModel (MVVM) + +Use the files in the **starter** folder to follow the [Implementing Model, View, ViewModel (MVVM)](https://peterfriese.github.io/MakeItSo/tutorials/makeitso) tutorial, you'll create a new Xcode project as described in the first section of the tutorial. To explore on your own, open the Xcode project in the **final** folder and browse the project's code. diff --git a/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo.xcodeproj/project.pbxproj b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo.xcodeproj/project.pbxproj new file mode 100644 index 000000000..00ff6f3fe --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo.xcodeproj/project.pbxproj @@ -0,0 +1,396 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 8842941329AFEEA8002B16B9 /* MakeItSoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842941229AFEEA8002B16B9 /* MakeItSoApp.swift */; }; + 8842941529AFEEA8002B16B9 /* RemindersListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842941429AFEEA8002B16B9 /* RemindersListView.swift */; }; + 8842941729AFEEA9002B16B9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8842941629AFEEA9002B16B9 /* Assets.xcassets */; }; + 8842941A29AFEEA9002B16B9 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8842941929AFEEA9002B16B9 /* Preview Assets.xcassets */; }; + 8842942529AFF792002B16B9 /* Reminder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842942429AFF792002B16B9 /* Reminder.swift */; }; + 8842942729B275B9002B16B9 /* AddReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842942629B275B9002B16B9 /* AddReminderView.swift */; }; + 886FAA722A1278FF004ACF43 /* ReminderListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886FAA712A1278FF004ACF43 /* ReminderListViewModel.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 8842940F29AFEEA8002B16B9 /* MakeItSo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MakeItSo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 8842941229AFEEA8002B16B9 /* MakeItSoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeItSoApp.swift; sourceTree = ""; }; + 8842941429AFEEA8002B16B9 /* RemindersListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemindersListView.swift; sourceTree = ""; }; + 8842941629AFEEA9002B16B9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 8842941929AFEEA9002B16B9 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 8842942429AFF792002B16B9 /* Reminder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reminder.swift; sourceTree = ""; }; + 8842942629B275B9002B16B9 /* AddReminderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddReminderView.swift; sourceTree = ""; }; + 886FAA712A1278FF004ACF43 /* ReminderListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReminderListViewModel.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8842940C29AFEEA8002B16B9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 8842940629AFEEA8002B16B9 = { + isa = PBXGroup; + children = ( + 8842941129AFEEA8002B16B9 /* MakeItSo */, + 8842941029AFEEA8002B16B9 /* Products */, + ); + sourceTree = ""; + }; + 8842941029AFEEA8002B16B9 /* Products */ = { + isa = PBXGroup; + children = ( + 8842940F29AFEEA8002B16B9 /* MakeItSo.app */, + ); + name = Products; + sourceTree = ""; + }; + 8842941129AFEEA8002B16B9 /* MakeItSo */ = { + isa = PBXGroup; + children = ( + 886FAA6C2A127422004ACF43 /* Features */, + 8842941229AFEEA8002B16B9 /* MakeItSoApp.swift */, + 8842941629AFEEA9002B16B9 /* Assets.xcassets */, + 8842941829AFEEA9002B16B9 /* Preview Content */, + ); + path = MakeItSo; + sourceTree = ""; + }; + 8842941829AFEEA9002B16B9 /* Preview Content */ = { + isa = PBXGroup; + children = ( + 8842941929AFEEA9002B16B9 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + 886FAA6C2A127422004ACF43 /* Features */ = { + isa = PBXGroup; + children = ( + 886FAA6D2A12742C004ACF43 /* Reminders */, + ); + path = Features; + sourceTree = ""; + }; + 886FAA6D2A12742C004ACF43 /* Reminders */ = { + isa = PBXGroup; + children = ( + 886FAA6E2A12743E004ACF43 /* Models */, + 886FAA6F2A127444004ACF43 /* ViewModels */, + 886FAA702A12744A004ACF43 /* Views */, + ); + path = Reminders; + sourceTree = ""; + }; + 886FAA6E2A12743E004ACF43 /* Models */ = { + isa = PBXGroup; + children = ( + 8842942429AFF792002B16B9 /* Reminder.swift */, + ); + path = Models; + sourceTree = ""; + }; + 886FAA6F2A127444004ACF43 /* ViewModels */ = { + isa = PBXGroup; + children = ( + 886FAA712A1278FF004ACF43 /* ReminderListViewModel.swift */, + ); + path = ViewModels; + sourceTree = ""; + }; + 886FAA702A12744A004ACF43 /* Views */ = { + isa = PBXGroup; + children = ( + 8842941429AFEEA8002B16B9 /* RemindersListView.swift */, + 8842942629B275B9002B16B9 /* AddReminderView.swift */, + ); + path = Views; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8842940E29AFEEA8002B16B9 /* MakeItSo */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8842941D29AFEEA9002B16B9 /* Build configuration list for PBXNativeTarget "MakeItSo" */; + buildPhases = ( + 8842940B29AFEEA8002B16B9 /* Sources */, + 8842940C29AFEEA8002B16B9 /* Frameworks */, + 8842940D29AFEEA8002B16B9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MakeItSo; + productName = MakeItSo; + productReference = 8842940F29AFEEA8002B16B9 /* MakeItSo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 8842940729AFEEA8002B16B9 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1420; + LastUpgradeCheck = 1420; + TargetAttributes = { + 8842940E29AFEEA8002B16B9 = { + CreatedOnToolsVersion = 14.2; + }; + }; + }; + buildConfigurationList = 8842940A29AFEEA8002B16B9 /* Build configuration list for PBXProject "MakeItSo" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 8842940629AFEEA8002B16B9; + productRefGroup = 8842941029AFEEA8002B16B9 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8842940E29AFEEA8002B16B9 /* MakeItSo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8842940D29AFEEA8002B16B9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8842941A29AFEEA9002B16B9 /* Preview Assets.xcassets in Resources */, + 8842941729AFEEA9002B16B9 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8842940B29AFEEA8002B16B9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8842942529AFF792002B16B9 /* Reminder.swift in Sources */, + 8842941529AFEEA8002B16B9 /* RemindersListView.swift in Sources */, + 886FAA722A1278FF004ACF43 /* ReminderListViewModel.swift in Sources */, + 8842942729B275B9002B16B9 /* AddReminderView.swift in Sources */, + 8842941329AFEEA8002B16B9 /* MakeItSoApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 8842941B29AFEEA9002B16B9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 8842941C29AFEEA9002B16B9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 8842941E29AFEEA9002B16B9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"MakeItSo/Preview Content\""; + DEVELOPMENT_TEAM = ""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.MakeItSo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 8842941F29AFEEA9002B16B9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"MakeItSo/Preview Content\""; + DEVELOPMENT_TEAM = ""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.MakeItSo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 8842940A29AFEEA8002B16B9 /* Build configuration list for PBXProject "MakeItSo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8842941B29AFEEA9002B16B9 /* Debug */, + 8842941C29AFEEA9002B16B9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8842941D29AFEEA9002B16B9 /* Build configuration list for PBXNativeTarget "MakeItSo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8842941E29AFEEA9002B16B9 /* Debug */, + 8842941F29AFEEA9002B16B9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 8842940729AFEEA8002B16B9 /* Project object */; +} diff --git a/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Assets.xcassets/AccentColor.colorset/Contents.json b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 000000000..eb8789700 --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Assets.xcassets/AppIcon.appiconset/Contents.json b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..13613e3ee --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Assets.xcassets/Contents.json b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Features/Reminders/Models/Reminder.swift b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Features/Reminders/Models/Reminder.swift new file mode 100644 index 000000000..54734c9fd --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Features/Reminders/Models/Reminder.swift @@ -0,0 +1,34 @@ +// +// Reminder.swift +// MakeItSo +// +// Created by Peter Friese on 01.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +struct Reminder: Identifiable { + let id = UUID() + var title: String + var isCompleted = false +} + +extension Reminder { + static let samples = [ + Reminder(title: "Build sample app", isCompleted: true), + Reminder(title: "Create tutorial"), + Reminder(title: "???"), + Reminder(title: "PROFIT!"), + ] +} diff --git a/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Features/Reminders/ViewModels/ReminderListViewModel.swift b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Features/Reminders/ViewModels/ReminderListViewModel.swift new file mode 100644 index 000000000..0656656e9 --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Features/Reminders/ViewModels/ReminderListViewModel.swift @@ -0,0 +1,34 @@ +// +// ReminderListViewModel.swift +// MakeItSo +// +// Created by Peter Friese on 15.05.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +class RemindersListViewModel: ObservableObject { + @Published + var reminders = Reminder.samples + + func addReminder(_ reminder: Reminder) { + reminders.append(reminder) + } + + func toggleCompleted(_ reminder: Reminder) { + if let index = reminders.firstIndex(where: { $0.id == reminder.id} ) { + reminders[index].isCompleted.toggle() + } + } +} diff --git a/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Features/Reminders/Views/AddReminderView.swift b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Features/Reminders/Views/AddReminderView.swift new file mode 100644 index 000000000..5197fc71c --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Features/Reminders/Views/AddReminderView.swift @@ -0,0 +1,80 @@ +// +// AddReminderView.swift +// MakeItSo +// +// Created by Peter Friese on 03.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftUI + +struct AddReminderView: View { + enum FocusableField: Hashable { + case title + } + + @FocusState + private var focusedField: FocusableField? + + @State + private var reminder = Reminder(title: "") + + @Environment(\.dismiss) + private var dismiss + + let onCommit: (_ reminder: Reminder) -> Void + + private func commit() { + onCommit(reminder) + dismiss() + } + + private func cancel() { + dismiss() + } + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + .focused($focusedField, equals: .title) + } + .navigationTitle("New Reminder") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .cancellationAction) { + Button(action: cancel) { + Text("Cancel") + } + } + ToolbarItem(placement: .confirmationAction) { + Button(action: commit) { + Text("Add") + } + .disabled(reminder.title.isEmpty) + } + } + .onAppear { + focusedField = .title + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Features/Reminders/Views/RemindersListView.swift b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Features/Reminders/Views/RemindersListView.swift new file mode 100644 index 000000000..c5596c929 --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Features/Reminders/Views/RemindersListView.swift @@ -0,0 +1,72 @@ +// +// ContentView.swift +// MakeItSo +// +// Created by Peter Friese on 01.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftUI + +struct RemindersListView: View { + @StateObject + private var viewModel = RemindersListViewModel() + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($viewModel.reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + viewModel.toggleCompleted(reminder) + } + Text(reminder.title) + } + } + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + Button(action: presentAddReminderView) { + HStack { + Image(systemName: "plus.circle.fill") + Text("New Reminder") + } + } + Spacer() + } + } + .sheet(isPresented: $isAddReminderDialogPresented) { + AddReminderView { reminder in + viewModel.addReminder(reminder) + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + NavigationStack { + RemindersListView() + .navigationTitle("Reminders") + } + } +} diff --git a/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/MakeItSoApp.swift b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/MakeItSoApp.swift new file mode 100644 index 000000000..921abac96 --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/MakeItSoApp.swift @@ -0,0 +1,31 @@ +// +// MakeItSoApp.swift +// MakeItSo +// +// Created by Peter Friese on 01.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftUI + +@main +struct MakeItSoApp: App { + var body: some Scene { + WindowGroup { + NavigationStack { + RemindersListView() + .navigationTitle("Reminders") + } + } + } +} diff --git a/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Preview Content/Preview Assets.xcassets/Contents.json b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/final/MakeItSo/MakeItSo/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tutorial/chapter01/02-implementing-mvvm/final/README.md b/tutorial/chapter01/02-implementing-mvvm/final/README.md new file mode 100644 index 000000000..6fafa5315 --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/final/README.md @@ -0,0 +1,3 @@ +# Implementing Model, View, ViewModel (MVVM) - Final + +This folder contains the _final_ state for the _Implementing Model, View, ViewModel (MVVM)_ part of the _Make It So_ tutorial. \ No newline at end of file diff --git a/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo.xcodeproj/project.pbxproj b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo.xcodeproj/project.pbxproj new file mode 100644 index 000000000..d95cd2b0a --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo.xcodeproj/project.pbxproj @@ -0,0 +1,352 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 8842941329AFEEA8002B16B9 /* MakeItSoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842941229AFEEA8002B16B9 /* MakeItSoApp.swift */; }; + 8842941529AFEEA8002B16B9 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842941429AFEEA8002B16B9 /* ContentView.swift */; }; + 8842941729AFEEA9002B16B9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8842941629AFEEA9002B16B9 /* Assets.xcassets */; }; + 8842941A29AFEEA9002B16B9 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8842941929AFEEA9002B16B9 /* Preview Assets.xcassets */; }; + 8842942529AFF792002B16B9 /* Reminder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842942429AFF792002B16B9 /* Reminder.swift */; }; + 8842942729B275B9002B16B9 /* AddReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8842942629B275B9002B16B9 /* AddReminderView.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 8842940F29AFEEA8002B16B9 /* MakeItSo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MakeItSo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 8842941229AFEEA8002B16B9 /* MakeItSoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeItSoApp.swift; sourceTree = ""; }; + 8842941429AFEEA8002B16B9 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 8842941629AFEEA9002B16B9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 8842941929AFEEA9002B16B9 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 8842942429AFF792002B16B9 /* Reminder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reminder.swift; sourceTree = ""; }; + 8842942629B275B9002B16B9 /* AddReminderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddReminderView.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8842940C29AFEEA8002B16B9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 8842940629AFEEA8002B16B9 = { + isa = PBXGroup; + children = ( + 8842941129AFEEA8002B16B9 /* MakeItSo */, + 8842941029AFEEA8002B16B9 /* Products */, + ); + sourceTree = ""; + }; + 8842941029AFEEA8002B16B9 /* Products */ = { + isa = PBXGroup; + children = ( + 8842940F29AFEEA8002B16B9 /* MakeItSo.app */, + ); + name = Products; + sourceTree = ""; + }; + 8842941129AFEEA8002B16B9 /* MakeItSo */ = { + isa = PBXGroup; + children = ( + 8842941229AFEEA8002B16B9 /* MakeItSoApp.swift */, + 8842941429AFEEA8002B16B9 /* ContentView.swift */, + 8842941629AFEEA9002B16B9 /* Assets.xcassets */, + 8842941829AFEEA9002B16B9 /* Preview Content */, + 8842942429AFF792002B16B9 /* Reminder.swift */, + 8842942629B275B9002B16B9 /* AddReminderView.swift */, + ); + path = MakeItSo; + sourceTree = ""; + }; + 8842941829AFEEA9002B16B9 /* Preview Content */ = { + isa = PBXGroup; + children = ( + 8842941929AFEEA9002B16B9 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8842940E29AFEEA8002B16B9 /* MakeItSo */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8842941D29AFEEA9002B16B9 /* Build configuration list for PBXNativeTarget "MakeItSo" */; + buildPhases = ( + 8842940B29AFEEA8002B16B9 /* Sources */, + 8842940C29AFEEA8002B16B9 /* Frameworks */, + 8842940D29AFEEA8002B16B9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MakeItSo; + productName = MakeItSo; + productReference = 8842940F29AFEEA8002B16B9 /* MakeItSo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 8842940729AFEEA8002B16B9 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1420; + LastUpgradeCheck = 1420; + TargetAttributes = { + 8842940E29AFEEA8002B16B9 = { + CreatedOnToolsVersion = 14.2; + }; + }; + }; + buildConfigurationList = 8842940A29AFEEA8002B16B9 /* Build configuration list for PBXProject "MakeItSo" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 8842940629AFEEA8002B16B9; + productRefGroup = 8842941029AFEEA8002B16B9 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8842940E29AFEEA8002B16B9 /* MakeItSo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8842940D29AFEEA8002B16B9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8842941A29AFEEA9002B16B9 /* Preview Assets.xcassets in Resources */, + 8842941729AFEEA9002B16B9 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8842940B29AFEEA8002B16B9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8842942529AFF792002B16B9 /* Reminder.swift in Sources */, + 8842941529AFEEA8002B16B9 /* ContentView.swift in Sources */, + 8842942729B275B9002B16B9 /* AddReminderView.swift in Sources */, + 8842941329AFEEA8002B16B9 /* MakeItSoApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 8842941B29AFEEA9002B16B9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 8842941C29AFEEA9002B16B9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 8842941E29AFEEA9002B16B9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"MakeItSo/Preview Content\""; + DEVELOPMENT_TEAM = ""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.MakeItSo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 8842941F29AFEEA9002B16B9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"MakeItSo/Preview Content\""; + DEVELOPMENT_TEAM = ""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.MakeItSo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 8842940A29AFEEA8002B16B9 /* Build configuration list for PBXProject "MakeItSo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8842941B29AFEEA9002B16B9 /* Debug */, + 8842941C29AFEEA9002B16B9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8842941D29AFEEA9002B16B9 /* Build configuration list for PBXNativeTarget "MakeItSo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8842941E29AFEEA9002B16B9 /* Debug */, + 8842941F29AFEEA9002B16B9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 8842940729AFEEA8002B16B9 /* Project object */; +} diff --git a/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/AddReminderView.swift b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/AddReminderView.swift new file mode 100644 index 000000000..5197fc71c --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/AddReminderView.swift @@ -0,0 +1,80 @@ +// +// AddReminderView.swift +// MakeItSo +// +// Created by Peter Friese on 03.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftUI + +struct AddReminderView: View { + enum FocusableField: Hashable { + case title + } + + @FocusState + private var focusedField: FocusableField? + + @State + private var reminder = Reminder(title: "") + + @Environment(\.dismiss) + private var dismiss + + let onCommit: (_ reminder: Reminder) -> Void + + private func commit() { + onCommit(reminder) + dismiss() + } + + private func cancel() { + dismiss() + } + + var body: some View { + NavigationStack { + Form { + TextField("Title", text: $reminder.title) + .focused($focusedField, equals: .title) + } + .navigationTitle("New Reminder") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .cancellationAction) { + Button(action: cancel) { + Text("Cancel") + } + } + ToolbarItem(placement: .confirmationAction) { + Button(action: commit) { + Text("Add") + } + .disabled(reminder.title.isEmpty) + } + } + .onAppear { + focusedField = .title + } + } + } +} + +struct AddReminderView_Previews: PreviewProvider { + static var previews: some View { + AddReminderView { reminder in + print("You added a new reminder titled \(reminder.title)") + } + } +} diff --git a/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/Assets.xcassets/AccentColor.colorset/Contents.json b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 000000000..eb8789700 --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/Assets.xcassets/AppIcon.appiconset/Contents.json b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..13613e3ee --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/Assets.xcassets/Contents.json b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/ContentView.swift b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/ContentView.swift new file mode 100644 index 000000000..ab5a811d8 --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/ContentView.swift @@ -0,0 +1,72 @@ +// +// ContentView.swift +// MakeItSo +// +// Created by Peter Friese on 01.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftUI + +struct ContentView: View { + @State + private var reminders = Reminder.samples + + @State + private var isAddReminderDialogPresented = false + + private func presentAddReminderView() { + isAddReminderDialogPresented.toggle() + } + + var body: some View { + List($reminders) { $reminder in + HStack { + Image(systemName: reminder.isCompleted + ? "largecircle.fill.circle" + : "circle") + .imageScale(.large) + .foregroundColor(.accentColor) + .onTapGesture { + reminder.isCompleted.toggle() + } + Text(reminder.title) + } + } + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + Button(action: presentAddReminderView) { + HStack { + Image(systemName: "plus.circle.fill") + Text("New Reminder") + } + } + Spacer() + } + } + .sheet(isPresented: $isAddReminderDialogPresented) { + AddReminderView { reminder in + reminders.append(reminder) + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + NavigationStack { + ContentView() + .navigationTitle("Reminders") + } + } +} diff --git a/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/MakeItSoApp.swift b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/MakeItSoApp.swift new file mode 100644 index 000000000..9bf564661 --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/MakeItSoApp.swift @@ -0,0 +1,31 @@ +// +// MakeItSoApp.swift +// MakeItSo +// +// Created by Peter Friese on 01.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftUI + +@main +struct MakeItSoApp: App { + var body: some Scene { + WindowGroup { + NavigationStack { + ContentView() + .navigationTitle("Reminders") + } + } + } +} diff --git a/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/Preview Content/Preview Assets.xcassets/Contents.json b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/Reminder.swift b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/Reminder.swift new file mode 100644 index 000000000..54734c9fd --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/starter/MakeItSo/MakeItSo/Reminder.swift @@ -0,0 +1,34 @@ +// +// Reminder.swift +// MakeItSo +// +// Created by Peter Friese on 01.03.23. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +struct Reminder: Identifiable { + let id = UUID() + var title: String + var isCompleted = false +} + +extension Reminder { + static let samples = [ + Reminder(title: "Build sample app", isCompleted: true), + Reminder(title: "Create tutorial"), + Reminder(title: "???"), + Reminder(title: "PROFIT!"), + ] +} diff --git a/tutorial/chapter01/02-implementing-mvvm/starter/README.md b/tutorial/chapter01/02-implementing-mvvm/starter/README.md new file mode 100644 index 000000000..b9df7ae3b --- /dev/null +++ b/tutorial/chapter01/02-implementing-mvvm/starter/README.md @@ -0,0 +1,3 @@ +# Implementing Model, View, ViewModel (MVVM) - Starter + +This folder contains the _starter_ project for the _Implementing Model, View, ViewModel (MVVM)_ part of the _Make It So_ tutorial. \ No newline at end of file