├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .resources ├── Assets │ ├── icon.png │ ├── icon.svg │ ├── logo.png │ ├── logo.svg │ ├── social.png │ └── social.svg ├── Recordings │ ├── AnalogClockWidget.gif │ ├── AppGroupWidget.gif │ ├── AudioPlaybackWidget.gif │ ├── CoreDataWidget.gif │ ├── CountdownWidget.gif │ ├── DeepLinkWidget.gif │ ├── DigitalClockWidget.gif │ ├── DynamicIntentWidget.gif │ ├── EnvironmentWidget.gif │ ├── IntentWidget.gif │ ├── InteractiveWidget.gif │ ├── LiveActivityWidget.gif │ ├── LockScreenWidget.gif │ ├── NetworkWidget.gif │ ├── SharedViewWidget.gif │ ├── SwiftDataWidget.gif │ └── URLImageWidget.gif └── Screenshots │ ├── AnalogClockWidget.png │ ├── AppGroupWidget.png │ ├── AudioPlaybackWidget.png │ ├── CoreDataWidget.png │ ├── CountdownWidget.png │ ├── DeepLinkWidget.png │ ├── DigitalClockWidget.png │ ├── DynamicIntentWidget.png │ ├── EnvironmentWidget.png │ ├── IntentWidget.png │ ├── InteractiveWidget.png │ ├── LiveActivityWidget.png │ ├── LockScreenWidget.png │ ├── NetworkWidget.png │ ├── SharedViewWidget.png │ ├── SwiftDataWidget.png │ └── URLImageWidget.png ├── App ├── App.swift ├── ContentView.swift ├── Navigation │ ├── AppDetailColumn.swift │ ├── AppRoute.swift │ ├── AppScreen.swift │ ├── AppSidebarList.swift │ └── DeepLink+Parser.swift ├── Resources │ └── Assets.xcassets │ │ ├── AccentColor.colorset │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ └── icon.png │ │ └── Contents.json ├── Routes │ └── DeepLink │ │ └── DeepLinkWidgetView.swift ├── Screens │ ├── AppGroup │ │ └── AppGroupWidgetView.swift │ ├── AudioPlayback │ │ └── AudioPlaybackWidgetView.swift │ ├── CoreData │ │ └── CoreDataWidgetView.swift │ ├── DynamicIntent │ │ ├── DynamicIntentWidgetView+Person.swift │ │ └── DynamicIntentWidgetView.swift │ ├── LiveActivity │ │ ├── LiveActivityWidgetView+Model.swift │ │ └── LiveActivityWidgetView.swift │ ├── SharedView │ │ └── SharedViewWidgetView.swift │ └── SwiftData │ │ └── SwiftDataWidgetView.swift └── Supporting Files │ └── App.entitlements ├── Frameworks └── ClockRotationEffect.xcframework │ ├── Info.plist │ ├── ios-arm64 │ └── ClockRotationEffect.framework │ │ ├── ClockRotationEffect │ │ ├── Headers │ │ ├── ClockRotationEffect-Swift.h │ │ └── ClockRotationEffect.h │ │ ├── Info.plist │ │ └── Modules │ │ ├── ClockRotationEffect.swiftmodule │ │ ├── arm64-apple-ios.swiftdoc │ │ └── arm64-apple-ios.swiftinterface │ │ └── module.modulemap │ └── ios-arm64_x86_64-simulator │ └── ClockRotationEffect.framework │ ├── ClockRotationEffect │ ├── Headers │ ├── ClockRotationEffect-Swift.h │ └── ClockRotationEffect.h │ ├── Info.plist │ └── Modules │ ├── ClockRotationEffect.swiftmodule │ ├── arm64-apple-ios-simulator.swiftdoc │ ├── arm64-apple-ios-simulator.swiftinterface │ ├── x86_64-apple-ios-simulator.swiftdoc │ └── x86_64-apple-ios-simulator.swiftinterface │ └── module.modulemap ├── LICENSE.md ├── README.md ├── Shared ├── Components │ ├── AudioPlayer.swift │ ├── DeepLink.swift │ ├── Loadable.swift │ ├── PersistenceController.swift │ ├── UserDefaultKey.swift │ └── WebRepository.swift ├── Extensions │ ├── Array+Extensions.swift │ ├── Date+Extensions.swift │ ├── FileManager+Extensions.swift │ ├── URL+Extensions.swift │ └── UserDefaults+Extensions.swift ├── Logger.swift ├── Models │ ├── AudioPlayback │ │ └── Sound.swift │ ├── CoreData │ │ ├── DataModel.xcdatamodeld │ │ │ └── DataModel.xcdatamodel │ │ │ │ └── contents │ │ └── Document.swift │ ├── DynamicIntent │ │ └── Person.swift │ ├── LiveActivity │ │ ├── Delivery.swift │ │ ├── DeliveryAttributes.swift │ │ └── DeliveryState.swift │ └── SwiftData │ │ └── Product.swift ├── Shared.swift └── WidgetType.swift ├── Widget Examples.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ ├── Widget Examples.xcscheme │ └── Widgets.xcscheme └── Widgets ├── AnalogClockWidget ├── AnalogClockWidget+Entry.swift ├── AnalogClockWidget+EntryView.swift ├── AnalogClockWidget+Provider.swift ├── AnalogClockWidget.swift └── README.md ├── AppGroupWidget ├── AppGroupWidget+Entry.swift ├── AppGroupWidget+EntryView.swift ├── AppGroupWidget+Provider.swift ├── AppGroupWidget.swift └── README.md ├── AudioPlaybackWidget ├── AudioPlaybackWidget+Entry.swift ├── AudioPlaybackWidget+EntryView.swift ├── AudioPlaybackWidget+Provider.swift ├── AudioPlaybackWidget.swift ├── README.md └── Shared │ ├── AudioPlaybackWidget+Intents.swift │ └── AudioPlaybackWidgetButtonsView.swift ├── Components └── WidgetHeaderView.swift ├── CoreDataWidget ├── CoreDataWidget+Entry.swift ├── CoreDataWidget+EntryView.swift ├── CoreDataWidget+Provider.swift ├── CoreDataWidget.swift └── README.md ├── CountdownWidget ├── CountdownWidget+Entry.swift ├── CountdownWidget+EntryView.swift ├── CountdownWidget+Provider.swift ├── CountdownWidget.swift └── README.md ├── DeepLinkWidget ├── DeepLinkWidget+Entry.swift ├── DeepLinkWidget+EntryView.swift ├── DeepLinkWidget+Provider.swift ├── DeepLinkWidget.swift └── README.md ├── DigitalClockWidget ├── DigitalClockWidget+Entry.swift ├── DigitalClockWidget+EntryView.swift ├── DigitalClockWidget+Provider.swift ├── DigitalClockWidget.swift └── README.md ├── DynamicIntentWidget ├── DynamicIntentWidget+Entry.swift ├── DynamicIntentWidget+EntryView.swift ├── DynamicIntentWidget+Intent.swift ├── DynamicIntentWidget+Provider.swift ├── DynamicIntentWidget.swift └── README.md ├── EnvironmentWidget ├── EnvironmentWidget+Entry.swift ├── EnvironmentWidget+EntryView.swift ├── EnvironmentWidget+Provider.swift ├── EnvironmentWidget.swift └── README.md ├── IntentWidget ├── IntentWidget+Entry.swift ├── IntentWidget+EntryView.swift ├── IntentWidget+Intent.swift ├── IntentWidget+Provider.swift ├── IntentWidget.swift └── README.md ├── InteractiveWidget ├── InteractiveWidget+Entry.swift ├── InteractiveWidget+EntryView.swift ├── InteractiveWidget+Intents.swift ├── InteractiveWidget+Provider.swift ├── InteractiveWidget.swift └── README.md ├── LiveActivityWidget ├── LiveActivityWidget.swift ├── README.md └── Shared │ ├── LiveActivityView+Icon.swift │ ├── LiveActivityView+Status.swift │ ├── LiveActivityView+Time.swift │ ├── LiveActivityView+Title.swift │ └── LiveActivityView.swift ├── LockScreenWidget ├── LockScreenWidget+Entry.swift ├── LockScreenWidget+EntryView.swift ├── LockScreenWidget+Provider.swift ├── LockScreenWidget.swift └── README.md ├── NetworkWidget ├── CountryWebRepository.swift ├── NetworkWidget+Entry.swift ├── NetworkWidget+EntryView.swift ├── NetworkWidget+Provider.swift ├── NetworkWidget.swift └── README.md ├── Resources ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ └── icon.png │ └── Contents.json └── main.mp3 ├── SharedViewWidget ├── README.md ├── Shared │ ├── SharedViewWidgetEntry.swift │ └── SharedViewWidgetEntryView.swift ├── SharedViewWidget+Provider.swift └── SharedViewWidget.swift ├── Supporting Files ├── Info.plist └── Widgets.entitlements ├── SwiftDataWidget ├── README.md ├── SwiftDataWidget+Entry.swift ├── SwiftDataWidget+EntryView.swift ├── SwiftDataWidget+Provider.swift └── SwiftDataWidget.swift ├── URLImageWidget ├── README.md ├── URLImageWidget+Entry.swift ├── URLImageWidget+EntryView.swift ├── URLImageWidget+Provider.swift └── URLImageWidget.swift └── WidgetBundle.swift /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | env: 10 | SCHEME: "Widget Examples" 11 | IOS_SDK: "iphonesimulator" 12 | IOS_DESTINATION: "platform=iOS Simulator,name=Any iOS Simulator Device,OS=latest" 13 | 14 | jobs: 15 | lint: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | - name: SwiftLint 21 | uses: norio-nomura/action-swiftlint@3.2.1 22 | 23 | build: 24 | runs-on: macos-latest 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v4 28 | - name: Build 29 | run: | 30 | xcodebuild clean build \ 31 | -scheme "$SCHEME" \ 32 | -sdk "$IOS_SDK" \ 33 | -destination "$IOS_DESTINATION" \ 34 | CODE_SIGNING_ALLOWED=NO 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .build 3 | .swiftpm/xcode/package.xcworkspace 4 | .swiftpm/xcode/xcuserdata 5 | Package.resolved 6 | 7 | xcuserdata 8 | *.xcodeproj/* 9 | !*.xcodeproj/project.pbxproj 10 | !*.xcodeproj/xcshareddata/ 11 | !*.xcworkspace/contents.xcworkspacedata 12 | **/xcshareddata/WorkspaceSettings.xcsettings 13 | -------------------------------------------------------------------------------- /.resources/Assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Assets/icon.png -------------------------------------------------------------------------------- /.resources/Assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Assets/logo.png -------------------------------------------------------------------------------- /.resources/Assets/social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Assets/social.png -------------------------------------------------------------------------------- /.resources/Recordings/AnalogClockWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/AnalogClockWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/AppGroupWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/AppGroupWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/AudioPlaybackWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/AudioPlaybackWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/CoreDataWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/CoreDataWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/CountdownWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/CountdownWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/DeepLinkWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/DeepLinkWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/DigitalClockWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/DigitalClockWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/DynamicIntentWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/DynamicIntentWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/EnvironmentWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/EnvironmentWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/IntentWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/IntentWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/InteractiveWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/InteractiveWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/LiveActivityWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/LiveActivityWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/LockScreenWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/LockScreenWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/NetworkWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/NetworkWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/SharedViewWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/SharedViewWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/SwiftDataWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/SwiftDataWidget.gif -------------------------------------------------------------------------------- /.resources/Recordings/URLImageWidget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Recordings/URLImageWidget.gif -------------------------------------------------------------------------------- /.resources/Screenshots/AnalogClockWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/AnalogClockWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/AppGroupWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/AppGroupWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/AudioPlaybackWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/AudioPlaybackWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/CoreDataWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/CoreDataWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/CountdownWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/CountdownWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/DeepLinkWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/DeepLinkWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/DigitalClockWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/DigitalClockWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/DynamicIntentWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/DynamicIntentWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/EnvironmentWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/EnvironmentWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/IntentWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/IntentWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/InteractiveWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/InteractiveWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/LiveActivityWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/LiveActivityWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/LockScreenWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/LockScreenWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/NetworkWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/NetworkWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/SharedViewWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/SharedViewWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/SwiftDataWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/SwiftDataWidget.png -------------------------------------------------------------------------------- /.resources/Screenshots/URLImageWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/.resources/Screenshots/URLImageWidget.png -------------------------------------------------------------------------------- /App/App.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | @main 26 | struct WidgetExamplesApp: App { 27 | var body: some Scene { 28 | WindowGroup { 29 | let persistenceController = PersistenceController.shared 30 | ContentView() 31 | .environment(\.managedObjectContext, persistenceController.managedObjectContext) 32 | .modelContainer(for: Product.self) 33 | } 34 | } 35 | } 36 | 37 | // MARK: - Screenshots 38 | 39 | extension WidgetExamplesApp { 40 | @MainActor 41 | private func createScreenshot() { 42 | let view = SharedViewWidgetEntryView(entry: .placeholder) 43 | .padding(15) 44 | .frame(width: 150, height: 150) 45 | .background(.white) 46 | .clipShape(RoundedRectangle(cornerRadius: 20)) 47 | .padding(15) 48 | .environment(\.locale, .init(identifier: "en_US")) 49 | let renderer = ImageRenderer(content: view) 50 | renderer.scale = 10 51 | let filename = URL.documentsDirectory.appending(path: "SharedViewWidget.png") 52 | try? renderer.uiImage?.pngData()?.write(to: filename) 53 | print(filename) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /App/ContentView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | struct ContentView: View { 26 | @State private var selection: AppScreen? 27 | 28 | var body: some View { 29 | NavigationSplitView( 30 | columnVisibility: .constant(.doubleColumn), 31 | preferredCompactColumn: .constant(.sidebar) 32 | ) { 33 | AppSidebarList(selection: $selection) 34 | } detail: { 35 | AppDetailColumn(screen: selection) 36 | } 37 | } 38 | } 39 | 40 | // MARK: - Preview 41 | 42 | #Preview { 43 | ContentView() 44 | } 45 | -------------------------------------------------------------------------------- /App/Navigation/AppRoute.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | enum AppRoute: Hashable { 26 | case deepLink(widgetFamily: String) 27 | case liveActivity 28 | } 29 | 30 | // MARK: - View 31 | 32 | extension AppRoute { 33 | @ViewBuilder 34 | var view: some View { 35 | if case .deepLink(let widgetFamily) = self { 36 | DeepLinkWidgetView(widgetFamily: widgetFamily) 37 | } 38 | if case .liveActivity = self { 39 | LiveActivityWidgetView() 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /App/Navigation/AppSidebarList.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | struct AppSidebarList: View { 26 | @Binding var selection: AppScreen? 27 | 28 | var body: some View { 29 | List(AppScreen.allCases, selection: $selection) { screen in 30 | NavigationLink(value: screen) { 31 | Label(screen.title, systemImage: screen.icon) 32 | } 33 | } 34 | .navigationTitle("Widgets") 35 | } 36 | } 37 | 38 | // MARK: - Preview 39 | 40 | #Preview { 41 | NavigationSplitView { 42 | AppSidebarList(selection: .constant(.appGroup)) 43 | } detail: { 44 | Text(verbatim: "Detail column") 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /App/Navigation/DeepLink+Parser.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | 25 | extension DeepLink { 26 | class Parser { 27 | private let url: URL 28 | 29 | init(url: URL) { 30 | self.url = url 31 | } 32 | } 33 | } 34 | 35 | // MARK: - AppRoute 36 | 37 | extension DeepLink.Parser { 38 | func route() -> AppRoute? { 39 | switch url.scheme { 40 | case DeepLink.widgetScheme: 41 | route(widget: url.host()) 42 | default: 43 | nil 44 | } 45 | } 46 | 47 | private func route(widget: String?) -> AppRoute? { 48 | guard let widget else { 49 | return nil 50 | } 51 | switch widget { 52 | case WidgetType.deepLink.kind: 53 | if let widgetFamily = url.queryParameter(name: DeepLink.widgetFamilyParamName) { 54 | return .deepLink(widgetFamily: widgetFamily) 55 | } 56 | return nil 57 | case WidgetType.liveActivity.kind: 58 | return .liveActivity 59 | default: 60 | return nil 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xCC", 9 | "green" : "0xB1", 10 | "red" : "0x00" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xFF", 27 | "green" : "0xDD", 28 | "red" : "0x00" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /App/Resources/Assets.xcassets/AppIcon.appiconset/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/App/Resources/Assets.xcassets/AppIcon.appiconset/icon.png -------------------------------------------------------------------------------- /App/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /App/Routes/DeepLink/DeepLinkWidgetView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | struct DeepLinkWidgetView: View { 26 | let widgetFamily: String 27 | 28 | var body: some View { 29 | List { 30 | Section { 31 | contentView 32 | } header: { 33 | headerView 34 | } 35 | } 36 | .navigationTitle("Deep Link") 37 | } 38 | } 39 | 40 | // MARK: - Content 41 | 42 | extension DeepLinkWidgetView { 43 | private var headerView: some View { 44 | Text("Deep Link") 45 | } 46 | 47 | private var contentView: some View { 48 | Text("Opened from widget: \(widgetFamily)") 49 | } 50 | } 51 | 52 | // MARK: - Preview 53 | 54 | #Preview { 55 | NavigationStack { 56 | DeepLinkWidgetView(widgetFamily: "systemSmall") 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /App/Screens/AudioPlayback/AudioPlaybackWidgetView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2024-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct AudioPlaybackWidgetView: View { 27 | @AppStorage(UserDefaultKey.isAudioPlaying, store: .appGroup) 28 | private var isPlaying = false 29 | 30 | var body: some View { 31 | List { 32 | Section { 33 | contentView 34 | } header: { 35 | headerView 36 | } 37 | } 38 | .onChange(of: isPlaying) { 39 | reloadWidgetTimelines() 40 | } 41 | } 42 | } 43 | 44 | // MARK: - Content 45 | 46 | extension AudioPlaybackWidgetView { 47 | private var headerView: some View { 48 | Text("Audio Playback") 49 | } 50 | 51 | @ViewBuilder 52 | private var contentView: some View { 53 | stateView 54 | buttonsView 55 | } 56 | 57 | private var stateView: some View { 58 | Text(isPlaying ? "Playing..." : "Paused") 59 | } 60 | 61 | private var buttonsView: some View { 62 | AudioPlaybackWidgetButtonsView(isPlaying: isPlaying) 63 | } 64 | } 65 | 66 | // MARK: - Helpers 67 | 68 | extension AudioPlaybackWidgetView { 69 | private func reloadWidgetTimelines() { 70 | WidgetCenter.shared.reloadTimelines(ofKind: WidgetType.audioPlayback.kind) 71 | } 72 | } 73 | 74 | // MARK: - Preview 75 | 76 | #Preview { 77 | NavigationStack { 78 | AudioPlaybackWidgetView() 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /App/Screens/DynamicIntent/DynamicIntentWidgetView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct DynamicIntentWidgetView: View { 27 | @State private var persons = Person.getAll() 28 | 29 | var body: some View { 30 | List { 31 | Section { 32 | contentView 33 | } header: { 34 | headerView 35 | } footer: { 36 | footerView 37 | } 38 | } 39 | .onChange(of: persons) { 40 | savePersons() 41 | reloadWidgetTimelines() 42 | } 43 | } 44 | } 45 | 46 | // MARK: - Content 47 | 48 | extension DynamicIntentWidgetView { 49 | private var headerView: some View { 50 | Text("Persons") 51 | } 52 | 53 | private var footerView: some View { 54 | Text("Count: \(persons.count)") 55 | } 56 | 57 | private var contentView: some View { 58 | ForEach($persons) { 59 | PersonView(person: $0) 60 | } 61 | } 62 | } 63 | 64 | // MARK: - Helpers 65 | 66 | extension DynamicIntentWidgetView { 67 | private func savePersons() { 68 | UserDefaults.appGroup.setArray(persons, forKey: UserDefaultKey.persons) 69 | } 70 | 71 | private func reloadWidgetTimelines() { 72 | WidgetCenter.shared.reloadTimelines(ofKind: WidgetType.dynamicIntent.kind) 73 | } 74 | } 75 | 76 | // MARK: - Preview 77 | 78 | #Preview { 79 | NavigationStack { 80 | DynamicIntentWidgetView() 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /App/Screens/SharedView/SharedViewWidgetView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | struct SharedViewWidgetView: View { 26 | var body: some View { 27 | List { 28 | Section { 29 | contentView 30 | } header: { 31 | headerView 32 | } 33 | } 34 | } 35 | } 36 | 37 | // MARK: - Content 38 | 39 | extension SharedViewWidgetView { 40 | private var headerView: some View { 41 | Text("Widget View") 42 | } 43 | 44 | private var contentView: some View { 45 | SharedViewWidgetEntryView(entry: .placeholder) 46 | .scaledToFit() 47 | .padding(20) 48 | .frame(width: 200, height: 200) 49 | .cornerRadius(25) 50 | .overlay { 51 | RoundedRectangle(cornerRadius: 25) 52 | .strokeBorder(.gray, lineWidth: 3) 53 | } 54 | .frame(maxWidth: .infinity) 55 | } 56 | } 57 | 58 | // MARK: - Preview 59 | 60 | #Preview { 61 | NavigationStack { 62 | SharedViewWidgetView() 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /App/Supporting Files/App.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.com.tersacore.widget-examples 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Frameworks/ClockRotationEffect.xcframework/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AvailableLibraries 6 | 7 | 8 | LibraryIdentifier 9 | ios-arm64_x86_64-simulator 10 | LibraryPath 11 | ClockRotationEffect.framework 12 | SupportedArchitectures 13 | 14 | arm64 15 | x86_64 16 | 17 | SupportedPlatform 18 | ios 19 | SupportedPlatformVariant 20 | simulator 21 | 22 | 23 | LibraryIdentifier 24 | ios-arm64 25 | LibraryPath 26 | ClockRotationEffect.framework 27 | SupportedArchitectures 28 | 29 | arm64 30 | 31 | SupportedPlatform 32 | ios 33 | 34 | 35 | CFBundlePackageType 36 | XFWK 37 | XCFrameworkFormatVersion 38 | 1.0 39 | 40 | 41 | -------------------------------------------------------------------------------- /Frameworks/ClockRotationEffect.xcframework/ios-arm64/ClockRotationEffect.framework/ClockRotationEffect: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/Frameworks/ClockRotationEffect.xcframework/ios-arm64/ClockRotationEffect.framework/ClockRotationEffect -------------------------------------------------------------------------------- /Frameworks/ClockRotationEffect.xcframework/ios-arm64/ClockRotationEffect.framework/Headers/ClockRotationEffect.h: -------------------------------------------------------------------------------- 1 | #import 2 | -------------------------------------------------------------------------------- /Frameworks/ClockRotationEffect.xcframework/ios-arm64/ClockRotationEffect.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/Frameworks/ClockRotationEffect.xcframework/ios-arm64/ClockRotationEffect.framework/Info.plist -------------------------------------------------------------------------------- /Frameworks/ClockRotationEffect.xcframework/ios-arm64/ClockRotationEffect.framework/Modules/ClockRotationEffect.swiftmodule/arm64-apple-ios.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/Frameworks/ClockRotationEffect.xcframework/ios-arm64/ClockRotationEffect.framework/Modules/ClockRotationEffect.swiftmodule/arm64-apple-ios.swiftdoc -------------------------------------------------------------------------------- /Frameworks/ClockRotationEffect.xcframework/ios-arm64/ClockRotationEffect.framework/Modules/ClockRotationEffect.swiftmodule/arm64-apple-ios.swiftinterface: -------------------------------------------------------------------------------- 1 | // swift-interface-format-version: 1.0 2 | // swift-compiler-version: Apple Swift version 5.6.1 (swiftlang-5.6.0.323.66 clang-1316.0.20.12) 3 | // swift-module-flags: -target arm64-apple-ios15.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name ClockRotationEffect 4 | @_exported import ClockRotationEffect 5 | import Foundation 6 | import Swift 7 | import SwiftUI 8 | import WidgetKit 9 | import _Concurrency 10 | public enum ClockRotationPeriod { 11 | case custom(Foundation.TimeInterval) 12 | case secondHand, hourHand, miniuteHand 13 | } 14 | public struct ClockRotationModifier : SwiftUI.ViewModifier { 15 | public init(period: ClockRotationEffect.ClockRotationPeriod, timezone: Foundation.TimeZone, anchor: SwiftUI.UnitPoint) 16 | @_Concurrency.MainActor(unsafe) public func body(content: ClockRotationEffect.ClockRotationModifier.Content) -> some SwiftUI.View 17 | 18 | public typealias Body = @_opaqueReturnTypeOf("$s19ClockRotationEffect0aB8ModifierV4body7contentQr7SwiftUI05_ViewD8_ContentVyACG_tF", 0) __ 19 | } 20 | -------------------------------------------------------------------------------- /Frameworks/ClockRotationEffect.xcframework/ios-arm64/ClockRotationEffect.framework/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module ClockRotationEffect { 2 | umbrella header "ClockRotationEffect.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | 8 | module ClockRotationEffect.Swift { 9 | header "ClockRotationEffect-Swift.h" 10 | requires objc 11 | } 12 | -------------------------------------------------------------------------------- /Frameworks/ClockRotationEffect.xcframework/ios-arm64_x86_64-simulator/ClockRotationEffect.framework/ClockRotationEffect: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/Frameworks/ClockRotationEffect.xcframework/ios-arm64_x86_64-simulator/ClockRotationEffect.framework/ClockRotationEffect -------------------------------------------------------------------------------- /Frameworks/ClockRotationEffect.xcframework/ios-arm64_x86_64-simulator/ClockRotationEffect.framework/Headers/ClockRotationEffect.h: -------------------------------------------------------------------------------- 1 | #import 2 | -------------------------------------------------------------------------------- /Frameworks/ClockRotationEffect.xcframework/ios-arm64_x86_64-simulator/ClockRotationEffect.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/Frameworks/ClockRotationEffect.xcframework/ios-arm64_x86_64-simulator/ClockRotationEffect.framework/Info.plist -------------------------------------------------------------------------------- /Frameworks/ClockRotationEffect.xcframework/ios-arm64_x86_64-simulator/ClockRotationEffect.framework/Modules/ClockRotationEffect.swiftmodule/arm64-apple-ios-simulator.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/Frameworks/ClockRotationEffect.xcframework/ios-arm64_x86_64-simulator/ClockRotationEffect.framework/Modules/ClockRotationEffect.swiftmodule/arm64-apple-ios-simulator.swiftdoc -------------------------------------------------------------------------------- /Frameworks/ClockRotationEffect.xcframework/ios-arm64_x86_64-simulator/ClockRotationEffect.framework/Modules/ClockRotationEffect.swiftmodule/arm64-apple-ios-simulator.swiftinterface: -------------------------------------------------------------------------------- 1 | // swift-interface-format-version: 1.0 2 | // swift-compiler-version: Apple Swift version 5.6.1 (swiftlang-5.6.0.323.66 clang-1316.0.20.12) 3 | // swift-module-flags: -target arm64-apple-ios15.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name ClockRotationEffect 4 | @_exported import ClockRotationEffect 5 | import Foundation 6 | import Swift 7 | import SwiftUI 8 | import WidgetKit 9 | import _Concurrency 10 | public enum ClockRotationPeriod { 11 | case custom(Foundation.TimeInterval) 12 | case secondHand, hourHand, miniuteHand 13 | } 14 | public struct ClockRotationModifier : SwiftUI.ViewModifier { 15 | public init(period: ClockRotationEffect.ClockRotationPeriod, timezone: Foundation.TimeZone, anchor: SwiftUI.UnitPoint) 16 | @_Concurrency.MainActor(unsafe) public func body(content: ClockRotationEffect.ClockRotationModifier.Content) -> some SwiftUI.View 17 | 18 | public typealias Body = @_opaqueReturnTypeOf("$s19ClockRotationEffect0aB8ModifierV4body7contentQr7SwiftUI05_ViewD8_ContentVyACG_tF", 0) __ 19 | } 20 | -------------------------------------------------------------------------------- /Frameworks/ClockRotationEffect.xcframework/ios-arm64_x86_64-simulator/ClockRotationEffect.framework/Modules/ClockRotationEffect.swiftmodule/x86_64-apple-ios-simulator.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/Frameworks/ClockRotationEffect.xcframework/ios-arm64_x86_64-simulator/ClockRotationEffect.framework/Modules/ClockRotationEffect.swiftmodule/x86_64-apple-ios-simulator.swiftdoc -------------------------------------------------------------------------------- /Frameworks/ClockRotationEffect.xcframework/ios-arm64_x86_64-simulator/ClockRotationEffect.framework/Modules/ClockRotationEffect.swiftmodule/x86_64-apple-ios-simulator.swiftinterface: -------------------------------------------------------------------------------- 1 | // swift-interface-format-version: 1.0 2 | // swift-compiler-version: Apple Swift version 5.6.1 (swiftlang-5.6.0.323.66 clang-1316.0.20.12) 3 | // swift-module-flags: -target x86_64-apple-ios15.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name ClockRotationEffect 4 | @_exported import ClockRotationEffect 5 | import Foundation 6 | import Swift 7 | import SwiftUI 8 | import WidgetKit 9 | import _Concurrency 10 | public enum ClockRotationPeriod { 11 | case custom(Foundation.TimeInterval) 12 | case secondHand, hourHand, miniuteHand 13 | } 14 | public struct ClockRotationModifier : SwiftUI.ViewModifier { 15 | public init(period: ClockRotationEffect.ClockRotationPeriod, timezone: Foundation.TimeZone, anchor: SwiftUI.UnitPoint) 16 | @_Concurrency.MainActor(unsafe) public func body(content: ClockRotationEffect.ClockRotationModifier.Content) -> some SwiftUI.View 17 | 18 | public typealias Body = @_opaqueReturnTypeOf("$s19ClockRotationEffect0aB8ModifierV4body7contentQr7SwiftUI05_ViewD8_ContentVyACG_tF", 0) __ 19 | } 20 | -------------------------------------------------------------------------------- /Frameworks/ClockRotationEffect.xcframework/ios-arm64_x86_64-simulator/ClockRotationEffect.framework/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module ClockRotationEffect { 2 | umbrella header "ClockRotationEffect.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | 8 | module ClockRotationEffect.Swift { 9 | header "ClockRotationEffect-Swift.h" 10 | requires objc 11 | } 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020-Present Paweł Wiszenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Shared/Components/DeepLink.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | 25 | enum DeepLink { 26 | static let widgetScheme = "widget" 27 | static let widgetFamilyParamName = "widgetFamily" 28 | } 29 | 30 | // MARK: - Builder 31 | 32 | extension DeepLink { 33 | class Builder { 34 | private var components = URLComponents() 35 | 36 | init(widget: WidgetType) { 37 | components.scheme = DeepLink.widgetScheme 38 | components.host = widget.kind 39 | } 40 | 41 | @discardableResult 42 | func widgetFamily(_ value: String) -> Self { 43 | createQueryItemsIfNeeded() 44 | components.queryItems?.append( 45 | .init( 46 | name: DeepLink.widgetFamilyParamName, 47 | value: value 48 | ) 49 | ) 50 | return self 51 | } 52 | 53 | func build() -> URL { 54 | components.url! 55 | } 56 | 57 | private func createQueryItemsIfNeeded() { 58 | if components.queryItems == nil { 59 | components.queryItems = [] 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Shared/Components/Loadable.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | 25 | enum Loadable { 26 | case notRequested 27 | case isLoading 28 | case loaded(value: Value) 29 | case cached(value: Value) 30 | case failed(error: String) 31 | } 32 | 33 | // MARK: - Helpers 34 | 35 | extension Loadable { 36 | var isLoading: Bool { 37 | switch self { 38 | case .isLoading: 39 | true 40 | default: 41 | false 42 | } 43 | } 44 | 45 | var value: Value? { 46 | switch self { 47 | case .loaded(let value), .cached(let value): 48 | value 49 | default: 50 | nil 51 | } 52 | } 53 | 54 | var error: String? { 55 | switch self { 56 | case .failed(let error): 57 | error 58 | default: 59 | nil 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Shared/Components/UserDefaultKey.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | 25 | enum UserDefaultKey { 26 | static var luckyNumber: String { #function } 27 | static var persons: String { #function } 28 | 29 | static var isAudioPlaying: String { #function } 30 | 31 | static func eventCounter(id: Int) -> String { 32 | "eventCounter-\(id)" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Shared/Extensions/Array+Extensions.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | 25 | extension Array: RawRepresentable where Element: Codable { 26 | public init?(rawValue: String) { 27 | guard 28 | let data = rawValue.data(using: .utf8), 29 | let result = try? JSONDecoder().decode([Element].self, from: data) 30 | else { 31 | return nil 32 | } 33 | self = result 34 | } 35 | 36 | public var rawValue: String { 37 | guard 38 | let data = try? JSONEncoder().encode(self), 39 | let result = String(data: data, encoding: .utf8) 40 | else { 41 | return "[]" 42 | } 43 | return result 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Shared/Extensions/Date+Extensions.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | 25 | extension Date { 26 | func adding( 27 | _ component: Calendar.Component, 28 | value: Int, 29 | in calendar: Calendar = .current 30 | ) -> Self { 31 | calendar.date(byAdding: component, value: value, to: self)! 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Shared/Extensions/FileManager+Extensions.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | import OSLog 25 | 26 | private let logger = Logger() 27 | 28 | extension FileManager { 29 | static func loadStringFromFile(filename: String) -> String? { 30 | let url = appGroupContainerURL.appendingPathComponent(filename) 31 | do { 32 | return try String(contentsOf: url, encoding: .utf8) 33 | } catch { 34 | Logger.fileManager.error("Error reading from file: \(error)") 35 | } 36 | return nil 37 | } 38 | 39 | static func saveStringToFile(_ value: String, filename: String) { 40 | let url = appGroupContainerURL.appendingPathComponent(filename) 41 | do { 42 | try value.write(to: url, atomically: false, encoding: .utf8) 43 | } catch { 44 | Logger.fileManager.error("Error writing to file: \(error)") 45 | } 46 | } 47 | } 48 | 49 | // MARK: - App Group 50 | 51 | extension FileManager { 52 | static let appGroupContainerURL = FileManager.default.containerURL( 53 | forSecurityApplicationGroupIdentifier: Shared.appGroupName 54 | )! 55 | } 56 | -------------------------------------------------------------------------------- /Shared/Extensions/URL+Extensions.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | 25 | extension URL { 26 | func queryParameter(name: String) -> String? { 27 | guard let url = URLComponents(string: absoluteString) else { 28 | return nil 29 | } 30 | return url.queryItems? 31 | .first(where: { $0.name == name })? 32 | .value 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Shared/Extensions/UserDefaults+Extensions.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | 25 | extension UserDefaults { 26 | func setArray(_ array: [Element], forKey key: String) where Element: Encodable { 27 | let data = try? JSONEncoder().encode(array) 28 | set(data, forKey: key) 29 | } 30 | 31 | func getArray(forKey key: String) -> [Element]? where Element: Decodable { 32 | guard let data = data(forKey: key) else { 33 | return nil 34 | } 35 | return try? JSONDecoder().decode([Element].self, from: data) 36 | } 37 | } 38 | 39 | // MARK: - App Group 40 | 41 | extension UserDefaults { 42 | static let appGroup = UserDefaults(suiteName: Shared.appGroupName)! 43 | } 44 | -------------------------------------------------------------------------------- /Shared/Logger.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import OSLog 24 | 25 | extension Logger { 26 | private static var subsystem = Bundle.main.bundleIdentifier! 27 | 28 | static let app = Logger(subsystem: subsystem, category: "App") 29 | static let widgets = Logger(subsystem: subsystem, category: "Widgets") 30 | 31 | static let audioPlayer = Logger(subsystem: subsystem, category: "AudioPlayer") 32 | static let coreData = Logger(subsystem: subsystem, category: "CoreData") 33 | static let fileManager = Logger(subsystem: subsystem, category: "FileManager") 34 | } 35 | -------------------------------------------------------------------------------- /Shared/Models/AudioPlayback/Sound.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2024-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | 25 | enum Sound: String { 26 | /// https://pixabay.com/music/beats-sad-soul-chasing-a-feeling-185750 27 | case main 28 | } 29 | 30 | extension Sound { 31 | var url: URL { 32 | Bundle.main.url(forResource: rawValue, withExtension: "mp3")! 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Shared/Models/CoreData/DataModel.xcdatamodeld/DataModel.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Shared/Models/CoreData/Document.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import CoreData 24 | import Foundation 25 | 26 | @objc(Document) 27 | class Document: NSManagedObject, Identifiable { 28 | @nonobjc class func fetchRequest() -> NSFetchRequest { 29 | NSFetchRequest(entityName: "Document") 30 | } 31 | 32 | @NSManaged var name: String 33 | @NSManaged var creationDate: Date 34 | 35 | @available(*, unavailable) 36 | init() { 37 | fatalError("\(#function) not implemented") 38 | } 39 | 40 | @available(*, unavailable) 41 | convenience init(context: NSManagedObjectContext) { 42 | fatalError("\(#function) not implemented") 43 | } 44 | 45 | init( 46 | context: NSManagedObjectContext, 47 | name: String = "Document #\(Int.random(in: 1 ... 99))", 48 | creationDate: Date = .now 49 | ) { 50 | let entity = NSEntityDescription.entity(forEntityName: "Document", in: context)! 51 | super.init(entity: entity, insertInto: context) 52 | self.name = name 53 | self.creationDate = creationDate 54 | } 55 | 56 | @objc override private init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { 57 | super.init(entity: entity, insertInto: context) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Shared/Models/DynamicIntent/Person.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | 25 | struct Person: Codable, Hashable, Identifiable { 26 | var id = UUID().uuidString 27 | var name: String 28 | var dateOfBirth: Date 29 | } 30 | 31 | // MARK: - Helpers 32 | 33 | extension Person { 34 | static func getAll() -> [Self] { 35 | let key = UserDefaultKey.persons 36 | guard let persons: [Self] = UserDefaults.appGroup.getArray(forKey: key) else { 37 | let persons: [Self] = .defaultFriends 38 | UserDefaults.appGroup.setArray(persons, forKey: key) 39 | return persons 40 | } 41 | return persons 42 | } 43 | } 44 | 45 | // MARK: - Convenience 46 | 47 | extension Person { 48 | init?(identifier: String) { 49 | if let person = Self.getAll().first(where: { $0.id == identifier }) { 50 | self = person 51 | } else { 52 | return nil 53 | } 54 | } 55 | } 56 | 57 | // MARK: - Data 58 | 59 | extension [Person] { 60 | static let defaultFriends: Self = [ 61 | .friend1, .friend2 62 | ] 63 | } 64 | 65 | extension Person { 66 | static let friend1: Self = .init( 67 | name: "Friend 1", 68 | dateOfBirth: .now.adding(.month, value: -2) 69 | ) 70 | 71 | static let friend2: Self = .init( 72 | name: "Friend 2", 73 | dateOfBirth: .now.adding(.year, value: -3) 74 | ) 75 | } 76 | -------------------------------------------------------------------------------- /Shared/Models/LiveActivity/Delivery.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | 25 | struct Delivery: Codable, Equatable { 26 | var id = UUID().uuidString.prefix(4).uppercased() 27 | var itemsCount: Int 28 | var date: Date = .now 29 | } 30 | 31 | // MARK: - Data 32 | 33 | extension Delivery { 34 | static func sent(minutesAgo: Int = 0) -> Self { 35 | .init( 36 | itemsCount: 3, 37 | date: .now.adding(.minute, value: -minutesAgo) 38 | ) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Shared/Models/LiveActivity/DeliveryAttributes.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import ActivityKit 24 | import Foundation 25 | 26 | struct DeliveryAttributes: ActivityAttributes { 27 | struct ContentState: Codable, Hashable { 28 | let expectedArrivalDate: Date 29 | let deliveryState: DeliveryState 30 | } 31 | 32 | let delivery: Delivery 33 | } 34 | 35 | // MARK: - Data 36 | 37 | extension DeliveryAttributes { 38 | static let previewStates: [DeliveryAttributes.ContentState] = [ 39 | .sent, .delayed, .arrived 40 | ] 41 | } 42 | 43 | extension DeliveryAttributes.ContentState { 44 | static let sent: Self = .init( 45 | expectedArrivalDate: .now.adding(.minute, value: 3), 46 | deliveryState: .sent 47 | ) 48 | 49 | static let delayed: Self = .init( 50 | expectedArrivalDate: .now.adding(.minute, value: 12), 51 | deliveryState: .delayed 52 | ) 53 | 54 | static let arrived: Self = .init( 55 | expectedArrivalDate: .now, 56 | deliveryState: .arrived 57 | ) 58 | } 59 | -------------------------------------------------------------------------------- /Shared/Models/LiveActivity/DeliveryState.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | 25 | enum DeliveryState: Codable { 26 | case sent 27 | case delayed 28 | case arrived 29 | } 30 | 31 | // MARK: - Helpers 32 | 33 | extension DeliveryState { 34 | var name: LocalizedStringResource { 35 | switch self { 36 | case .sent: 37 | "In transit" 38 | case .delayed: 39 | "Delayed" 40 | case .arrived: 41 | "Arrived" 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Shared/Models/SwiftData/Product.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | import SwiftData 25 | 26 | @Model 27 | final class Product { 28 | @Attribute(.unique) var id: String 29 | var name: String 30 | var creationDate: Date 31 | 32 | init( 33 | id: String = UUID().uuidString, 34 | name: String = "Product #\(Int.random(in: 1 ... 99))", 35 | creationDate: Date = .now 36 | ) { 37 | self.id = id 38 | self.name = name 39 | self.creationDate = creationDate 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Shared/Shared.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | 25 | enum Shared { 26 | static let appGroupName = "group.com.tersacore.widget-examples" 27 | static let luckyNumberFilename = "LuckyNumber.txt" 28 | } 29 | -------------------------------------------------------------------------------- /Shared/WidgetType.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Foundation 24 | 25 | enum WidgetType: String { 26 | case analogClock 27 | case appGroup 28 | case audioPlayback 29 | case coreData 30 | case countdown 31 | case deepLink 32 | case digitalClock 33 | case dynamicIntent 34 | case environment 35 | case intent 36 | case interactive 37 | case liveActivity 38 | case lockScreen 39 | case network 40 | case sharedView 41 | case swiftData 42 | case timer 43 | case urlImage 44 | case urlCachedImage 45 | } 46 | 47 | // MARK: - Helpers 48 | 49 | extension WidgetType { 50 | var kind: String { 51 | rawValue + "Widget" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Widgets/AnalogClockWidget/AnalogClockWidget+Entry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension AnalogClockWidget { 26 | struct Entry: TimelineEntry { 27 | var date: Date = .now 28 | } 29 | } 30 | 31 | // MARK: - Data 32 | 33 | extension AnalogClockWidget.Entry { 34 | static var placeholder: Self { 35 | .init() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Widgets/AnalogClockWidget/AnalogClockWidget+Provider.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension AnalogClockWidget { 26 | struct Provider: TimelineProvider { 27 | func placeholder(in context: Context) -> Entry { 28 | .placeholder 29 | } 30 | 31 | func getSnapshot(in context: Context, completion: @escaping (Entry) -> Void) { 32 | completion(.placeholder) 33 | } 34 | 35 | func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { 36 | completion(.init(entries: [.placeholder], policy: .never)) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Widgets/AnalogClockWidget/AnalogClockWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct AnalogClockWidget: Widget { 27 | private let kind = WidgetType.analogClock.kind 28 | 29 | var body: some WidgetConfiguration { 30 | StaticConfiguration(kind: kind, provider: Provider()) { 31 | EntryView(entry: $0) 32 | } 33 | .configurationDisplayName("Analog Clock Widget") 34 | .description("Display an analog clock that animates the rotation of its hands.") 35 | .supportedFamilies([.systemSmall]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .systemSmall) { 42 | AnalogClockWidget() 43 | } timeline: { 44 | AnalogClockWidget.Entry.placeholder 45 | } 46 | -------------------------------------------------------------------------------- /Widgets/AnalogClockWidget/README.md: -------------------------------------------------------------------------------- 1 | # Analog Clock Widget 2 | 3 | Display an analog clock that animates the rotation of its hands. 4 | 5 | ## Preview 6 | 7 | ![Analog Clock Widget](../../.resources/Recordings/AnalogClockWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/AppGroupWidget/AppGroupWidget+Entry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension AppGroupWidget { 26 | struct Entry: TimelineEntry { 27 | var date: Date = .now 28 | let numberFromUserDefaults: Int 29 | let numberFromFile: Int 30 | } 31 | } 32 | 33 | // MARK: - Data 34 | 35 | extension AppGroupWidget.Entry { 36 | static var placeholder: Self { 37 | .init(numberFromUserDefaults: 7, numberFromFile: 7) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Widgets/AppGroupWidget/AppGroupWidget+EntryView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | extension AppGroupWidget { 26 | struct EntryView: View { 27 | let entry: Entry 28 | 29 | var body: some View { 30 | VStack(alignment: .leading) { 31 | WidgetHeaderView(title: "App Group") 32 | Spacer() 33 | contentView 34 | Spacer() 35 | } 36 | .containerBackground(.clear, for: .widget) 37 | } 38 | } 39 | } 40 | 41 | // MARK: - Content 42 | 43 | extension AppGroupWidget.EntryView { 44 | @ViewBuilder 45 | private var contentView: some View { 46 | Text("Lucky number") 47 | .font(.subheadline) 48 | .bold() 49 | Group { 50 | Text("UserDefaults: \(entry.numberFromUserDefaults)") 51 | Text("TXT File: \(entry.numberFromFile)") 52 | } 53 | .font(.footnote) 54 | .foregroundStyle(.secondary) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Widgets/AppGroupWidget/AppGroupWidget+Provider.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension AppGroupWidget { 26 | struct Provider: TimelineProvider { 27 | func placeholder(in context: Context) -> Entry { 28 | .placeholder 29 | } 30 | 31 | func getSnapshot(in context: Context, completion: @escaping (Entry) -> Void) { 32 | completion(.placeholder) 33 | } 34 | 35 | func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { 36 | let entry = Entry( 37 | numberFromUserDefaults: luckyNumberFromUserDefaults, 38 | numberFromFile: luckyNumberFromFile 39 | ) 40 | completion(.init(entries: [entry], policy: .never)) 41 | } 42 | } 43 | } 44 | 45 | // MARK: - Helpers 46 | 47 | extension AppGroupWidget.Provider { 48 | private var luckyNumberFromUserDefaults: Int { 49 | UserDefaults.appGroup.integer(forKey: UserDefaultKey.luckyNumber) 50 | } 51 | 52 | private var luckyNumberFromFile: Int { 53 | let value = FileManager.loadStringFromFile( 54 | filename: Shared.luckyNumberFilename 55 | ) 56 | guard let value else { 57 | return 0 58 | } 59 | return Int(value) ?? 0 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Widgets/AppGroupWidget/AppGroupWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct AppGroupWidget: Widget { 27 | private let kind = WidgetType.appGroup.kind 28 | 29 | var body: some WidgetConfiguration { 30 | StaticConfiguration(kind: kind, provider: Provider()) { 31 | EntryView(entry: $0) 32 | } 33 | .configurationDisplayName("App Group Widget") 34 | .description("Use an App Group to share data between the App and the Widget.") 35 | .supportedFamilies([.systemSmall]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .systemSmall) { 42 | AppGroupWidget() 43 | } timeline: { 44 | AppGroupWidget.Entry.placeholder 45 | } 46 | -------------------------------------------------------------------------------- /Widgets/AppGroupWidget/README.md: -------------------------------------------------------------------------------- 1 | # App Group Widget 2 | 3 | Use an App Group to share data between the App and the Widget. 4 | 5 | ## Preview 6 | 7 | ![App Group Widget](../../.resources/Recordings/AppGroupWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/AudioPlaybackWidget/AudioPlaybackWidget+Entry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2024-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension AudioPlaybackWidget { 26 | struct Entry: TimelineEntry { 27 | var date: Date = .now 28 | var isPlaying: Bool 29 | } 30 | } 31 | 32 | // MARK: - Data 33 | 34 | extension AudioPlaybackWidget.Entry { 35 | static var placeholder: Self { 36 | .init(isPlaying: false) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Widgets/AudioPlaybackWidget/AudioPlaybackWidget+EntryView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2024-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | extension AudioPlaybackWidget { 26 | struct EntryView: View { 27 | let entry: Entry 28 | 29 | var body: some View { 30 | VStack(alignment: .leading) { 31 | WidgetHeaderView(title: "Audio Playback") 32 | Spacer() 33 | AudioPlaybackWidgetButtonsView(isPlaying: entry.isPlaying) 34 | } 35 | .containerBackground(.clear, for: .widget) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Widgets/AudioPlaybackWidget/AudioPlaybackWidget+Provider.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2024-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension AudioPlaybackWidget { 26 | struct Provider: TimelineProvider { 27 | func placeholder(in context: Context) -> Entry { 28 | .placeholder 29 | } 30 | 31 | func getSnapshot(in context: Context, completion: @escaping (Entry) -> Void) { 32 | completion(.placeholder) 33 | } 34 | 35 | func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { 36 | let isPlaying = UserDefaults.appGroup.bool(forKey: UserDefaultKey.isAudioPlaying) 37 | let entry = Entry(isPlaying: isPlaying) 38 | completion(.init(entries: [entry], policy: .never)) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Widgets/AudioPlaybackWidget/AudioPlaybackWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2024-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct AudioPlaybackWidget: Widget { 27 | private let kind: String = WidgetType.audioPlayback.kind 28 | 29 | var body: some WidgetConfiguration { 30 | StaticConfiguration(kind: kind, provider: Provider()) { 31 | EntryView(entry: $0) 32 | } 33 | .configurationDisplayName("Audio Playback Widget") 34 | .description("Play music in the background directly from the Widget.") 35 | .supportedFamilies([.systemSmall]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .systemSmall) { 42 | AudioPlaybackWidget() 43 | } timeline: { 44 | AudioPlaybackWidget.Entry(isPlaying: false) 45 | AudioPlaybackWidget.Entry(isPlaying: true) 46 | } 47 | -------------------------------------------------------------------------------- /Widgets/AudioPlaybackWidget/README.md: -------------------------------------------------------------------------------- 1 | # Audio Playback Widget 2 | 3 | Play music in the background directly from the Widget. 4 | 5 | ## Preview 6 | 7 | ![Audio Playback Widget](../../.resources/Recordings/AudioPlaybackWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/AudioPlaybackWidget/Shared/AudioPlaybackWidget+Intents.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2024-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import AppIntents 24 | import AVFoundation 25 | import WidgetKit 26 | 27 | // MARK: - PlayIntent 28 | 29 | struct AudioPlaybackWidgetPlayIntent: AudioPlaybackIntent { 30 | static var title: LocalizedStringResource = "Play Music" 31 | 32 | private let sound: Sound 33 | 34 | init(sound: Sound) { 35 | self.sound = sound 36 | } 37 | 38 | init() { 39 | self.init(sound: .main) 40 | } 41 | 42 | func perform() async throws -> some IntentResult { 43 | AudioPlayer.shared.play(sound: sound) 44 | UserDefaults.appGroup.set( 45 | AudioPlayer.shared.isPlaying, 46 | forKey: UserDefaultKey.isAudioPlaying 47 | ) 48 | return .result() 49 | } 50 | } 51 | 52 | // MARK: - PauseIntent 53 | 54 | struct AudioPlaybackWidgetPauseIntent: AudioPlaybackIntent { 55 | static var title: LocalizedStringResource = "Pause Music" 56 | 57 | func perform() async throws -> some IntentResult { 58 | AudioPlayer.shared.pause() 59 | UserDefaults.appGroup.set( 60 | AudioPlayer.shared.isPlaying, 61 | forKey: UserDefaultKey.isAudioPlaying 62 | ) 63 | return .result() 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Widgets/AudioPlaybackWidget/Shared/AudioPlaybackWidgetButtonsView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2024-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | struct AudioPlaybackWidgetButtonsView: View { 26 | let isPlaying: Bool 27 | 28 | var body: some View { 29 | if isPlaying { 30 | pauseButton 31 | } else { 32 | playButton 33 | } 34 | } 35 | } 36 | 37 | // MARK: - Content 38 | 39 | extension AudioPlaybackWidgetButtonsView { 40 | private var playButton: some View { 41 | Button(intent: AudioPlaybackWidgetPlayIntent(sound: .main)) { 42 | Image(systemName: "play") 43 | .padding(2) 44 | } 45 | .buttonStyle(.bordered) 46 | } 47 | 48 | private var pauseButton: some View { 49 | Button(intent: AudioPlaybackWidgetPauseIntent()) { 50 | Image(systemName: "pause") 51 | .padding(2) 52 | } 53 | .buttonStyle(.bordered) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Widgets/Components/WidgetHeaderView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | struct WidgetHeaderView: View { 26 | var title: LocalizedStringResource 27 | 28 | var body: some View { 29 | HStack { 30 | Text(title) 31 | .font(.headline) 32 | .fixedSize() 33 | Spacer(minLength: 0) 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Widgets/CoreDataWidget/CoreDataWidget+Entry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension CoreDataWidget { 26 | struct Entry: TimelineEntry { 27 | var date: Date = .now 28 | var documentInfo: DocumentInfo? 29 | } 30 | } 31 | 32 | // MARK: - DocumentInfo 33 | 34 | extension CoreDataWidget.Entry { 35 | struct DocumentInfo { 36 | let count: Int 37 | let lastItem: Document? 38 | } 39 | } 40 | 41 | extension CoreDataWidget.Entry.DocumentInfo { 42 | struct Document { 43 | var name: String 44 | var creationDate: Date 45 | } 46 | } 47 | 48 | // MARK: - Data 49 | 50 | extension CoreDataWidget.Entry { 51 | static var empty: Self { 52 | .init() 53 | } 54 | 55 | static var placeholder: Self { 56 | .init(documentInfo: .placeholder) 57 | } 58 | } 59 | 60 | extension CoreDataWidget.Entry.DocumentInfo { 61 | static var placeholder: Self { 62 | .init(count: 3, lastItem: .placeholder) 63 | } 64 | } 65 | 66 | extension CoreDataWidget.Entry.DocumentInfo.Document { 67 | static var placeholder: Self { 68 | .init(name: "Document #3", creationDate: .now) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Widgets/CoreDataWidget/CoreDataWidget+EntryView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | extension CoreDataWidget { 26 | struct EntryView: View { 27 | let entry: Entry 28 | 29 | var body: some View { 30 | VStack(alignment: .leading) { 31 | WidgetHeaderView(title: "Core Data") 32 | Spacer() 33 | contentView 34 | Spacer() 35 | } 36 | .containerBackground(.clear, for: .widget) 37 | } 38 | } 39 | } 40 | 41 | // MARK: - Content 42 | 43 | extension CoreDataWidget.EntryView { 44 | @ViewBuilder 45 | private var contentView: some View { 46 | if let documentInfo = entry.documentInfo { 47 | Text("Count: \(documentInfo.count)") 48 | .font(.subheadline) 49 | .bold() 50 | if let lastItem = documentInfo.lastItem { 51 | Group { 52 | Text("Last item:") 53 | Text(lastItem.name) 54 | } 55 | .font(.footnote) 56 | } 57 | } else { 58 | Text("Info unavailable") 59 | .font(.subheadline) 60 | .foregroundStyle(.secondary) 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Widgets/CoreDataWidget/CoreDataWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct CoreDataWidget: Widget { 27 | private let kind = WidgetType.coreData.kind 28 | 29 | var body: some WidgetConfiguration { 30 | StaticConfiguration(kind: kind, provider: Provider()) { 31 | EntryView(entry: $0) 32 | } 33 | .configurationDisplayName("CoreData Widget") 34 | .description("Use Core Data to share data between the App and the Widget.") 35 | .supportedFamilies([.systemSmall]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .systemSmall) { 42 | CoreDataWidget() 43 | } timeline: { 44 | CoreDataWidget.Entry.empty 45 | CoreDataWidget.Entry.placeholder 46 | } 47 | -------------------------------------------------------------------------------- /Widgets/CoreDataWidget/README.md: -------------------------------------------------------------------------------- 1 | # Core Data Widget 2 | 3 | Use Core Data to share data between the App and the Widget. 4 | 5 | ## Preview 6 | 7 | ![Core Data Widget](../../.resources/Recordings/CoreDataWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/CountdownWidget/CountdownWidget+Entry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension CountdownWidget { 26 | struct Entry: TimelineEntry { 27 | var date: Date = .now 28 | var displayDate: Date 29 | var countdownState: CountdownState 30 | } 31 | } 32 | 33 | // MARK: - CountdownState 34 | 35 | extension CountdownWidget.Entry { 36 | enum CountdownState: Codable { 37 | case counting 38 | case nearEnd 39 | case end 40 | } 41 | } 42 | 43 | // MARK: - Data 44 | 45 | extension CountdownWidget.Entry { 46 | static var placeholder: Self { 47 | .counting 48 | } 49 | 50 | static var counting: Self { 51 | .init( 52 | displayDate: .now.adding(.minute, value: 1), 53 | countdownState: .counting 54 | ) 55 | } 56 | 57 | static var nearEnd: Self { 58 | .init( 59 | displayDate: .now.adding(.second, value: 10), 60 | countdownState: .nearEnd 61 | ) 62 | } 63 | 64 | static var end: Self { 65 | .init( 66 | displayDate: .now, 67 | countdownState: .end 68 | ) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Widgets/CountdownWidget/CountdownWidget+EntryView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | extension CountdownWidget { 26 | struct EntryView: View { 27 | let entry: Entry 28 | 29 | var body: some View { 30 | VStack(alignment: .leading) { 31 | WidgetHeaderView(title: "Countdown") 32 | Spacer() 33 | contentView 34 | Spacer() 35 | } 36 | .containerBackground(.clear, for: .widget) 37 | } 38 | } 39 | } 40 | 41 | // MARK: - Content 42 | 43 | extension CountdownWidget.EntryView { 44 | @ViewBuilder 45 | private var contentView: some View { 46 | HStack { 47 | Text("Timer:") 48 | timerView 49 | .foregroundStyle(textColor) 50 | .id(entry.countdownState) 51 | Spacer() 52 | } 53 | } 54 | 55 | @ViewBuilder 56 | private var timerView: some View { 57 | switch entry.countdownState { 58 | case .counting, .nearEnd: 59 | Text(entry.displayDate, style: .timer) 60 | case .end: 61 | Text("End") 62 | } 63 | } 64 | } 65 | 66 | // MARK: - Helpers 67 | 68 | extension CountdownWidget.EntryView { 69 | private var textColor: Color { 70 | switch entry.countdownState { 71 | case .counting: 72 | .primary 73 | case .nearEnd: 74 | .red 75 | case .end: 76 | .secondary 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Widgets/CountdownWidget/CountdownWidget+Provider.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension CountdownWidget { 26 | struct Provider: TimelineProvider { 27 | func placeholder(in context: Context) -> Entry { 28 | .placeholder 29 | } 30 | 31 | func getSnapshot(in context: Context, completion: @escaping (Entry) -> Void) { 32 | completion(.placeholder) 33 | } 34 | 35 | func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { 36 | let currentDate = Date() 37 | let nearEndDate = currentDate.adding(.second, value: 20) 38 | let endDate = currentDate.adding(.second, value: 30) 39 | 40 | let entries = [ 41 | Entry(date: currentDate, displayDate: endDate, countdownState: .counting), 42 | Entry(date: nearEndDate, displayDate: endDate, countdownState: .nearEnd), 43 | Entry(date: endDate, displayDate: endDate, countdownState: .end) 44 | ] 45 | 46 | let timeline = Timeline(entries: entries, policy: .never) 47 | completion(timeline) 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Widgets/CountdownWidget/CountdownWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct CountdownWidget: Widget { 27 | private let kind = WidgetType.countdown.kind 28 | 29 | var body: some WidgetConfiguration { 30 | StaticConfiguration(kind: kind, provider: Provider()) { 31 | EntryView(entry: $0) 32 | } 33 | .configurationDisplayName("Countdown Widget") 34 | .description("Display the remaining time in seconds and change color when the end date is approaching.") 35 | .supportedFamilies([.systemSmall]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .systemSmall) { 42 | CountdownWidget() 43 | } timeline: { 44 | CountdownWidget.Entry.counting 45 | CountdownWidget.Entry.nearEnd 46 | CountdownWidget.Entry.end 47 | } 48 | -------------------------------------------------------------------------------- /Widgets/CountdownWidget/README.md: -------------------------------------------------------------------------------- 1 | # Countdown Widget 2 | 3 | Display the remaining time in seconds and change color when the end date is approaching. 4 | 5 | ## Preview 6 | 7 | ![Countdown Widget](../../.resources/Recordings/CountdownWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/DeepLinkWidget/DeepLinkWidget+Entry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension DeepLinkWidget { 26 | struct Entry: TimelineEntry { 27 | var date: Date = .now 28 | } 29 | } 30 | 31 | // MARK: - Data 32 | 33 | extension DeepLinkWidget.Entry { 34 | static var placeholder: Self { 35 | .init() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Widgets/DeepLinkWidget/DeepLinkWidget+EntryView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | extension DeepLinkWidget { 26 | struct EntryView: View { 27 | @Environment(\.widgetFamily) var widgetFamily 28 | 29 | let entry: Entry 30 | 31 | var body: some View { 32 | VStack(alignment: .leading) { 33 | WidgetHeaderView(title: "Deep Link") 34 | Spacer() 35 | contentView 36 | Spacer() 37 | } 38 | .containerBackground(.clear, for: .widget) 39 | } 40 | } 41 | } 42 | 43 | // MARK: - Content 44 | 45 | extension DeepLinkWidget.EntryView { 46 | @ViewBuilder 47 | private var contentView: some View { 48 | if widgetFamily == .systemSmall { 49 | Text("Tap anywhere") 50 | .widgetURL(deeplinkURL) 51 | } else { 52 | Link("Tap here", destination: deeplinkURL) 53 | } 54 | } 55 | } 56 | 57 | // MARK: - Helpers 58 | 59 | extension DeepLinkWidget.EntryView { 60 | private var deeplinkURL: URL { 61 | DeepLink.Builder(widget: .deepLink) 62 | .widgetFamily("\(widgetFamily)") 63 | .build() 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Widgets/DeepLinkWidget/DeepLinkWidget+Provider.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension DeepLinkWidget { 26 | struct Provider: TimelineProvider { 27 | func placeholder(in context: Context) -> Entry { 28 | .placeholder 29 | } 30 | 31 | func getSnapshot(in context: Context, completion: @escaping (Entry) -> Void) { 32 | completion(.placeholder) 33 | } 34 | 35 | func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { 36 | completion(.init(entries: [.placeholder], policy: .never)) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Widgets/DeepLinkWidget/DeepLinkWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct DeepLinkWidget: Widget { 27 | private let kind = WidgetType.deepLink.kind 28 | 29 | var body: some WidgetConfiguration { 30 | StaticConfiguration(kind: kind, provider: Provider()) { 31 | EntryView(entry: $0) 32 | } 33 | .configurationDisplayName("Deep Link Widget") 34 | .description("Use Deep Links to pass information from the Widget when opening the parent App.") 35 | .supportedFamilies([.systemSmall, .systemMedium]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .systemSmall) { 42 | DeepLinkWidget() 43 | } timeline: { 44 | DeepLinkWidget.Entry.placeholder 45 | } 46 | -------------------------------------------------------------------------------- /Widgets/DeepLinkWidget/README.md: -------------------------------------------------------------------------------- 1 | # Deep Link Widget 2 | 3 | Use Deep Links to pass information from the Widget when opening the parent App. 4 | 5 | ## Preview 6 | 7 | ![Deep Link Widget](../../.resources/Recordings/DeepLinkWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/DigitalClockWidget/DigitalClockWidget+Entry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension DigitalClockWidget { 26 | struct Entry: TimelineEntry { 27 | var date: Date = .now 28 | } 29 | } 30 | 31 | // MARK: - Data 32 | 33 | extension DigitalClockWidget.Entry { 34 | static var placeholder: Self { 35 | .init() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Widgets/DigitalClockWidget/DigitalClockWidget+EntryView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | extension DigitalClockWidget { 26 | struct EntryView: View { 27 | let entry: Entry 28 | 29 | var body: some View { 30 | VStack(alignment: .leading) { 31 | WidgetHeaderView(title: "Digital Clock") 32 | Spacer() 33 | contentView 34 | Spacer() 35 | } 36 | .containerBackground(.clear, for: .widget) 37 | } 38 | } 39 | } 40 | 41 | // MARK: - Content 42 | 43 | extension DigitalClockWidget.EntryView { 44 | @ViewBuilder 45 | private var contentView: some View { 46 | Text("\(entry.date.adding(.second, value: 1), formatter: Self.dateFormatter)") 47 | Text(entry.date.adding(.second, value: 1), style: .time) 48 | Text(Calendar.current.startOfDay(for: .now), style: .timer) 49 | } 50 | } 51 | 52 | // MARK: - Helpers 53 | 54 | extension DigitalClockWidget.EntryView { 55 | private static let dateFormatter: DateFormatter = { 56 | let formatter = DateFormatter() 57 | formatter.locale = .init(identifier: "en_US_POSIX") 58 | formatter.dateFormat = "HH:mm" 59 | return formatter 60 | }() 61 | } 62 | -------------------------------------------------------------------------------- /Widgets/DigitalClockWidget/DigitalClockWidget+Provider.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension DigitalClockWidget { 26 | struct Provider: TimelineProvider { 27 | func placeholder(in context: Context) -> Entry { 28 | .placeholder 29 | } 30 | 31 | func getSnapshot(in context: Context, completion: @escaping (Entry) -> Void) { 32 | completion(.placeholder) 33 | } 34 | 35 | func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { 36 | let currentDate = Date() 37 | let seconds = Calendar.current.component(.second, from: currentDate) 38 | let startDate = currentDate.adding(.second, value: -seconds) 39 | let entries = (0 ..< 60).map { 40 | let date = startDate.adding(.second, value: $0 * 60 - 1) 41 | return Entry(date: date) 42 | } 43 | completion(.init(entries: entries, policy: .atEnd)) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Widgets/DigitalClockWidget/DigitalClockWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct DigitalClockWidget: Widget { 27 | private let kind = WidgetType.digitalClock.kind 28 | 29 | var body: some WidgetConfiguration { 30 | StaticConfiguration(kind: kind, provider: Provider()) { 31 | EntryView(entry: $0) 32 | } 33 | .configurationDisplayName("Digital Clock Widget") 34 | .description("Display a digital clock that shows time in various formats.") 35 | .supportedFamilies([.systemSmall]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .systemSmall) { 42 | DigitalClockWidget() 43 | } timeline: { 44 | DigitalClockWidget.Entry.placeholder 45 | } 46 | -------------------------------------------------------------------------------- /Widgets/DigitalClockWidget/README.md: -------------------------------------------------------------------------------- 1 | # Digital Clock Widget 2 | 3 | Display a digital clock that shows time in various formats. 4 | 5 | ## Preview 6 | 7 | ![Digital Clock Widget](../../.resources/Recordings/DigitalClockWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/DynamicIntentWidget/DynamicIntentWidget+Entry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension DynamicIntentWidget { 26 | struct Entry: TimelineEntry { 27 | var date: Date = .now 28 | var person: Person? 29 | } 30 | } 31 | 32 | // MARK: - Data 33 | 34 | extension DynamicIntentWidget.Entry { 35 | static var empty: Self { 36 | .init() 37 | } 38 | 39 | static var placeholder: Self { 40 | .init(person: .friend1) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Widgets/DynamicIntentWidget/DynamicIntentWidget+EntryView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | extension DynamicIntentWidget { 26 | struct EntryView: View { 27 | let entry: Entry 28 | 29 | var body: some View { 30 | VStack(alignment: .leading) { 31 | WidgetHeaderView(title: "Dynamic Intent") 32 | Spacer() 33 | contentView 34 | Spacer() 35 | } 36 | .containerBackground(.clear, for: .widget) 37 | } 38 | } 39 | } 40 | 41 | // MARK: - Content 42 | 43 | extension DynamicIntentWidget.EntryView { 44 | @ViewBuilder 45 | private var contentView: some View { 46 | if let person = entry.person { 47 | personView(for: person) 48 | } else { 49 | Text("Edit Widget to choose a person") 50 | .font(.subheadline) 51 | .foregroundStyle(.secondary) 52 | } 53 | } 54 | 55 | @ViewBuilder 56 | private func personView(for person: Person) -> some View { 57 | Text(person.name) 58 | .font(.subheadline) 59 | .bold() 60 | Group { 61 | Text("Date of birth:") 62 | Text(person.dateOfBirth, style: .date) 63 | } 64 | .font(.footnote) 65 | .foregroundStyle(.secondary) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Widgets/DynamicIntentWidget/DynamicIntentWidget+Provider.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension DynamicIntentWidget { 26 | struct Provider: AppIntentTimelineProvider { 27 | func placeholder(in context: Context) -> Entry { 28 | .placeholder 29 | } 30 | 31 | func snapshot( 32 | for configuration: DynamicIntentWidgetPersonIntent, 33 | in context: Context 34 | ) async -> Entry { 35 | .placeholder 36 | } 37 | 38 | func timeline( 39 | for configuration: DynamicIntentWidgetPersonIntent, 40 | in context: Context 41 | ) async -> Timeline { 42 | let entry = Entry(person: person(for: configuration)) 43 | return .init(entries: [entry], policy: .never) 44 | } 45 | 46 | func recommendations() -> [AppIntentRecommendation] { 47 | Person.getAll().map { 48 | .init( 49 | intent: .init(person: .init(id: $0.id, name: $0.name)), 50 | description: $0.name 51 | ) 52 | } 53 | } 54 | } 55 | } 56 | 57 | // MARK: - Helpers 58 | 59 | extension DynamicIntentWidget.Provider { 60 | private func person(for configuration: DynamicIntentWidgetPersonIntent) -> Person? { 61 | if let person = configuration.person { 62 | .init(identifier: person.id) 63 | } else { 64 | nil 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Widgets/DynamicIntentWidget/DynamicIntentWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct DynamicIntentWidget: Widget { 27 | private let kind: String = WidgetType.dynamicIntent.kind 28 | 29 | var body: some WidgetConfiguration { 30 | AppIntentConfiguration(kind: kind, intent: DynamicIntentWidgetPersonIntent.self, provider: Provider()) { 31 | EntryView(entry: $0) 32 | } 33 | .configurationDisplayName("Dynamic Intent Widget") 34 | .description("Configure the Widget with data that can be changed dynamically.") 35 | .supportedFamilies([.systemSmall]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .systemSmall) { 42 | DynamicIntentWidget() 43 | } timeline: { 44 | DynamicIntentWidget.Entry.empty 45 | DynamicIntentWidget.Entry.placeholder 46 | } 47 | -------------------------------------------------------------------------------- /Widgets/DynamicIntentWidget/README.md: -------------------------------------------------------------------------------- 1 | # Dynamic Intent Widget 2 | 3 | Configure the Widget with data that can be changed dynamically. 4 | 5 | ## Preview 6 | 7 | ![Dynamic Intent Widget](../../.resources/Recordings/DynamicIntentWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/EnvironmentWidget/EnvironmentWidget+Entry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension EnvironmentWidget { 26 | struct Entry: TimelineEntry { 27 | var date: Date = .now 28 | } 29 | } 30 | 31 | // MARK: - Data 32 | 33 | extension EnvironmentWidget.Entry { 34 | static var placeholder: Self { 35 | .init() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Widgets/EnvironmentWidget/EnvironmentWidget+EntryView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | extension EnvironmentWidget { 26 | struct EntryView: View { 27 | @Environment(\.colorScheme) var colorScheme 28 | @Environment(\.widgetFamily) var widgetFamily 29 | 30 | let entry: Entry 31 | 32 | var body: some View { 33 | VStack(alignment: .leading) { 34 | WidgetHeaderView(title: "Environment") 35 | Spacer() 36 | contentView 37 | Spacer() 38 | } 39 | .containerBackground(backgroundColor.opacity(0.5), for: .widget) 40 | } 41 | } 42 | } 43 | 44 | // MARK: - Content 45 | 46 | extension EnvironmentWidget.EntryView { 47 | @ViewBuilder 48 | private var contentView: some View { 49 | Text("Widget family") 50 | .font(.subheadline) 51 | .bold() 52 | Text(String(describing: widgetFamily)) 53 | .font(.subheadline) 54 | } 55 | } 56 | 57 | // MARK: - Helpers 58 | 59 | extension EnvironmentWidget.EntryView { 60 | private var backgroundColor: Color { 61 | colorScheme == .dark ? .red : .orange 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Widgets/EnvironmentWidget/EnvironmentWidget+Provider.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension EnvironmentWidget { 26 | struct Provider: TimelineProvider { 27 | func placeholder(in context: Context) -> Entry { 28 | .placeholder 29 | } 30 | 31 | func getSnapshot(in context: Context, completion: @escaping (Entry) -> Void) { 32 | completion(.placeholder) 33 | } 34 | 35 | func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { 36 | completion(.init(entries: [.placeholder], policy: .never)) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Widgets/EnvironmentWidget/EnvironmentWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct EnvironmentWidget: Widget { 27 | private let kind = WidgetType.environment.kind 28 | 29 | var body: some WidgetConfiguration { 30 | StaticConfiguration(kind: kind, provider: Provider()) { 31 | EntryView(entry: $0) 32 | } 33 | .configurationDisplayName("Environment Widget") 34 | .description("Customize the Widget view depending on Environment variables.") 35 | .supportedFamilies([.systemSmall, .systemMedium]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .systemSmall) { 42 | EnvironmentWidget() 43 | } timeline: { 44 | EnvironmentWidget.Entry.placeholder 45 | } 46 | -------------------------------------------------------------------------------- /Widgets/EnvironmentWidget/README.md: -------------------------------------------------------------------------------- 1 | # Environment Widget 2 | 3 | Customize the Widget view depending on Environment variables. 4 | 5 | ## Preview 6 | 7 | ![Environment Widget](../../.resources/Recordings/EnvironmentWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/IntentWidget/IntentWidget+Entry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension IntentWidget { 26 | struct Entry: TimelineEntry { 27 | var date: Date = .now 28 | var background: IntentWidgetBackground 29 | } 30 | } 31 | 32 | // MARK: - Background 33 | 34 | struct IntentWidgetBackground { 35 | var type: IntentWidgetBackgroundType = .color 36 | var colors: [IntentWidgetBackgroundColor?] = [.teal] 37 | } 38 | 39 | // MARK: - Data 40 | 41 | extension IntentWidget.Entry { 42 | static var placeholder: Self { 43 | .color 44 | } 45 | 46 | static var color: Self { 47 | .init(background: .init(type: .color, colors: [.teal])) 48 | } 49 | 50 | static var gradient: Self { 51 | .init(background: .init(type: .gradient, colors: [.teal, .yellow])) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Widgets/IntentWidget/IntentWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct IntentWidget: Widget { 27 | private let kind: String = WidgetType.intent.kind 28 | 29 | var body: some WidgetConfiguration { 30 | AppIntentConfiguration(kind: kind, intent: IntentWidgetBackgroundIntent.self, provider: Provider()) { 31 | EntryView(entry: $0) 32 | } 33 | .configurationDisplayName("Intent Widget") 34 | .description("Configure the Widget by changing its background type and color.") 35 | .supportedFamilies([.systemSmall]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .systemSmall) { 42 | IntentWidget() 43 | } timeline: { 44 | IntentWidget.Entry.color 45 | IntentWidget.Entry.gradient 46 | } 47 | -------------------------------------------------------------------------------- /Widgets/IntentWidget/README.md: -------------------------------------------------------------------------------- 1 | # Intent Widget 2 | 3 | Configure the Widget by changing its background type and color. 4 | 5 | ## Preview 6 | 7 | ![Intent Widget](../../.resources/Recordings/IntentWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/InteractiveWidget/InteractiveWidget+Entry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension InteractiveWidget { 26 | struct Entry: TimelineEntry { 27 | var date: Date = .now 28 | var counter: EventCounter 29 | } 30 | } 31 | 32 | // MARK: - EventCounter 33 | 34 | struct EventCounter: Identifiable { 35 | var id: Int 36 | var value: Int 37 | } 38 | 39 | // MARK: - Data 40 | 41 | extension InteractiveWidget.Entry { 42 | static var placeholder: Self { 43 | .init(counter: .placeholder) 44 | } 45 | } 46 | 47 | extension EventCounter { 48 | static var placeholder: Self { 49 | .init(id: 1, value: 1) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Widgets/InteractiveWidget/InteractiveWidget+EntryView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | extension InteractiveWidget { 26 | struct EntryView: View { 27 | let entry: Entry 28 | 29 | var body: some View { 30 | VStack(alignment: .leading) { 31 | WidgetHeaderView(title: "Interactive") 32 | Spacer() 33 | counterView 34 | Spacer() 35 | buttonsView 36 | } 37 | .containerBackground(.clear, for: .widget) 38 | } 39 | } 40 | } 41 | 42 | // MARK: - Content 43 | 44 | extension InteractiveWidget.EntryView { 45 | private var counterView: some View { 46 | Text("Counter: \(entry.counter.value)") 47 | .font(.subheadline) 48 | } 49 | 50 | private var buttonsView: some View { 51 | HStack { 52 | Button(intent: InteractiveWidgetIncreaseIntent(counter: entry.counter)) { 53 | Image(systemName: "plus") 54 | .padding(2) 55 | } 56 | Button(intent: InteractiveWidgetResetIntent(counter: entry.counter)) { 57 | Image(systemName: "arrow.circlepath") 58 | } 59 | } 60 | .buttonStyle(.bordered) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Widgets/InteractiveWidget/InteractiveWidget+Provider.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension InteractiveWidget { 26 | struct Provider: TimelineProvider { 27 | func placeholder(in context: Context) -> Entry { 28 | .placeholder 29 | } 30 | 31 | func getSnapshot(in context: Context, completion: @escaping (Entry) -> Void) { 32 | completion(.placeholder) 33 | } 34 | 35 | func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { 36 | let id = EventCounter.placeholder.id 37 | let key = UserDefaultKey.eventCounter(id: id) 38 | let value = UserDefaults.appGroup.integer(forKey: key) 39 | let entry = Entry(counter: .init(id: id, value: value)) 40 | completion(.init(entries: [entry], policy: .never)) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Widgets/InteractiveWidget/InteractiveWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct InteractiveWidget: Widget { 27 | private let kind: String = WidgetType.interactive.kind 28 | 29 | var body: some WidgetConfiguration { 30 | StaticConfiguration(kind: kind, provider: Provider()) { 31 | EntryView(entry: $0) 32 | } 33 | .configurationDisplayName("Interactive Widget") 34 | .description("Interact with elements of the Widget.") 35 | .supportedFamilies([.systemSmall]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .systemSmall) { 42 | InteractiveWidget() 43 | } timeline: { 44 | InteractiveWidget.Entry.placeholder 45 | } 46 | -------------------------------------------------------------------------------- /Widgets/InteractiveWidget/README.md: -------------------------------------------------------------------------------- 1 | # Interactive Widget 2 | 3 | Interact with elements of the Widget. 4 | 5 | ## Preview 6 | 7 | ![Interactive Widget](../../.resources/Recordings/InteractiveWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/LiveActivityWidget/README.md: -------------------------------------------------------------------------------- 1 | # Live Activity Widget 2 | 3 | Create a Live Activity to show the delivery status. 4 | 5 | ## Preview 6 | 7 | ![Live Activity Widget](../../.resources/Recordings/LiveActivityWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/LiveActivityWidget/Shared/LiveActivityView+Time.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | extension LiveActivityView { 26 | struct TimeView: View { 27 | let state: DeliveryAttributes.ContentState 28 | 29 | var body: some View { 30 | Image(systemName: "square") 31 | .hidden() 32 | .padding(7) 33 | .overlay { 34 | contentView 35 | } 36 | } 37 | } 38 | } 39 | 40 | // MARK: - Content 41 | 42 | extension LiveActivityView.TimeView { 43 | @ViewBuilder 44 | private var contentView: some View { 45 | if state.deliveryState == .arrived { 46 | Image(systemName: "flag.checkered") 47 | .imageScale(.large) 48 | } else { 49 | Text("\(remainingTimeInMinutes)m") 50 | } 51 | } 52 | } 53 | 54 | // MARK: - Helpers 55 | 56 | extension LiveActivityView.TimeView { 57 | private var remainingTimeInMinutes: Int { 58 | let seconds = Date().distance(to: state.expectedArrivalDate) 59 | return Int(seconds / 60) 60 | } 61 | } 62 | 63 | // MARK: - Preview 64 | 65 | #Preview { 66 | HStack { 67 | ForEach(DeliveryAttributes.previewStates, id: \.self) { 68 | LiveActivityView.TimeView( 69 | state: $0 70 | ) 71 | .border(.red) 72 | } 73 | } 74 | .scaleEffect(2) 75 | } 76 | -------------------------------------------------------------------------------- /Widgets/LiveActivityWidget/Shared/LiveActivityView+Title.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | extension LiveActivityView { 26 | struct TitleView: View { 27 | let delivery: Delivery 28 | 29 | var body: some View { 30 | Text("#\(delivery.id) - \(delivery.itemsCount) items") 31 | .font(.headline) 32 | } 33 | } 34 | } 35 | 36 | // MARK: - Preview 37 | 38 | #Preview { 39 | LiveActivityView.TitleView(delivery: .sent()) 40 | .border(.red) 41 | } 42 | -------------------------------------------------------------------------------- /Widgets/LockScreenWidget/LockScreenWidget+Entry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension LockScreenWidget { 26 | struct Entry: TimelineEntry { 27 | var date: Date = .now 28 | let fractionOfDay: Double 29 | } 30 | } 31 | 32 | // MARK: - Data 33 | 34 | extension LockScreenWidget.Entry { 35 | static var placeholder: Self { 36 | .init(fractionOfDay: 0.67) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Widgets/LockScreenWidget/LockScreenWidget+Provider.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension LockScreenWidget { 26 | struct Provider: TimelineProvider { 27 | func placeholder(in context: Context) -> Entry { 28 | .placeholder 29 | } 30 | 31 | func getSnapshot(in context: Context, completion: @escaping (Entry) -> Void) { 32 | completion(.placeholder) 33 | } 34 | 35 | func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { 36 | let currentDate = Date() 37 | let midnight = Calendar.current.startOfDay(for: currentDate) 38 | 39 | let hoursPassed = Calendar.current 40 | .dateComponents([.hour], from: midnight, to: currentDate) 41 | .hour ?? 0 42 | let fractionOfDay = Double(hoursPassed) / 24 43 | let nextDate = midnight.adding(.hour, value: hoursPassed + 1) 44 | 45 | let entry = Entry(date: currentDate, fractionOfDay: fractionOfDay) 46 | let timeline = Timeline(entries: [entry], policy: .after(nextDate)) 47 | completion(timeline) 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Widgets/LockScreenWidget/LockScreenWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct LockScreenWidget: Widget { 27 | private let kind: String = WidgetType.lockScreen.kind 28 | 29 | var body: some WidgetConfiguration { 30 | StaticConfiguration(kind: kind, provider: Provider()) { 31 | EntryView(entry: $0) 32 | } 33 | .configurationDisplayName("Lock Screen Widget") 34 | .description("Display the Widget on both the lock screen and the home screen.") 35 | .supportedFamilies([.accessoryCircular, .accessoryInline, .accessoryRectangular, .systemSmall]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .accessoryCircular) { 42 | LockScreenWidget() 43 | } timeline: { 44 | LockScreenWidget.Entry.placeholder 45 | } 46 | -------------------------------------------------------------------------------- /Widgets/LockScreenWidget/README.md: -------------------------------------------------------------------------------- 1 | # Lock Screen Widget 2 | 3 | Display the Widget on both the lock screen and the home screen. 4 | 5 | ## Preview 6 | 7 | ![Lock Screen Widget](../../.resources/Recordings/LockScreenWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/NetworkWidget/CountryWebRepository.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import Combine 24 | import Foundation 25 | 26 | class CountryWebRepository: WebRepository { 27 | let session: URLSession 28 | 29 | init(session: URLSession = .shared) { 30 | self.session = session 31 | } 32 | } 33 | 34 | // MARK: - ErrorResponse 35 | 36 | extension CountryWebRepository { 37 | struct ErrorResponse: ErrorResponseDecodable { 38 | let message: String 39 | 40 | var error: String { 41 | message 42 | } 43 | } 44 | } 45 | 46 | // MARK: - Resource 47 | 48 | struct CountryResource: APIResource { 49 | let serverPath = "restcountries.com" 50 | let methodPath: String 51 | var queryItems: [URLQueryItem]? 52 | 53 | init(code: String) { 54 | methodPath = "/v3.1/alpha/\(code)" 55 | queryItems = [.init(name: "fields", value: "name,capital")] 56 | } 57 | } 58 | 59 | // MARK: - Response 60 | 61 | extension CountryResource { 62 | struct Response: Decodable { 63 | let name: Name 64 | let capital: [String] 65 | } 66 | } 67 | 68 | extension CountryResource.Response { 69 | struct Name: Decodable { 70 | let common: String 71 | let official: String 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Widgets/NetworkWidget/NetworkWidget+Entry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension NetworkWidget { 26 | struct Entry: TimelineEntry { 27 | var date: Date = .now 28 | var country: Loadable 29 | } 30 | } 31 | 32 | // MARK: - CurrencyPair 33 | 34 | extension NetworkWidget.Entry { 35 | struct Country { 36 | let name: String 37 | let capital: String 38 | } 39 | } 40 | 41 | // MARK: - Data 42 | 43 | extension NetworkWidget.Entry { 44 | static var placeholder: Self { 45 | .init(country: .loaded(value: .poland)) 46 | } 47 | } 48 | 49 | extension NetworkWidget.Entry.Country { 50 | static var poland: Self { 51 | .init(name: "Poland", capital: "Warsaw") 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Widgets/NetworkWidget/NetworkWidget+EntryView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | extension NetworkWidget { 26 | struct EntryView: View { 27 | let entry: Entry 28 | 29 | var body: some View { 30 | VStack(alignment: .leading) { 31 | WidgetHeaderView(title: "Network") 32 | Spacer() 33 | contentView 34 | Spacer() 35 | } 36 | .containerBackground(.clear, for: .widget) 37 | } 38 | } 39 | } 40 | 41 | // MARK: - Content 42 | 43 | extension NetworkWidget.EntryView { 44 | private var contentView: some View { 45 | Group { 46 | switch entry.country { 47 | case .notRequested: 48 | Text("Not requested") 49 | .foregroundStyle(.secondary) 50 | case .isLoading: 51 | Text("Loading...") 52 | .foregroundStyle(.secondary) 53 | case .loaded(let country), .cached(let country): 54 | countryView(country: country) 55 | case .failed(let error): 56 | Text(error) 57 | .foregroundStyle(.red) 58 | } 59 | } 60 | .font(.subheadline) 61 | } 62 | 63 | @ViewBuilder 64 | private func countryView(country: NetworkWidget.Entry.Country) -> some View { 65 | Text(country.name) 66 | .bold() 67 | Text(country.capital) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Widgets/NetworkWidget/NetworkWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct NetworkWidget: Widget { 27 | private let kind: String = WidgetType.network.kind 28 | 29 | var body: some WidgetConfiguration { 30 | StaticConfiguration(kind: kind, provider: Provider()) { 31 | EntryView(entry: $0) 32 | } 33 | .configurationDisplayName("Network Widget") 34 | .description("Load data into the Widget from a network request.") 35 | .supportedFamilies([.systemSmall]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .systemSmall) { 42 | NetworkWidget() 43 | } timeline: { 44 | NetworkWidget.Entry(country: .notRequested) 45 | NetworkWidget.Entry(country: .isLoading) 46 | NetworkWidget.Entry(country: .loaded(value: .poland)) 47 | NetworkWidget.Entry(country: .failed(error: "Error")) 48 | } 49 | -------------------------------------------------------------------------------- /Widgets/NetworkWidget/README.md: -------------------------------------------------------------------------------- 1 | # Network Widget 2 | 3 | Load data into the Widget from a network request. 4 | 5 | ## Preview 6 | 7 | ![Network Widget](../../.resources/Recordings/NetworkWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/Resources/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xCC", 9 | "green" : "0xB1", 10 | "red" : "0x00" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xFF", 27 | "green" : "0xDD", 28 | "red" : "0x00" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Widgets/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Widgets/Resources/Assets.xcassets/AppIcon.appiconset/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/Widgets/Resources/Assets.xcassets/AppIcon.appiconset/icon.png -------------------------------------------------------------------------------- /Widgets/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Widgets/Resources/main.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawello2222/WidgetExamples/3597d226dced7cf11d2ae0304725b359f0770b91/Widgets/Resources/main.mp3 -------------------------------------------------------------------------------- /Widgets/SharedViewWidget/README.md: -------------------------------------------------------------------------------- 1 | # Shared View Widget 2 | 3 | Display the Widget view directly in the parent App. 4 | 5 | ## Preview 6 | 7 | ![Shared View Widget](../../.resources/Recordings/SharedViewWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/SharedViewWidget/Shared/SharedViewWidgetEntry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | struct SharedViewWidgetEntry: TimelineEntry { 26 | var date: Date = .now 27 | var icon: String 28 | } 29 | 30 | // MARK: - Data 31 | 32 | extension SharedViewWidgetEntry { 33 | static var placeholder: Self { 34 | .init(icon: "star.fill") 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Widgets/SharedViewWidget/Shared/SharedViewWidgetEntryView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | struct SharedViewWidgetEntryView: View { 26 | var entry: SharedViewWidgetEntry 27 | 28 | var body: some View { 29 | GeometryReader { geometry in 30 | ZStack { 31 | circleView 32 | iconView 33 | .frame( 34 | maxWidth: geometry.size.width / 2, 35 | maxHeight: geometry.size.height / 2 36 | ) 37 | } 38 | } 39 | .containerBackground(.clear, for: .widget) 40 | } 41 | } 42 | 43 | // MARK: - Content 44 | 45 | extension SharedViewWidgetEntryView { 46 | private var circleView: some View { 47 | Circle() 48 | .fill(.teal.gradient) 49 | } 50 | 51 | private var iconView: some View { 52 | Image(systemName: entry.icon) 53 | .resizable() 54 | .scaledToFit() 55 | .foregroundStyle(.white.gradient) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Widgets/SharedViewWidget/SharedViewWidget+Provider.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension SharedViewWidget { 26 | struct Provider: TimelineProvider { 27 | func placeholder(in context: Context) -> SharedViewWidgetEntry { 28 | .placeholder 29 | } 30 | 31 | func getSnapshot(in context: Context, completion: @escaping (SharedViewWidgetEntry) -> Void) { 32 | completion(.placeholder) 33 | } 34 | 35 | func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { 36 | completion(.init(entries: [.placeholder], policy: .never)) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Widgets/SharedViewWidget/SharedViewWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct SharedViewWidget: Widget { 27 | private let kind = WidgetType.sharedView.kind 28 | 29 | var body: some WidgetConfiguration { 30 | StaticConfiguration(kind: kind, provider: Provider()) { 31 | SharedViewWidgetEntryView(entry: $0) 32 | } 33 | .configurationDisplayName("Shared View Widget") 34 | .description("Display the Widget view directly in the parent App.") 35 | .supportedFamilies([.systemSmall]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .systemSmall) { 42 | SharedViewWidget() 43 | } timeline: { 44 | SharedViewWidgetEntry.placeholder 45 | } 46 | -------------------------------------------------------------------------------- /Widgets/Supporting Files/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.widgetkit-extension 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Widgets/Supporting Files/Widgets.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.com.tersacore.widget-examples 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Widgets/SwiftDataWidget/README.md: -------------------------------------------------------------------------------- 1 | # SwiftData Widget 2 | 3 | Use SwiftData to share data between the App and the Widget. 4 | 5 | ## Preview 6 | 7 | ![SwiftData Widget](../../.resources/Recordings/SwiftDataWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/SwiftDataWidget/SwiftDataWidget+Entry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import WidgetKit 24 | 25 | extension SwiftDataWidget { 26 | struct Entry: TimelineEntry { 27 | var date: Date = .now 28 | var productInfo: ProductInfo? 29 | } 30 | } 31 | 32 | // MARK: - ProductInfo 33 | 34 | extension SwiftDataWidget.Entry { 35 | struct ProductInfo { 36 | let count: Int 37 | let lastItem: Product? 38 | } 39 | } 40 | 41 | // MARK: - Data 42 | 43 | extension SwiftDataWidget.Entry { 44 | static var empty: Self { 45 | .init() 46 | } 47 | 48 | static var placeholder: Self { 49 | .init(productInfo: .placeholder) 50 | } 51 | } 52 | 53 | extension SwiftDataWidget.Entry.ProductInfo { 54 | static var placeholder: Self { 55 | .init(count: 3, lastItem: .placeholder) 56 | } 57 | } 58 | 59 | extension Product { 60 | static let placeholder = Product( 61 | name: "Product #3", 62 | creationDate: .now 63 | ) 64 | } 65 | -------------------------------------------------------------------------------- /Widgets/SwiftDataWidget/SwiftDataWidget+EntryView.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | 25 | extension SwiftDataWidget { 26 | struct EntryView: View { 27 | let entry: Entry 28 | 29 | var body: some View { 30 | VStack(alignment: .leading) { 31 | WidgetHeaderView(title: "SwiftData") 32 | Spacer() 33 | contentView 34 | Spacer() 35 | } 36 | .containerBackground(.clear, for: .widget) 37 | } 38 | } 39 | } 40 | 41 | // MARK: - Content 42 | 43 | extension SwiftDataWidget.EntryView { 44 | @ViewBuilder 45 | private var contentView: some View { 46 | if let productInfo = entry.productInfo { 47 | Text("Count: \(productInfo.count)") 48 | .font(.subheadline) 49 | .bold() 50 | if let lastItem = productInfo.lastItem { 51 | Group { 52 | Text("Last item:") 53 | Text(lastItem.name) 54 | } 55 | .font(.footnote) 56 | } 57 | } else { 58 | Text("Info unavailable") 59 | .font(.subheadline) 60 | .foregroundStyle(.secondary) 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Widgets/SwiftDataWidget/SwiftDataWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct SwiftDataWidget: Widget { 27 | private let kind = WidgetType.swiftData.kind 28 | 29 | var body: some WidgetConfiguration { 30 | StaticConfiguration(kind: kind, provider: Provider()) { 31 | EntryView(entry: $0) 32 | } 33 | .configurationDisplayName("SwiftData Widget") 34 | .description("Use SwiftData to share data between the App and the Widget.") 35 | .supportedFamilies([.systemSmall]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .systemSmall) { 42 | SwiftDataWidget() 43 | } timeline: { 44 | SwiftDataWidget.Entry.empty 45 | SwiftDataWidget.Entry.placeholder 46 | } 47 | -------------------------------------------------------------------------------- /Widgets/URLImageWidget/README.md: -------------------------------------------------------------------------------- 1 | # URL Image Widget 2 | 3 | Display an image downloaded from an external URL and cache it. 4 | 5 | ## Preview 6 | 7 | ![URL Image Widget](../../.resources/Recordings/URLImageWidget.gif) 8 | -------------------------------------------------------------------------------- /Widgets/URLImageWidget/URLImageWidget+Entry.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | extension URLImageWidget { 27 | struct Entry: TimelineEntry { 28 | var date: Date = .now 29 | var image: Loadable 30 | var requestCount = 0 31 | } 32 | } 33 | 34 | // MARK: - Data 35 | 36 | extension URLImageWidget.Entry { 37 | static var placeholder: Self { 38 | .init(image: .loaded(value: .init(systemName: "photo"))) 39 | } 40 | 41 | static var notRequested: Self { 42 | .init(image: .notRequested) 43 | } 44 | 45 | static var isLoading: Self { 46 | .init(image: .isLoading) 47 | } 48 | 49 | static var loaded: Self { 50 | .init(image: .loaded(value: .init(systemName: "photo")), requestCount: 1) 51 | } 52 | 53 | static var cached: Self { 54 | .init(image: .cached(value: .init(systemName: "photo")), requestCount: 2) 55 | } 56 | 57 | static var failed: Self { 58 | .init(image: .failed(error: "Error")) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Widgets/URLImageWidget/URLImageWidget.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | struct URLImageWidget: Widget { 27 | private let kind: String = WidgetType.urlImage.kind 28 | 29 | var body: some WidgetConfiguration { 30 | StaticConfiguration(kind: kind, provider: Provider()) { 31 | EntryView(entry: $0) 32 | } 33 | .configurationDisplayName("URLImage Widget") 34 | .description("Display an image downloaded from an external URL and cache it.") 35 | .supportedFamilies([.systemSmall]) 36 | } 37 | } 38 | 39 | // MARK: - Preview 40 | 41 | #Preview(as: .systemSmall) { 42 | URLImageWidget() 43 | } timeline: { 44 | URLImageWidget.Entry.notRequested 45 | URLImageWidget.Entry.isLoading 46 | URLImageWidget.Entry.loaded 47 | URLImageWidget.Entry.cached 48 | URLImageWidget.Entry.failed 49 | } 50 | -------------------------------------------------------------------------------- /Widgets/WidgetBundle.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2020-Present Paweł Wiszenko 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | import SwiftUI 24 | import WidgetKit 25 | 26 | @main 27 | struct WidgetExamplesWidgetBundle: WidgetBundle { 28 | var body: some Widget { 29 | WidgetBundle1().body 30 | WidgetBundle2().body 31 | } 32 | } 33 | 34 | struct WidgetBundle1: WidgetBundle { 35 | var body: some Widget { 36 | AnalogClockWidget() 37 | AppGroupWidget() 38 | AudioPlaybackWidget() 39 | CoreDataWidget() 40 | CountdownWidget() 41 | DeepLinkWidget() 42 | DigitalClockWidget() 43 | DynamicIntentWidget() 44 | EnvironmentWidget() 45 | IntentWidget() 46 | } 47 | } 48 | 49 | struct WidgetBundle2: WidgetBundle { 50 | var body: some Widget { 51 | InteractiveWidget() 52 | LiveActivityWidget() 53 | LockScreenWidget() 54 | NetworkWidget() 55 | SharedViewWidget() 56 | SwiftDataWidget() 57 | URLImageWidget() 58 | } 59 | } 60 | --------------------------------------------------------------------------------