├── AppWidget
├── AppWidget.swift
├── AppWidgetBundle.swift
├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ └── WidgetBackground.colorset
│ │ └── Contents.json
└── Info.plist
├── AppWidgetExtension.entitlements
├── MacWidget
├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ └── WidgetBackground.colorset
│ │ └── Contents.json
├── Info.plist
├── MacWidget.entitlements
├── MacWidget.swift
└── MacWidgetBundle.swift
├── README.md
├── WidgetIntermediateAnimation.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcshareddata
│ └── xcschemes
│ │ ├── AppWidgetExtension.xcscheme
│ │ └── WidgetIntermediateAnimation.xcscheme
└── xcuserdata
│ ├── chaos.xcuserdatad
│ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ │ └── xcschememanagement.plist
│ └── juniperphoton.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
└── WidgetIntermediateAnimation
├── AppModelContainer.swift
├── Assets.xcassets
├── AccentColor.colorset
│ └── Contents.json
├── AppIcon.appiconset
│ └── Contents.json
└── Contents.json
├── ContentView.swift
├── Item.swift
├── Preview Content
└── Preview Assets.xcassets
│ └── Contents.json
├── WidgetIntermediateAnimation.entitlements
├── WidgetIntermediateAnimationApp.swift
└── WidgetShared.swift
/AppWidget/AppWidget.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppWidget.swift
3 | // AppWidget
4 | //
5 | // Created by chaos on 2023/8/23.
6 | //
7 |
8 | import WidgetKit
9 | import SwiftUI
10 | import SwiftData
11 | import AppIntents
12 |
13 | struct AppWidget: Widget {
14 | let kind: String = "AppWidget"
15 |
16 | var body: some WidgetConfiguration {
17 | StaticConfiguration(kind: kind, provider: Provider()) { entry in
18 | if #available(iOS 17.0, *) {
19 | AppWidgetEntryView(entry: entry)
20 | .containerBackground(.fill.tertiary, for: .widget)
21 | } else {
22 | AppWidgetEntryView(entry: entry)
23 | .padding()
24 | .background()
25 | }
26 | }
27 | .configurationDisplayName("My Widget")
28 | .description("This is an example widget.")
29 | }
30 | }
31 |
32 | #Preview(as: WidgetFamily.systemLarge) {
33 | AppWidget()
34 | } timeline: {
35 | SimpleEntry(date: .now, items: [])
36 | SimpleEntry(date: .now, items: [
37 | .init(id: "0", text: "first", completedDate: nil)
38 | ])
39 | SimpleEntry(date: .now, items: [
40 | .init(id: "0", text: "first", completedDate: nil),
41 | .init(id: "1", text: "second", completedDate: nil)
42 | ])
43 | SimpleEntry(date: .now, items: [
44 | .init(id: "0", text: "first", completedDate: .now),
45 | .init(id: "1", text: "second", completedDate: nil)
46 | ])
47 | SimpleEntry(date: .now, items: [])
48 | }
49 |
--------------------------------------------------------------------------------
/AppWidget/AppWidgetBundle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppWidgetBundle.swift
3 | // AppWidget
4 | //
5 | // Created by chaos on 2023/8/23.
6 | //
7 |
8 | import WidgetKit
9 | import SwiftUI
10 |
11 | @main
12 | struct AppWidgetBundle: WidgetBundle {
13 | var body: some Widget {
14 | AppWidget()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/AppWidget/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/AppWidget/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "platform" : "ios",
6 | "size" : "1024x1024"
7 | }
8 | ],
9 | "info" : {
10 | "author" : "xcode",
11 | "version" : 1
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/AppWidget/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/AppWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/AppWidget/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSExtension
6 |
7 | NSExtensionPointIdentifier
8 | com.apple.widgetkit-extension
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/AppWidgetExtension.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.application-groups
6 |
7 | group.juniperphoton.widgetanimation
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/MacWidget/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/MacWidget/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "scale" : "1x",
6 | "size" : "16x16"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "scale" : "2x",
11 | "size" : "16x16"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "scale" : "1x",
16 | "size" : "32x32"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "scale" : "2x",
21 | "size" : "32x32"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "scale" : "1x",
26 | "size" : "128x128"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "scale" : "2x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "scale" : "1x",
36 | "size" : "256x256"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "scale" : "2x",
41 | "size" : "256x256"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "scale" : "1x",
46 | "size" : "512x512"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "scale" : "2x",
51 | "size" : "512x512"
52 | }
53 | ],
54 | "info" : {
55 | "author" : "xcode",
56 | "version" : 1
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/MacWidget/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/MacWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/MacWidget/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSExtension
6 |
7 | NSExtensionPointIdentifier
8 | com.apple.widgetkit-extension
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/MacWidget/MacWidget.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.application-groups
8 |
9 | group.juniperphoton.widgetanimation
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/MacWidget/MacWidget.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MacWidget.swift
3 | // MacWidget
4 | //
5 | // Created by chaos on 2023/8/24.
6 | //
7 |
8 | import WidgetKit
9 | import SwiftUI
10 |
11 | struct MacWidget: Widget {
12 | let kind: String = "MacWidget"
13 |
14 | var body: some WidgetConfiguration {
15 | StaticConfiguration(kind: kind, provider: Provider()) { entry in
16 | if #available(macOS 14.0, *) {
17 | AppWidgetEntryView(entry: entry)
18 | .containerBackground(.fill.tertiary, for: .widget)
19 | } else {
20 | AppWidgetEntryView(entry: entry)
21 | .padding()
22 | .background()
23 | }
24 | }
25 | .configurationDisplayName("My Widget")
26 | .description("This is an example widget.")
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/MacWidget/MacWidgetBundle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MacWidgetBundle.swift
3 | // MacWidget
4 | //
5 | // Created by chaos on 2023/8/24.
6 | //
7 |
8 | import WidgetKit
9 | import SwiftUI
10 |
11 | @main
12 | struct MacWidgetBundle: WidgetBundle {
13 | var body: some Widget {
14 | MacWidget()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Widget Intermediate Animation Demo
2 | A demo to demonstrate how to animate widget changes with intermediate state.
3 |
4 | ## Required
5 |
6 | This demo is based on the SwiftData demo in Xcode 15. Currently you need Xcode 15 Beta to open this project and runs on the devices or simulators in iOS 17.
7 |
8 | ## Demo time
9 |
10 | 
11 |
12 |
13 | 1. Build and install the app
14 | 2. Add a widget in the home screen
15 | 3. Launch the app, add some reminders
16 | 4. Go back to the home screen and now you can see the reminders you previously added
17 | 5. Click the circle to the left which will mark a reminder "complete"
18 | 6. Now you can see the circle is filled with a check icon and then disappear with fine animation
19 |
20 | ## Implementation details
21 |
22 | The keys to achieve this effect are:
23 | 1. When the button with `AppIntent` is clicked the `AppIntent`'s perform method will be invoked
24 | 2. After you successfully perform the action, the timeline need to be reconstructed
25 | 3. The timeline should at least contains two entries: one for displaying the "recently completed" items(in this case, the reminder that its completed date is less than 2 seconds to now); and one for displaying the incompleted items.
26 | 4. In iOS 17, the animation is added by the system to animate between two entries in a timeline.
27 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 56;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2238EDEB2A966262006CA6A3 /* WidgetIntermediateAnimationApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2238EDEA2A966262006CA6A3 /* WidgetIntermediateAnimationApp.swift */; };
11 | 2238EDED2A966262006CA6A3 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2238EDEC2A966262006CA6A3 /* ContentView.swift */; };
12 | 2238EDEF2A966262006CA6A3 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2238EDEE2A966262006CA6A3 /* Item.swift */; };
13 | 2238EDF12A966263006CA6A3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2238EDF02A966263006CA6A3 /* Assets.xcassets */; };
14 | 2238EDF52A966263006CA6A3 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2238EDF42A966263006CA6A3 /* Preview Assets.xcassets */; };
15 | C450DD4A2A96634700753213 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C450DD492A96634700753213 /* WidgetKit.framework */; };
16 | C450DD4C2A96634700753213 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C450DD4B2A96634700753213 /* SwiftUI.framework */; };
17 | C450DD4F2A96634700753213 /* AppWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C450DD4E2A96634700753213 /* AppWidgetBundle.swift */; };
18 | C450DD512A96634700753213 /* AppWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = C450DD502A96634700753213 /* AppWidget.swift */; };
19 | C450DD532A96634800753213 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C450DD522A96634800753213 /* Assets.xcassets */; };
20 | C450DD572A96634800753213 /* AppWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = C450DD472A96634700753213 /* AppWidgetExtension.appex */; platformFilter = ios; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
21 | C450DD5E2A96641C00753213 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2238EDEE2A966262006CA6A3 /* Item.swift */; };
22 | C450DD612A96651500753213 /* AppModelContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C450DD602A96651500753213 /* AppModelContainer.swift */; };
23 | C450DD622A96651500753213 /* AppModelContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C450DD602A96651500753213 /* AppModelContainer.swift */; };
24 | C49183F12A9730780064E503 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C450DD492A96634700753213 /* WidgetKit.framework */; };
25 | C49183F22A9730780064E503 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C450DD4B2A96634700753213 /* SwiftUI.framework */; };
26 | C49183F52A9730780064E503 /* MacWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49183F42A9730780064E503 /* MacWidgetBundle.swift */; };
27 | C49183F72A9730780064E503 /* MacWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49183F62A9730780064E503 /* MacWidget.swift */; };
28 | C49183F92A9730790064E503 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C49183F82A9730790064E503 /* Assets.xcassets */; };
29 | C49183FE2A9730790064E503 /* MacWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = C49183F02A9730780064E503 /* MacWidgetExtension.appex */; platformFilters = (macos, ); settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
30 | C49184032A9730C00064E503 /* WidgetShared.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49184022A9730C00064E503 /* WidgetShared.swift */; };
31 | C49184042A9730C00064E503 /* WidgetShared.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49184022A9730C00064E503 /* WidgetShared.swift */; };
32 | C49184052A9731200064E503 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2238EDEE2A966262006CA6A3 /* Item.swift */; };
33 | C49184062A9731440064E503 /* AppModelContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C450DD602A96651500753213 /* AppModelContainer.swift */; };
34 | /* End PBXBuildFile section */
35 |
36 | /* Begin PBXContainerItemProxy section */
37 | C450DD552A96634800753213 /* PBXContainerItemProxy */ = {
38 | isa = PBXContainerItemProxy;
39 | containerPortal = 2238EDDF2A966262006CA6A3 /* Project object */;
40 | proxyType = 1;
41 | remoteGlobalIDString = C450DD462A96634700753213;
42 | remoteInfo = AppWidgetExtension;
43 | };
44 | C49183FC2A9730790064E503 /* PBXContainerItemProxy */ = {
45 | isa = PBXContainerItemProxy;
46 | containerPortal = 2238EDDF2A966262006CA6A3 /* Project object */;
47 | proxyType = 1;
48 | remoteGlobalIDString = C49183EF2A9730780064E503;
49 | remoteInfo = MacWidgetExtension;
50 | };
51 | /* End PBXContainerItemProxy section */
52 |
53 | /* Begin PBXCopyFilesBuildPhase section */
54 | C450DD582A96634800753213 /* Embed Foundation Extensions */ = {
55 | isa = PBXCopyFilesBuildPhase;
56 | buildActionMask = 2147483647;
57 | dstPath = "";
58 | dstSubfolderSpec = 13;
59 | files = (
60 | C49183FE2A9730790064E503 /* MacWidgetExtension.appex in Embed Foundation Extensions */,
61 | C450DD572A96634800753213 /* AppWidgetExtension.appex in Embed Foundation Extensions */,
62 | );
63 | name = "Embed Foundation Extensions";
64 | runOnlyForDeploymentPostprocessing = 0;
65 | };
66 | /* End PBXCopyFilesBuildPhase section */
67 |
68 | /* Begin PBXFileReference section */
69 | 2238EDE72A966262006CA6A3 /* WidgetIntermediateAnimation.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WidgetIntermediateAnimation.app; sourceTree = BUILT_PRODUCTS_DIR; };
70 | 2238EDEA2A966262006CA6A3 /* WidgetIntermediateAnimationApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetIntermediateAnimationApp.swift; sourceTree = ""; };
71 | 2238EDEC2A966262006CA6A3 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
72 | 2238EDEE2A966262006CA6A3 /* Item.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Item.swift; sourceTree = ""; };
73 | 2238EDF02A966263006CA6A3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
74 | 2238EDF22A966263006CA6A3 /* WidgetIntermediateAnimation.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WidgetIntermediateAnimation.entitlements; sourceTree = ""; };
75 | 2238EDF42A966263006CA6A3 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
76 | C450DD472A96634700753213 /* AppWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = AppWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
77 | C450DD492A96634700753213 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
78 | C450DD4B2A96634700753213 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
79 | C450DD4E2A96634700753213 /* AppWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppWidgetBundle.swift; sourceTree = ""; };
80 | C450DD502A96634700753213 /* AppWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppWidget.swift; sourceTree = ""; };
81 | C450DD522A96634800753213 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
82 | C450DD542A96634800753213 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
83 | C450DD5C2A9663A700753213 /* AppWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AppWidgetExtension.entitlements; sourceTree = ""; };
84 | C450DD602A96651500753213 /* AppModelContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppModelContainer.swift; sourceTree = ""; };
85 | C49183F02A9730780064E503 /* MacWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = MacWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
86 | C49183F42A9730780064E503 /* MacWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacWidgetBundle.swift; sourceTree = ""; };
87 | C49183F62A9730780064E503 /* MacWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacWidget.swift; sourceTree = ""; };
88 | C49183F82A9730790064E503 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
89 | C49183FA2A9730790064E503 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
90 | C49183FB2A9730790064E503 /* MacWidget.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MacWidget.entitlements; sourceTree = ""; };
91 | C49184022A9730C00064E503 /* WidgetShared.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetShared.swift; sourceTree = ""; };
92 | /* End PBXFileReference section */
93 |
94 | /* Begin PBXFrameworksBuildPhase section */
95 | 2238EDE42A966262006CA6A3 /* Frameworks */ = {
96 | isa = PBXFrameworksBuildPhase;
97 | buildActionMask = 2147483647;
98 | files = (
99 | );
100 | runOnlyForDeploymentPostprocessing = 0;
101 | };
102 | C450DD442A96634700753213 /* Frameworks */ = {
103 | isa = PBXFrameworksBuildPhase;
104 | buildActionMask = 2147483647;
105 | files = (
106 | C450DD4C2A96634700753213 /* SwiftUI.framework in Frameworks */,
107 | C450DD4A2A96634700753213 /* WidgetKit.framework in Frameworks */,
108 | );
109 | runOnlyForDeploymentPostprocessing = 0;
110 | };
111 | C49183ED2A9730780064E503 /* Frameworks */ = {
112 | isa = PBXFrameworksBuildPhase;
113 | buildActionMask = 2147483647;
114 | files = (
115 | C49183F22A9730780064E503 /* SwiftUI.framework in Frameworks */,
116 | C49183F12A9730780064E503 /* WidgetKit.framework in Frameworks */,
117 | );
118 | runOnlyForDeploymentPostprocessing = 0;
119 | };
120 | /* End PBXFrameworksBuildPhase section */
121 |
122 | /* Begin PBXGroup section */
123 | 2238EDDE2A966262006CA6A3 = {
124 | isa = PBXGroup;
125 | children = (
126 | C450DD5C2A9663A700753213 /* AppWidgetExtension.entitlements */,
127 | 2238EDE92A966262006CA6A3 /* WidgetIntermediateAnimation */,
128 | C450DD4D2A96634700753213 /* AppWidget */,
129 | C49183F32A9730780064E503 /* MacWidget */,
130 | C450DD482A96634700753213 /* Frameworks */,
131 | 2238EDE82A966262006CA6A3 /* Products */,
132 | );
133 | sourceTree = "";
134 | };
135 | 2238EDE82A966262006CA6A3 /* Products */ = {
136 | isa = PBXGroup;
137 | children = (
138 | 2238EDE72A966262006CA6A3 /* WidgetIntermediateAnimation.app */,
139 | C450DD472A96634700753213 /* AppWidgetExtension.appex */,
140 | C49183F02A9730780064E503 /* MacWidgetExtension.appex */,
141 | );
142 | name = Products;
143 | sourceTree = "";
144 | };
145 | 2238EDE92A966262006CA6A3 /* WidgetIntermediateAnimation */ = {
146 | isa = PBXGroup;
147 | children = (
148 | 2238EDEA2A966262006CA6A3 /* WidgetIntermediateAnimationApp.swift */,
149 | 2238EDEC2A966262006CA6A3 /* ContentView.swift */,
150 | C450DD602A96651500753213 /* AppModelContainer.swift */,
151 | 2238EDEE2A966262006CA6A3 /* Item.swift */,
152 | C49184022A9730C00064E503 /* WidgetShared.swift */,
153 | 2238EDF02A966263006CA6A3 /* Assets.xcassets */,
154 | 2238EDF22A966263006CA6A3 /* WidgetIntermediateAnimation.entitlements */,
155 | 2238EDF32A966263006CA6A3 /* Preview Content */,
156 | );
157 | path = WidgetIntermediateAnimation;
158 | sourceTree = "";
159 | };
160 | 2238EDF32A966263006CA6A3 /* Preview Content */ = {
161 | isa = PBXGroup;
162 | children = (
163 | 2238EDF42A966263006CA6A3 /* Preview Assets.xcassets */,
164 | );
165 | path = "Preview Content";
166 | sourceTree = "";
167 | };
168 | C450DD482A96634700753213 /* Frameworks */ = {
169 | isa = PBXGroup;
170 | children = (
171 | C450DD492A96634700753213 /* WidgetKit.framework */,
172 | C450DD4B2A96634700753213 /* SwiftUI.framework */,
173 | );
174 | name = Frameworks;
175 | sourceTree = "";
176 | };
177 | C450DD4D2A96634700753213 /* AppWidget */ = {
178 | isa = PBXGroup;
179 | children = (
180 | C450DD4E2A96634700753213 /* AppWidgetBundle.swift */,
181 | C450DD502A96634700753213 /* AppWidget.swift */,
182 | C450DD522A96634800753213 /* Assets.xcassets */,
183 | C450DD542A96634800753213 /* Info.plist */,
184 | );
185 | path = AppWidget;
186 | sourceTree = "";
187 | };
188 | C49183F32A9730780064E503 /* MacWidget */ = {
189 | isa = PBXGroup;
190 | children = (
191 | C49183F42A9730780064E503 /* MacWidgetBundle.swift */,
192 | C49183F62A9730780064E503 /* MacWidget.swift */,
193 | C49183F82A9730790064E503 /* Assets.xcassets */,
194 | C49183FA2A9730790064E503 /* Info.plist */,
195 | C49183FB2A9730790064E503 /* MacWidget.entitlements */,
196 | );
197 | path = MacWidget;
198 | sourceTree = "";
199 | };
200 | /* End PBXGroup section */
201 |
202 | /* Begin PBXNativeTarget section */
203 | 2238EDE62A966262006CA6A3 /* WidgetIntermediateAnimation */ = {
204 | isa = PBXNativeTarget;
205 | buildConfigurationList = 2238EDF82A966263006CA6A3 /* Build configuration list for PBXNativeTarget "WidgetIntermediateAnimation" */;
206 | buildPhases = (
207 | 2238EDE32A966262006CA6A3 /* Sources */,
208 | 2238EDE42A966262006CA6A3 /* Frameworks */,
209 | 2238EDE52A966262006CA6A3 /* Resources */,
210 | C450DD582A96634800753213 /* Embed Foundation Extensions */,
211 | );
212 | buildRules = (
213 | );
214 | dependencies = (
215 | C450DD562A96634800753213 /* PBXTargetDependency */,
216 | C49183FD2A9730790064E503 /* PBXTargetDependency */,
217 | );
218 | name = WidgetIntermediateAnimation;
219 | productName = WidgetIntermediateAnimation;
220 | productReference = 2238EDE72A966262006CA6A3 /* WidgetIntermediateAnimation.app */;
221 | productType = "com.apple.product-type.application";
222 | };
223 | C450DD462A96634700753213 /* AppWidgetExtension */ = {
224 | isa = PBXNativeTarget;
225 | buildConfigurationList = C450DD5B2A96634800753213 /* Build configuration list for PBXNativeTarget "AppWidgetExtension" */;
226 | buildPhases = (
227 | C450DD432A96634700753213 /* Sources */,
228 | C450DD442A96634700753213 /* Frameworks */,
229 | C450DD452A96634700753213 /* Resources */,
230 | );
231 | buildRules = (
232 | );
233 | dependencies = (
234 | );
235 | name = AppWidgetExtension;
236 | productName = AppWidgetExtension;
237 | productReference = C450DD472A96634700753213 /* AppWidgetExtension.appex */;
238 | productType = "com.apple.product-type.app-extension";
239 | };
240 | C49183EF2A9730780064E503 /* MacWidgetExtension */ = {
241 | isa = PBXNativeTarget;
242 | buildConfigurationList = C49184012A9730790064E503 /* Build configuration list for PBXNativeTarget "MacWidgetExtension" */;
243 | buildPhases = (
244 | C49183EC2A9730780064E503 /* Sources */,
245 | C49183ED2A9730780064E503 /* Frameworks */,
246 | C49183EE2A9730780064E503 /* Resources */,
247 | );
248 | buildRules = (
249 | );
250 | dependencies = (
251 | );
252 | name = MacWidgetExtension;
253 | productName = MacWidgetExtension;
254 | productReference = C49183F02A9730780064E503 /* MacWidgetExtension.appex */;
255 | productType = "com.apple.product-type.app-extension";
256 | };
257 | /* End PBXNativeTarget section */
258 |
259 | /* Begin PBXProject section */
260 | 2238EDDF2A966262006CA6A3 /* Project object */ = {
261 | isa = PBXProject;
262 | attributes = {
263 | BuildIndependentTargetsInParallel = 1;
264 | LastSwiftUpdateCheck = 1500;
265 | LastUpgradeCheck = 1500;
266 | TargetAttributes = {
267 | 2238EDE62A966262006CA6A3 = {
268 | CreatedOnToolsVersion = 15.0;
269 | };
270 | C450DD462A96634700753213 = {
271 | CreatedOnToolsVersion = 15.0;
272 | };
273 | C49183EF2A9730780064E503 = {
274 | CreatedOnToolsVersion = 15.0;
275 | };
276 | };
277 | };
278 | buildConfigurationList = 2238EDE22A966262006CA6A3 /* Build configuration list for PBXProject "WidgetIntermediateAnimation" */;
279 | compatibilityVersion = "Xcode 14.0";
280 | developmentRegion = en;
281 | hasScannedForEncodings = 0;
282 | knownRegions = (
283 | en,
284 | Base,
285 | );
286 | mainGroup = 2238EDDE2A966262006CA6A3;
287 | productRefGroup = 2238EDE82A966262006CA6A3 /* Products */;
288 | projectDirPath = "";
289 | projectRoot = "";
290 | targets = (
291 | 2238EDE62A966262006CA6A3 /* WidgetIntermediateAnimation */,
292 | C450DD462A96634700753213 /* AppWidgetExtension */,
293 | C49183EF2A9730780064E503 /* MacWidgetExtension */,
294 | );
295 | };
296 | /* End PBXProject section */
297 |
298 | /* Begin PBXResourcesBuildPhase section */
299 | 2238EDE52A966262006CA6A3 /* Resources */ = {
300 | isa = PBXResourcesBuildPhase;
301 | buildActionMask = 2147483647;
302 | files = (
303 | 2238EDF52A966263006CA6A3 /* Preview Assets.xcassets in Resources */,
304 | 2238EDF12A966263006CA6A3 /* Assets.xcassets in Resources */,
305 | );
306 | runOnlyForDeploymentPostprocessing = 0;
307 | };
308 | C450DD452A96634700753213 /* Resources */ = {
309 | isa = PBXResourcesBuildPhase;
310 | buildActionMask = 2147483647;
311 | files = (
312 | C450DD532A96634800753213 /* Assets.xcassets in Resources */,
313 | );
314 | runOnlyForDeploymentPostprocessing = 0;
315 | };
316 | C49183EE2A9730780064E503 /* Resources */ = {
317 | isa = PBXResourcesBuildPhase;
318 | buildActionMask = 2147483647;
319 | files = (
320 | C49183F92A9730790064E503 /* Assets.xcassets in Resources */,
321 | );
322 | runOnlyForDeploymentPostprocessing = 0;
323 | };
324 | /* End PBXResourcesBuildPhase section */
325 |
326 | /* Begin PBXSourcesBuildPhase section */
327 | 2238EDE32A966262006CA6A3 /* Sources */ = {
328 | isa = PBXSourcesBuildPhase;
329 | buildActionMask = 2147483647;
330 | files = (
331 | 2238EDED2A966262006CA6A3 /* ContentView.swift in Sources */,
332 | 2238EDEF2A966262006CA6A3 /* Item.swift in Sources */,
333 | 2238EDEB2A966262006CA6A3 /* WidgetIntermediateAnimationApp.swift in Sources */,
334 | C450DD612A96651500753213 /* AppModelContainer.swift in Sources */,
335 | );
336 | runOnlyForDeploymentPostprocessing = 0;
337 | };
338 | C450DD432A96634700753213 /* Sources */ = {
339 | isa = PBXSourcesBuildPhase;
340 | buildActionMask = 2147483647;
341 | files = (
342 | C450DD5E2A96641C00753213 /* Item.swift in Sources */,
343 | C450DD622A96651500753213 /* AppModelContainer.swift in Sources */,
344 | C49184032A9730C00064E503 /* WidgetShared.swift in Sources */,
345 | C450DD4F2A96634700753213 /* AppWidgetBundle.swift in Sources */,
346 | C450DD512A96634700753213 /* AppWidget.swift in Sources */,
347 | );
348 | runOnlyForDeploymentPostprocessing = 0;
349 | };
350 | C49183EC2A9730780064E503 /* Sources */ = {
351 | isa = PBXSourcesBuildPhase;
352 | buildActionMask = 2147483647;
353 | files = (
354 | C49184052A9731200064E503 /* Item.swift in Sources */,
355 | C49184062A9731440064E503 /* AppModelContainer.swift in Sources */,
356 | C49184042A9730C00064E503 /* WidgetShared.swift in Sources */,
357 | C49183F52A9730780064E503 /* MacWidgetBundle.swift in Sources */,
358 | C49183F72A9730780064E503 /* MacWidget.swift in Sources */,
359 | );
360 | runOnlyForDeploymentPostprocessing = 0;
361 | };
362 | /* End PBXSourcesBuildPhase section */
363 |
364 | /* Begin PBXTargetDependency section */
365 | C450DD562A96634800753213 /* PBXTargetDependency */ = {
366 | isa = PBXTargetDependency;
367 | platformFilter = ios;
368 | target = C450DD462A96634700753213 /* AppWidgetExtension */;
369 | targetProxy = C450DD552A96634800753213 /* PBXContainerItemProxy */;
370 | };
371 | C49183FD2A9730790064E503 /* PBXTargetDependency */ = {
372 | isa = PBXTargetDependency;
373 | platformFilters = (
374 | macos,
375 | );
376 | target = C49183EF2A9730780064E503 /* MacWidgetExtension */;
377 | targetProxy = C49183FC2A9730790064E503 /* PBXContainerItemProxy */;
378 | };
379 | /* End PBXTargetDependency section */
380 |
381 | /* Begin XCBuildConfiguration section */
382 | 2238EDF62A966263006CA6A3 /* Debug */ = {
383 | isa = XCBuildConfiguration;
384 | buildSettings = {
385 | ALWAYS_SEARCH_USER_PATHS = NO;
386 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
387 | CLANG_ANALYZER_NONNULL = YES;
388 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
389 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
390 | CLANG_ENABLE_MODULES = YES;
391 | CLANG_ENABLE_OBJC_ARC = YES;
392 | CLANG_ENABLE_OBJC_WEAK = YES;
393 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
394 | CLANG_WARN_BOOL_CONVERSION = YES;
395 | CLANG_WARN_COMMA = YES;
396 | CLANG_WARN_CONSTANT_CONVERSION = YES;
397 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
398 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
399 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
400 | CLANG_WARN_EMPTY_BODY = YES;
401 | CLANG_WARN_ENUM_CONVERSION = YES;
402 | CLANG_WARN_INFINITE_RECURSION = YES;
403 | CLANG_WARN_INT_CONVERSION = YES;
404 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
405 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
406 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
407 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
408 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
409 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
410 | CLANG_WARN_STRICT_PROTOTYPES = YES;
411 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
412 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
413 | CLANG_WARN_UNREACHABLE_CODE = YES;
414 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
415 | COPY_PHASE_STRIP = NO;
416 | DEBUG_INFORMATION_FORMAT = dwarf;
417 | ENABLE_STRICT_OBJC_MSGSEND = YES;
418 | ENABLE_TESTABILITY = YES;
419 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
420 | GCC_C_LANGUAGE_STANDARD = gnu17;
421 | GCC_DYNAMIC_NO_PIC = NO;
422 | GCC_NO_COMMON_BLOCKS = YES;
423 | GCC_OPTIMIZATION_LEVEL = 0;
424 | GCC_PREPROCESSOR_DEFINITIONS = (
425 | "DEBUG=1",
426 | "$(inherited)",
427 | );
428 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
429 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
430 | GCC_WARN_UNDECLARED_SELECTOR = YES;
431 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
432 | GCC_WARN_UNUSED_FUNCTION = YES;
433 | GCC_WARN_UNUSED_VARIABLE = YES;
434 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
435 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
436 | MTL_FAST_MATH = YES;
437 | ONLY_ACTIVE_ARCH = YES;
438 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
439 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
440 | };
441 | name = Debug;
442 | };
443 | 2238EDF72A966263006CA6A3 /* Release */ = {
444 | isa = XCBuildConfiguration;
445 | buildSettings = {
446 | ALWAYS_SEARCH_USER_PATHS = NO;
447 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
448 | CLANG_ANALYZER_NONNULL = YES;
449 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
450 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
451 | CLANG_ENABLE_MODULES = YES;
452 | CLANG_ENABLE_OBJC_ARC = YES;
453 | CLANG_ENABLE_OBJC_WEAK = YES;
454 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
455 | CLANG_WARN_BOOL_CONVERSION = YES;
456 | CLANG_WARN_COMMA = YES;
457 | CLANG_WARN_CONSTANT_CONVERSION = YES;
458 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
459 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
460 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
461 | CLANG_WARN_EMPTY_BODY = YES;
462 | CLANG_WARN_ENUM_CONVERSION = YES;
463 | CLANG_WARN_INFINITE_RECURSION = YES;
464 | CLANG_WARN_INT_CONVERSION = YES;
465 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
466 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
467 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
468 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
469 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
470 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
471 | CLANG_WARN_STRICT_PROTOTYPES = YES;
472 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
473 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
474 | CLANG_WARN_UNREACHABLE_CODE = YES;
475 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
476 | COPY_PHASE_STRIP = NO;
477 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
478 | ENABLE_NS_ASSERTIONS = NO;
479 | ENABLE_STRICT_OBJC_MSGSEND = YES;
480 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
481 | GCC_C_LANGUAGE_STANDARD = gnu17;
482 | GCC_NO_COMMON_BLOCKS = YES;
483 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
484 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
485 | GCC_WARN_UNDECLARED_SELECTOR = YES;
486 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
487 | GCC_WARN_UNUSED_FUNCTION = YES;
488 | GCC_WARN_UNUSED_VARIABLE = YES;
489 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
490 | MTL_ENABLE_DEBUG_INFO = NO;
491 | MTL_FAST_MATH = YES;
492 | SWIFT_COMPILATION_MODE = wholemodule;
493 | };
494 | name = Release;
495 | };
496 | 2238EDF92A966263006CA6A3 /* Debug */ = {
497 | isa = XCBuildConfiguration;
498 | buildSettings = {
499 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
500 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
501 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
502 | CODE_SIGN_ENTITLEMENTS = WidgetIntermediateAnimation/WidgetIntermediateAnimation.entitlements;
503 | CODE_SIGN_STYLE = Automatic;
504 | CURRENT_PROJECT_VERSION = 1;
505 | DEVELOPMENT_ASSET_PATHS = "\"WidgetIntermediateAnimation/Preview Content\"";
506 | DEVELOPMENT_TEAM = 7GB9CHCB87;
507 | ENABLE_HARDENED_RUNTIME = YES;
508 | ENABLE_PREVIEWS = YES;
509 | GENERATE_INFOPLIST_FILE = YES;
510 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
511 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
512 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
513 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
514 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
515 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
516 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
517 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
518 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
519 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
520 | IPHONEOS_DEPLOYMENT_TARGET = 17.0;
521 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
522 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
523 | MACOSX_DEPLOYMENT_TARGET = 14.0;
524 | MARKETING_VERSION = 1.0;
525 | PRODUCT_BUNDLE_IDENTIFIER = com.juniperphoton.WidgetIntermediateAnimation;
526 | PRODUCT_NAME = "$(TARGET_NAME)";
527 | SDKROOT = auto;
528 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
529 | SWIFT_EMIT_LOC_STRINGS = YES;
530 | SWIFT_VERSION = 5.0;
531 | TARGETED_DEVICE_FAMILY = "1,2";
532 | };
533 | name = Debug;
534 | };
535 | 2238EDFA2A966263006CA6A3 /* Release */ = {
536 | isa = XCBuildConfiguration;
537 | buildSettings = {
538 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
539 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
540 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
541 | CODE_SIGN_ENTITLEMENTS = WidgetIntermediateAnimation/WidgetIntermediateAnimation.entitlements;
542 | CODE_SIGN_STYLE = Automatic;
543 | CURRENT_PROJECT_VERSION = 1;
544 | DEVELOPMENT_ASSET_PATHS = "\"WidgetIntermediateAnimation/Preview Content\"";
545 | DEVELOPMENT_TEAM = 7GB9CHCB87;
546 | ENABLE_HARDENED_RUNTIME = YES;
547 | ENABLE_PREVIEWS = YES;
548 | GENERATE_INFOPLIST_FILE = YES;
549 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
550 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
551 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
552 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
553 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
554 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
555 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
556 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
557 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
558 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
559 | IPHONEOS_DEPLOYMENT_TARGET = 17.0;
560 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
561 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
562 | MACOSX_DEPLOYMENT_TARGET = 14.0;
563 | MARKETING_VERSION = 1.0;
564 | PRODUCT_BUNDLE_IDENTIFIER = com.juniperphoton.WidgetIntermediateAnimation;
565 | PRODUCT_NAME = "$(TARGET_NAME)";
566 | SDKROOT = auto;
567 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
568 | SWIFT_EMIT_LOC_STRINGS = YES;
569 | SWIFT_VERSION = 5.0;
570 | TARGETED_DEVICE_FAMILY = "1,2";
571 | };
572 | name = Release;
573 | };
574 | C450DD592A96634800753213 /* Debug */ = {
575 | isa = XCBuildConfiguration;
576 | buildSettings = {
577 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
578 | ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
579 | CODE_SIGN_ENTITLEMENTS = AppWidgetExtension.entitlements;
580 | CODE_SIGN_STYLE = Automatic;
581 | CURRENT_PROJECT_VERSION = 1;
582 | DEVELOPMENT_TEAM = 7GB9CHCB87;
583 | GENERATE_INFOPLIST_FILE = YES;
584 | INFOPLIST_FILE = AppWidget/Info.plist;
585 | INFOPLIST_KEY_CFBundleDisplayName = AppWidget;
586 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
587 | IPHONEOS_DEPLOYMENT_TARGET = 17.0;
588 | LD_RUNPATH_SEARCH_PATHS = (
589 | "$(inherited)",
590 | "@executable_path/Frameworks",
591 | "@executable_path/../../Frameworks",
592 | );
593 | MARKETING_VERSION = 1.0;
594 | PRODUCT_BUNDLE_IDENTIFIER = com.juniperphoton.WidgetIntermediateAnimation.AppWidget;
595 | PRODUCT_NAME = "$(TARGET_NAME)";
596 | SDKROOT = iphoneos;
597 | SKIP_INSTALL = YES;
598 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
599 | SUPPORTS_MACCATALYST = NO;
600 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
601 | SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
602 | SWIFT_EMIT_LOC_STRINGS = YES;
603 | SWIFT_VERSION = 5.0;
604 | TARGETED_DEVICE_FAMILY = "1,2";
605 | };
606 | name = Debug;
607 | };
608 | C450DD5A2A96634800753213 /* Release */ = {
609 | isa = XCBuildConfiguration;
610 | buildSettings = {
611 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
612 | ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
613 | CODE_SIGN_ENTITLEMENTS = AppWidgetExtension.entitlements;
614 | CODE_SIGN_STYLE = Automatic;
615 | CURRENT_PROJECT_VERSION = 1;
616 | DEVELOPMENT_TEAM = 7GB9CHCB87;
617 | GENERATE_INFOPLIST_FILE = YES;
618 | INFOPLIST_FILE = AppWidget/Info.plist;
619 | INFOPLIST_KEY_CFBundleDisplayName = AppWidget;
620 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
621 | IPHONEOS_DEPLOYMENT_TARGET = 17.0;
622 | LD_RUNPATH_SEARCH_PATHS = (
623 | "$(inherited)",
624 | "@executable_path/Frameworks",
625 | "@executable_path/../../Frameworks",
626 | );
627 | MARKETING_VERSION = 1.0;
628 | PRODUCT_BUNDLE_IDENTIFIER = com.juniperphoton.WidgetIntermediateAnimation.AppWidget;
629 | PRODUCT_NAME = "$(TARGET_NAME)";
630 | SDKROOT = iphoneos;
631 | SKIP_INSTALL = YES;
632 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
633 | SUPPORTS_MACCATALYST = NO;
634 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
635 | SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
636 | SWIFT_EMIT_LOC_STRINGS = YES;
637 | SWIFT_VERSION = 5.0;
638 | TARGETED_DEVICE_FAMILY = "1,2";
639 | VALIDATE_PRODUCT = YES;
640 | };
641 | name = Release;
642 | };
643 | C49183FF2A9730790064E503 /* Debug */ = {
644 | isa = XCBuildConfiguration;
645 | buildSettings = {
646 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
647 | ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
648 | CODE_SIGN_ENTITLEMENTS = MacWidget/MacWidget.entitlements;
649 | CODE_SIGN_STYLE = Automatic;
650 | CURRENT_PROJECT_VERSION = 1;
651 | DEVELOPMENT_TEAM = 7GB9CHCB87;
652 | ENABLE_HARDENED_RUNTIME = YES;
653 | GENERATE_INFOPLIST_FILE = YES;
654 | INFOPLIST_FILE = MacWidget/Info.plist;
655 | INFOPLIST_KEY_CFBundleDisplayName = MacWidget;
656 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
657 | LD_RUNPATH_SEARCH_PATHS = (
658 | "$(inherited)",
659 | "@executable_path/../Frameworks",
660 | "@executable_path/../../../../Frameworks",
661 | );
662 | MACOSX_DEPLOYMENT_TARGET = 14.0;
663 | MARKETING_VERSION = 1.0;
664 | PRODUCT_BUNDLE_IDENTIFIER = com.juniperphoton.WidgetIntermediateAnimation.MacWidget;
665 | PRODUCT_NAME = "$(TARGET_NAME)";
666 | SDKROOT = macosx;
667 | SKIP_INSTALL = YES;
668 | SWIFT_EMIT_LOC_STRINGS = YES;
669 | SWIFT_VERSION = 5.0;
670 | };
671 | name = Debug;
672 | };
673 | C49184002A9730790064E503 /* Release */ = {
674 | isa = XCBuildConfiguration;
675 | buildSettings = {
676 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
677 | ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
678 | CODE_SIGN_ENTITLEMENTS = MacWidget/MacWidget.entitlements;
679 | CODE_SIGN_STYLE = Automatic;
680 | CURRENT_PROJECT_VERSION = 1;
681 | DEVELOPMENT_TEAM = 7GB9CHCB87;
682 | ENABLE_HARDENED_RUNTIME = YES;
683 | GENERATE_INFOPLIST_FILE = YES;
684 | INFOPLIST_FILE = MacWidget/Info.plist;
685 | INFOPLIST_KEY_CFBundleDisplayName = MacWidget;
686 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
687 | LD_RUNPATH_SEARCH_PATHS = (
688 | "$(inherited)",
689 | "@executable_path/../Frameworks",
690 | "@executable_path/../../../../Frameworks",
691 | );
692 | MACOSX_DEPLOYMENT_TARGET = 14.0;
693 | MARKETING_VERSION = 1.0;
694 | PRODUCT_BUNDLE_IDENTIFIER = com.juniperphoton.WidgetIntermediateAnimation.MacWidget;
695 | PRODUCT_NAME = "$(TARGET_NAME)";
696 | SDKROOT = macosx;
697 | SKIP_INSTALL = YES;
698 | SWIFT_EMIT_LOC_STRINGS = YES;
699 | SWIFT_VERSION = 5.0;
700 | };
701 | name = Release;
702 | };
703 | /* End XCBuildConfiguration section */
704 |
705 | /* Begin XCConfigurationList section */
706 | 2238EDE22A966262006CA6A3 /* Build configuration list for PBXProject "WidgetIntermediateAnimation" */ = {
707 | isa = XCConfigurationList;
708 | buildConfigurations = (
709 | 2238EDF62A966263006CA6A3 /* Debug */,
710 | 2238EDF72A966263006CA6A3 /* Release */,
711 | );
712 | defaultConfigurationIsVisible = 0;
713 | defaultConfigurationName = Release;
714 | };
715 | 2238EDF82A966263006CA6A3 /* Build configuration list for PBXNativeTarget "WidgetIntermediateAnimation" */ = {
716 | isa = XCConfigurationList;
717 | buildConfigurations = (
718 | 2238EDF92A966263006CA6A3 /* Debug */,
719 | 2238EDFA2A966263006CA6A3 /* Release */,
720 | );
721 | defaultConfigurationIsVisible = 0;
722 | defaultConfigurationName = Release;
723 | };
724 | C450DD5B2A96634800753213 /* Build configuration list for PBXNativeTarget "AppWidgetExtension" */ = {
725 | isa = XCConfigurationList;
726 | buildConfigurations = (
727 | C450DD592A96634800753213 /* Debug */,
728 | C450DD5A2A96634800753213 /* Release */,
729 | );
730 | defaultConfigurationIsVisible = 0;
731 | defaultConfigurationName = Release;
732 | };
733 | C49184012A9730790064E503 /* Build configuration list for PBXNativeTarget "MacWidgetExtension" */ = {
734 | isa = XCConfigurationList;
735 | buildConfigurations = (
736 | C49183FF2A9730790064E503 /* Debug */,
737 | C49184002A9730790064E503 /* Release */,
738 | );
739 | defaultConfigurationIsVisible = 0;
740 | defaultConfigurationName = Release;
741 | };
742 | /* End XCConfigurationList section */
743 | };
744 | rootObject = 2238EDDF2A966262006CA6A3 /* Project object */;
745 | }
746 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation.xcodeproj/xcshareddata/xcschemes/AppWidgetExtension.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
6 |
9 |
10 |
16 |
22 |
23 |
24 |
30 |
36 |
37 |
38 |
39 |
40 |
46 |
47 |
59 |
62 |
68 |
69 |
70 |
71 |
77 |
78 |
79 |
80 |
84 |
85 |
89 |
90 |
94 |
95 |
96 |
97 |
105 |
107 |
113 |
114 |
115 |
116 |
118 |
119 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation.xcodeproj/xcshareddata/xcschemes/WidgetIntermediateAnimation.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
42 |
44 |
50 |
51 |
52 |
53 |
59 |
61 |
67 |
68 |
69 |
70 |
72 |
73 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation.xcodeproj/xcuserdata/chaos.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation.xcodeproj/xcuserdata/chaos.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | AppWidgetExtension.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 | MacWidgetExtension.xcscheme_^#shared#^_
13 |
14 | orderHint
15 | 2
16 |
17 | WidgetIntermediateAnimation.xcscheme_^#shared#^_
18 |
19 | orderHint
20 | 1
21 |
22 |
23 | SuppressBuildableAutocreation
24 |
25 | 2238EDE62A966262006CA6A3
26 |
27 | primary
28 |
29 |
30 | C450DD462A96634700753213
31 |
32 | primary
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation.xcodeproj/xcuserdata/juniperphoton.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | WidgetIntermediateAnimation.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation/AppModelContainer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppModelContainer.swift
3 | // WidgetIntermediateAnimation
4 | //
5 | // Created by chaos on 2023/8/24.
6 | //
7 |
8 | import Foundation
9 | import SwiftData
10 |
11 | var sharedModelContainer: ModelContainer = {
12 | let schema = Schema([
13 | Item.self,
14 | ])
15 | let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
16 |
17 | do {
18 | return try ModelContainer(for: schema, configurations: [modelConfiguration])
19 | } catch {
20 | fatalError("Could not create ModelContainer: \(error)")
21 | }
22 | }()
23 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "platform" : "ios",
6 | "size" : "1024x1024"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "scale" : "1x",
11 | "size" : "16x16"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "scale" : "2x",
16 | "size" : "16x16"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "scale" : "1x",
21 | "size" : "32x32"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "scale" : "2x",
26 | "size" : "32x32"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "scale" : "1x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "scale" : "2x",
36 | "size" : "128x128"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "scale" : "1x",
41 | "size" : "256x256"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "scale" : "2x",
46 | "size" : "256x256"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "scale" : "1x",
51 | "size" : "512x512"
52 | },
53 | {
54 | "idiom" : "mac",
55 | "scale" : "2x",
56 | "size" : "512x512"
57 | }
58 | ],
59 | "info" : {
60 | "author" : "xcode",
61 | "version" : 1
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // WidgetIntermediateAnimation
4 | //
5 | // Created by Photon Juniper on 2023/8/23.
6 | //
7 |
8 | import SwiftUI
9 | import SwiftData
10 | import WidgetKit
11 |
12 | struct ContentView: View {
13 | @Environment(\.scenePhase) private var scenePhase
14 | @Environment(\.modelContext) private var modelContext
15 |
16 | @Query(sort: [SortDescriptor(\Item.createdDate, order: .reverse)],
17 | animation: .default)
18 | private var items: [Item]
19 |
20 | @State private var inputText = ""
21 |
22 | var body: some View {
23 | NavigationSplitView {
24 | VStack {
25 | HStack {
26 | TextField("Input text to add", text: $inputText)
27 | .onSubmit {
28 | addItem()
29 | }
30 |
31 | Button(action: addItem) {
32 | Image(systemName: "plus.circle.fill")
33 | .resizable()
34 | .scaledToFit()
35 | .frame(width: 30, height: 30)
36 | }
37 | }.padding()
38 |
39 | List {
40 | ForEach(items) { item in
41 | HStack {
42 | Button {
43 | toggleComplete(item: item)
44 | } label: {
45 | Image(systemName: item.completedDate != nil ? "checkmark.circle.fill" : "circle")
46 | }.foregroundStyle(Color.accentColor)
47 |
48 | Text(item.text)
49 | }
50 | }
51 | .onDelete(perform: deleteItems)
52 | }.frame(maxHeight: .infinity, alignment: .top)
53 | }.toolbar {
54 | #if os(iOS)
55 | ToolbarItem(placement: .navigationBarTrailing) {
56 | EditButton()
57 | }
58 |
59 | ToolbarItem(placement: .topBarLeading) {
60 | Button {
61 | deleteAll()
62 | } label: {
63 | Text("Delete all")
64 | }
65 | }
66 | #endif
67 | }
68 | } detail: {
69 | Text("Select an item")
70 | }.onChange(of: items) { _,_ in
71 | WidgetCenter.shared.reloadAllTimelines()
72 | }.onChange(of: scenePhase) { oldValue, newValue in
73 | if newValue == .background {
74 | WidgetCenter.shared.reloadAllTimelines()
75 | }
76 | }
77 | }
78 |
79 | private func toggleComplete(item: Item) {
80 | withAnimation {
81 | if item.completedDate == nil {
82 | item.completedDate = .now
83 | } else {
84 | item.completedDate = nil
85 | }
86 | }
87 |
88 | WidgetCenter.shared.reloadAllTimelines()
89 | }
90 |
91 | private func deleteAll() {
92 | withAnimation {
93 | try? modelContext.delete(model: Item.self)
94 | }
95 | }
96 |
97 | private func addItem() {
98 | if inputText.isEmpty {
99 | return
100 | }
101 |
102 | withAnimation {
103 | let newItem = Item(id: UUID().uuidString, text: inputText, createdDate: .now, completedDate: nil)
104 | modelContext.insert(newItem)
105 | inputText = ""
106 | }
107 |
108 | WidgetCenter.shared.reloadAllTimelines()
109 | }
110 |
111 | private func deleteItems(offsets: IndexSet) {
112 | withAnimation {
113 | for index in offsets {
114 | modelContext.delete(items[index])
115 | }
116 | }
117 |
118 | WidgetCenter.shared.reloadAllTimelines()
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation/Item.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Item.swift
3 | // WidgetIntermediateAnimation
4 | //
5 | // Created by Photon Juniper on 2023/8/23.
6 | //
7 |
8 | import Foundation
9 | import SwiftData
10 |
11 | @Model
12 | final class Item {
13 | var id: String
14 | var text: String
15 | var createdDate: Date?
16 | var completedDate: Date?
17 |
18 | init(id: String, text: String, createdDate: Date?, completedDate: Date?) {
19 | self.id = id
20 | self.text = text
21 | self.createdDate = createdDate
22 | self.completedDate = completedDate
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation/WidgetIntermediateAnimation.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.application-groups
8 |
9 | group.juniperphoton.widgetanimation
10 |
11 | com.apple.security.files.user-selected.read-only
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation/WidgetIntermediateAnimationApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WidgetIntermediateAnimationApp.swift
3 | // WidgetIntermediateAnimation
4 | //
5 | // Created by Photon Juniper on 2023/8/23.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct WidgetIntermediateAnimationApp: App {
12 | var body: some Scene {
13 | WindowGroup {
14 | ContentView()
15 | }
16 | .modelContainer(sharedModelContainer)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/WidgetIntermediateAnimation/WidgetShared.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WidgetShared.swift
3 | // WidgetIntermediateAnimation
4 | //
5 | // Created by chaos on 2023/8/24.
6 | //
7 |
8 | import SwiftUI
9 | import WidgetKit
10 | import AppIntents
11 | import SwiftData
12 |
13 | /// Used in Widget only.
14 | /// If we try to use the ``Item`` with ``@Model`` macro attached,
15 | /// the Xcode preview won't work as expected.
16 | struct SimpleItem {
17 | var id: String
18 | var text: String
19 | var completedDate: Date?
20 | }
21 |
22 | @available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *)
23 | struct ReminderIntent: AppIntent {
24 | static var title: LocalizedStringResource = "Reminder intent"
25 |
26 | @Parameter(title: "Reminder id")
27 | var modelId: String
28 |
29 | init(modelId: String) {
30 | self.modelId = modelId
31 | }
32 |
33 | init() {
34 | // empty
35 | }
36 |
37 | func perform() async throws -> some IntentResult {
38 | let predicate = #Predicate- { item in
39 | item.id == modelId
40 | }
41 | if let item = try? await sharedModelContainer.mainContext.fetch(.init(predicate: predicate)).first {
42 | item.completedDate = .now
43 | }
44 | return .result()
45 | }
46 | }
47 |
48 | struct Provider: TimelineProvider {
49 | func placeholder(in context: Context) -> SimpleEntry {
50 | SimpleEntry(date: Date(), items: [])
51 | }
52 |
53 | func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
54 | let entry = SimpleEntry(date: Date(), items: [])
55 | completion(entry)
56 | }
57 |
58 | func getTimeline(in context: Context, completion: @escaping (Timeline) -> ()) {
59 | Task { @MainActor in
60 | var entries: [SimpleEntry] = []
61 |
62 | let now = Date.now
63 |
64 | let context = sharedModelContainer.mainContext
65 | let items = (try? context.fetch(FetchDescriptor
- ())) ?? []
66 | let simpleItems = items.map { SimpleItem(id: $0.id, text: $0.text, completedDate: $0.completedDate) }
67 |
68 | let recentlyCompletedOrIncompleted = simpleItems.filter { item in
69 | if let completedDate = item.completedDate {
70 | return abs(completedDate.timeIntervalSince(now)) < 2
71 | } else {
72 | return true
73 | }
74 | }
75 |
76 | let incompleted = simpleItems.filter { $0.completedDate == nil }
77 |
78 | // First display items that are recently completed, which completedDate should within 2 seconds from now
79 | entries.append(SimpleEntry(date: now, items: recentlyCompletedOrIncompleted))
80 |
81 | // Then display incomplted items
82 | entries.append(SimpleEntry(date: now.addingTimeInterval(0.5), items: incompleted))
83 |
84 | let timeline = Timeline(entries: entries, policy: .atEnd)
85 | completion(timeline)
86 | }
87 | }
88 | }
89 |
90 | struct SimpleEntry: TimelineEntry {
91 | let date: Date
92 | let items: [SimpleItem]
93 | }
94 |
95 | struct AppWidgetEntryView : View {
96 | var entry: Provider.Entry
97 |
98 | var body: some View {
99 | if entry.items.isEmpty {
100 | Text("No items")
101 | } else {
102 | VStack {
103 | ForEach(entry.items, id: \.id) { item in
104 | HStack {
105 | Button(intent: ReminderIntent(modelId: item.id)) {
106 | if let completedDate = item.completedDate,
107 | abs(completedDate.timeIntervalSince(.now)) < 2 {
108 | Image(systemName: "checkmark.circle.fill")
109 | } else {
110 | Image(systemName: "circle")
111 | }
112 | }.buttonStyle(.plain).foregroundStyle(Color.accentColor)
113 |
114 | Text(item.text).lineLimit(1)
115 | .frame(maxWidth: .infinity, alignment: .leading)
116 | }.transition(.push(from: .bottom))
117 | }
118 | }.frame(maxHeight: .infinity, alignment: .topLeading)
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------