├── .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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 |
--------------------------------------------------------------------------------