├── 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 | ![ezgif-1-6ad223da6f](https://github.com/JuniperPhoton/WidgetIntermediateAnimation/assets/7578386/26172940-45ea-4cb2-bcbd-5bfdf2557518) 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 | --------------------------------------------------------------------------------