From 499d9695cda1e6bff564a104526cf5b211267d81 Mon Sep 17 00:00:00 2001 From: Florian Schweizer Date: Thu, 9 Dec 2021 20:43:44 +0100 Subject: [PATCH 1/2] End of lesson 1 --- .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 98 +++++++++ .../Assets.xcassets/Contents.json | 6 + .../WidgetBackground.colorset/Contents.json | 11 + WidgetKitCourse Widget/Info.plist | 11 + WidgetKitCourse Widget/Provider.swift | 34 ++++ WidgetKitCourse Widget/SimpleEntry.swift | 12 ++ .../WidgetKitCourse_Widget.swift | 29 +++ WidgetKitCourse Widget/WidgetView.swift | 17 ++ WidgetKitCourse.xcodeproj/project.pbxproj | 190 ++++++++++++++++++ .../xcschemes/xcschememanagement.plist | 7 +- 11 files changed, 425 insertions(+), 1 deletion(-) create mode 100644 WidgetKitCourse Widget/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 WidgetKitCourse Widget/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 WidgetKitCourse Widget/Assets.xcassets/Contents.json create mode 100644 WidgetKitCourse Widget/Assets.xcassets/WidgetBackground.colorset/Contents.json create mode 100644 WidgetKitCourse Widget/Info.plist create mode 100644 WidgetKitCourse Widget/Provider.swift create mode 100644 WidgetKitCourse Widget/SimpleEntry.swift create mode 100644 WidgetKitCourse Widget/WidgetKitCourse_Widget.swift create mode 100644 WidgetKitCourse Widget/WidgetView.swift diff --git a/WidgetKitCourse Widget/Assets.xcassets/AccentColor.colorset/Contents.json b/WidgetKitCourse Widget/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/WidgetKitCourse Widget/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/WidgetKitCourse Widget/Assets.xcassets/AppIcon.appiconset/Contents.json b/WidgetKitCourse Widget/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..9221b9b --- /dev/null +++ b/WidgetKitCourse Widget/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/WidgetKitCourse Widget/Assets.xcassets/Contents.json b/WidgetKitCourse Widget/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/WidgetKitCourse Widget/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/WidgetKitCourse Widget/Assets.xcassets/WidgetBackground.colorset/Contents.json b/WidgetKitCourse Widget/Assets.xcassets/WidgetBackground.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/WidgetKitCourse Widget/Assets.xcassets/WidgetBackground.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/WidgetKitCourse Widget/Info.plist b/WidgetKitCourse Widget/Info.plist new file mode 100644 index 0000000..0f118fb --- /dev/null +++ b/WidgetKitCourse Widget/Info.plist @@ -0,0 +1,11 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.widgetkit-extension + + + diff --git a/WidgetKitCourse Widget/Provider.swift b/WidgetKitCourse Widget/Provider.swift new file mode 100644 index 0000000..c6f80ed --- /dev/null +++ b/WidgetKitCourse Widget/Provider.swift @@ -0,0 +1,34 @@ +// +// Provider.swift +// WidgetKitCourse WidgetExtension +// +// Created by Florian Schweizer on 06.12.21. +// + +import WidgetKit + +struct Provider: TimelineProvider { + func placeholder(in context: Context) -> SimpleEntry { + SimpleEntry(date: Date()) + } + + func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) { + let entry = SimpleEntry(date: Date()) + completion(entry) + } + + func getTimeline(in context: Context, completion: @escaping (Timeline) -> ()) { + var entries: [SimpleEntry] = [] + + // Generate a timeline consisting of five entries an hour apart, starting from the current date. + let currentDate = Date() + for hourOffset in 0 ..< 5 { + let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! + let entry = SimpleEntry(date: entryDate) + entries.append(entry) + } + + let timeline = Timeline(entries: entries, policy: .atEnd) + completion(timeline) + } +} diff --git a/WidgetKitCourse Widget/SimpleEntry.swift b/WidgetKitCourse Widget/SimpleEntry.swift new file mode 100644 index 0000000..2946530 --- /dev/null +++ b/WidgetKitCourse Widget/SimpleEntry.swift @@ -0,0 +1,12 @@ +// +// SimpleEntry.swift +// WidgetKitCourse WidgetExtension +// +// Created by Florian Schweizer on 06.12.21. +// + +import WidgetKit + +struct SimpleEntry: TimelineEntry { + let date: Date +} diff --git a/WidgetKitCourse Widget/WidgetKitCourse_Widget.swift b/WidgetKitCourse Widget/WidgetKitCourse_Widget.swift new file mode 100644 index 0000000..2e8e4b4 --- /dev/null +++ b/WidgetKitCourse Widget/WidgetKitCourse_Widget.swift @@ -0,0 +1,29 @@ +// +// WidgetKitCourse_Widget.swift +// WidgetKitCourse Widget +// +// Created by Florian Schweizer on 06.12.21. +// + +import WidgetKit +import SwiftUI + +@main +struct WidgetKitCourse_Widget: Widget { + let kind: String = "WidgetKitCourse_Widget" + + var body: some WidgetConfiguration { + StaticConfiguration(kind: kind, provider: Provider()) { entry in + WidgetView(entry: entry) + } + .configurationDisplayName("My Widget") + .description("This is an example widget.") + } +} + +struct WidgetKitCourse_Widget_Previews: PreviewProvider { + static var previews: some View { + WidgetView(entry: SimpleEntry(date: Date())) + .previewContext(WidgetPreviewContext(family: .systemSmall)) + } +} diff --git a/WidgetKitCourse Widget/WidgetView.swift b/WidgetKitCourse Widget/WidgetView.swift new file mode 100644 index 0000000..103844b --- /dev/null +++ b/WidgetKitCourse Widget/WidgetView.swift @@ -0,0 +1,17 @@ +// +// WidgetView.swift +// WidgetKitCourse WidgetExtension +// +// Created by Florian Schweizer on 06.12.21. +// + +import WidgetKit +import SwiftUI + +struct WidgetView: View { + var entry: Provider.Entry + + var body: some View { + Text(entry.date, style: .time) + } +} diff --git a/WidgetKitCourse.xcodeproj/project.pbxproj b/WidgetKitCourse.xcodeproj/project.pbxproj index 194d038..71b5222 100644 --- a/WidgetKitCourse.xcodeproj/project.pbxproj +++ b/WidgetKitCourse.xcodeproj/project.pbxproj @@ -13,8 +13,40 @@ 5C658B0E27578E1A00435678 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5C658B0D27578E1A00435678 /* Preview Assets.xcassets */; }; 5C658B172757923A00435678 /* Todo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C658B162757923A00435678 /* Todo.swift */; }; 5C658B192757926700435678 /* TodoService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C658B182757926700435678 /* TodoService.swift */; }; + 5CA9F7BA275E56D600EAA6D2 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CA9F7B9275E56D600EAA6D2 /* WidgetKit.framework */; }; + 5CA9F7BC275E56D600EAA6D2 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CA9F7BB275E56D600EAA6D2 /* SwiftUI.framework */; }; + 5CA9F7BF275E56D600EAA6D2 /* WidgetKitCourse_Widget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA9F7BE275E56D600EAA6D2 /* WidgetKitCourse_Widget.swift */; }; + 5CA9F7C1275E56D700EAA6D2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5CA9F7C0275E56D700EAA6D2 /* Assets.xcassets */; }; + 5CA9F7C5275E56D700EAA6D2 /* WidgetKitCourse WidgetExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 5CA9F7B7275E56D600EAA6D2 /* WidgetKitCourse WidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 5CA9F7CB275E586200EAA6D2 /* Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA9F7CA275E586200EAA6D2 /* Provider.swift */; }; + 5CA9F7CD275E588B00EAA6D2 /* SimpleEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA9F7CC275E588B00EAA6D2 /* SimpleEntry.swift */; }; + 5CA9F7CF275E58A100EAA6D2 /* WidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA9F7CE275E58A100EAA6D2 /* WidgetView.swift */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 5CA9F7C3275E56D700EAA6D2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5C658AFB27578E1900435678 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5CA9F7B6275E56D600EAA6D2; + remoteInfo = "WidgetKitCourse WidgetExtension"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 5CA9F7C6275E56D700EAA6D2 /* Embed App Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 5CA9F7C5275E56D700EAA6D2 /* WidgetKitCourse WidgetExtension.appex in Embed App Extensions */, + ); + name = "Embed App Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 5C658B0327578E1900435678 /* WidgetKitCourse.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WidgetKitCourse.app; sourceTree = BUILT_PRODUCTS_DIR; }; 5C658B0627578E1900435678 /* WidgetKitCourseApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetKitCourseApp.swift; sourceTree = ""; }; @@ -23,6 +55,15 @@ 5C658B0D27578E1A00435678 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 5C658B162757923A00435678 /* Todo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Todo.swift; sourceTree = ""; }; 5C658B182757926700435678 /* TodoService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodoService.swift; sourceTree = ""; }; + 5CA9F7B7275E56D600EAA6D2 /* WidgetKitCourse WidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "WidgetKitCourse WidgetExtension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5CA9F7B9275E56D600EAA6D2 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; + 5CA9F7BB275E56D600EAA6D2 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; + 5CA9F7BE275E56D600EAA6D2 /* WidgetKitCourse_Widget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetKitCourse_Widget.swift; sourceTree = ""; }; + 5CA9F7C0275E56D700EAA6D2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 5CA9F7C2275E56D700EAA6D2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5CA9F7CA275E586200EAA6D2 /* Provider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Provider.swift; sourceTree = ""; }; + 5CA9F7CC275E588B00EAA6D2 /* SimpleEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleEntry.swift; sourceTree = ""; }; + 5CA9F7CE275E58A100EAA6D2 /* WidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -33,6 +74,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5CA9F7B4275E56D600EAA6D2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5CA9F7BC275E56D600EAA6D2 /* SwiftUI.framework in Frameworks */, + 5CA9F7BA275E56D600EAA6D2 /* WidgetKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -40,6 +90,8 @@ isa = PBXGroup; children = ( 5C658B0527578E1900435678 /* WidgetKitCourse */, + 5CA9F7BD275E56D600EAA6D2 /* WidgetKitCourse Widget */, + 5CA9F7B8275E56D600EAA6D2 /* Frameworks */, 5C658B0427578E1900435678 /* Products */, ); sourceTree = ""; @@ -48,6 +100,7 @@ isa = PBXGroup; children = ( 5C658B0327578E1900435678 /* WidgetKitCourse.app */, + 5CA9F7B7275E56D600EAA6D2 /* WidgetKitCourse WidgetExtension.appex */, ); name = Products; sourceTree = ""; @@ -89,6 +142,28 @@ path = "Feature Targets"; sourceTree = ""; }; + 5CA9F7B8275E56D600EAA6D2 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5CA9F7B9275E56D600EAA6D2 /* WidgetKit.framework */, + 5CA9F7BB275E56D600EAA6D2 /* SwiftUI.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 5CA9F7BD275E56D600EAA6D2 /* WidgetKitCourse Widget */ = { + isa = PBXGroup; + children = ( + 5CA9F7BE275E56D600EAA6D2 /* WidgetKitCourse_Widget.swift */, + 5CA9F7CE275E58A100EAA6D2 /* WidgetView.swift */, + 5CA9F7C0275E56D700EAA6D2 /* Assets.xcassets */, + 5CA9F7C2275E56D700EAA6D2 /* Info.plist */, + 5CA9F7CA275E586200EAA6D2 /* Provider.swift */, + 5CA9F7CC275E588B00EAA6D2 /* SimpleEntry.swift */, + ); + path = "WidgetKitCourse Widget"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -99,16 +174,35 @@ 5C658AFF27578E1900435678 /* Sources */, 5C658B0027578E1900435678 /* Frameworks */, 5C658B0127578E1900435678 /* Resources */, + 5CA9F7C6275E56D700EAA6D2 /* Embed App Extensions */, ); buildRules = ( ); dependencies = ( + 5CA9F7C4275E56D700EAA6D2 /* PBXTargetDependency */, ); name = WidgetKitCourse; productName = WidgetKitCourse; productReference = 5C658B0327578E1900435678 /* WidgetKitCourse.app */; productType = "com.apple.product-type.application"; }; + 5CA9F7B6275E56D600EAA6D2 /* WidgetKitCourse WidgetExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5CA9F7C9275E56D700EAA6D2 /* Build configuration list for PBXNativeTarget "WidgetKitCourse WidgetExtension" */; + buildPhases = ( + 5CA9F7B3275E56D600EAA6D2 /* Sources */, + 5CA9F7B4275E56D600EAA6D2 /* Frameworks */, + 5CA9F7B5275E56D600EAA6D2 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "WidgetKitCourse WidgetExtension"; + productName = "WidgetKitCourse WidgetExtension"; + productReference = 5CA9F7B7275E56D600EAA6D2 /* WidgetKitCourse WidgetExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -122,6 +216,9 @@ 5C658B0227578E1900435678 = { CreatedOnToolsVersion = 13.1; }; + 5CA9F7B6275E56D600EAA6D2 = { + CreatedOnToolsVersion = 13.1; + }; }; }; buildConfigurationList = 5C658AFE27578E1900435678 /* Build configuration list for PBXProject "WidgetKitCourse" */; @@ -138,6 +235,7 @@ projectRoot = ""; targets = ( 5C658B0227578E1900435678 /* WidgetKitCourse */, + 5CA9F7B6275E56D600EAA6D2 /* WidgetKitCourse WidgetExtension */, ); }; /* End PBXProject section */ @@ -152,6 +250,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5CA9F7B5275E56D600EAA6D2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5CA9F7C1275E56D700EAA6D2 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -166,8 +272,27 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5CA9F7B3275E56D600EAA6D2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5CA9F7CD275E588B00EAA6D2 /* SimpleEntry.swift in Sources */, + 5CA9F7CB275E586200EAA6D2 /* Provider.swift in Sources */, + 5CA9F7CF275E58A100EAA6D2 /* WidgetView.swift in Sources */, + 5CA9F7BF275E56D600EAA6D2 /* WidgetKitCourse_Widget.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 5CA9F7C4275E56D700EAA6D2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5CA9F7B6275E56D600EAA6D2 /* WidgetKitCourse WidgetExtension */; + targetProxy = 5CA9F7C3275E56D700EAA6D2 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin XCBuildConfiguration section */ 5C658B0F27578E1A00435678 /* Debug */ = { isa = XCBuildConfiguration; @@ -288,6 +413,7 @@ 5C658B1227578E1A00435678 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; @@ -317,6 +443,7 @@ 5C658B1327578E1A00435678 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; @@ -343,6 +470,60 @@ }; name = Release; }; + 5CA9F7C7275E56D700EAA6D2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 6YDE2UY2S5; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "WidgetKitCourse Widget/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "WidgetKitCourse Widget"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "fschweizer.WidgetKitCourse.WidgetKitCourse-Widget"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5CA9F7C8275E56D700EAA6D2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 6YDE2UY2S5; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "WidgetKitCourse Widget/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "WidgetKitCourse Widget"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "fschweizer.WidgetKitCourse.WidgetKitCourse-Widget"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -364,6 +545,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 5CA9F7C9275E56D700EAA6D2 /* Build configuration list for PBXNativeTarget "WidgetKitCourse WidgetExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5CA9F7C7275E56D700EAA6D2 /* Debug */, + 5CA9F7C8275E56D700EAA6D2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 5C658AFB27578E1900435678 /* Project object */; diff --git a/WidgetKitCourse.xcodeproj/xcuserdata/flo.xcuserdatad/xcschemes/xcschememanagement.plist b/WidgetKitCourse.xcodeproj/xcuserdata/flo.xcuserdatad/xcschemes/xcschememanagement.plist index 3ffc7ea..bb7fe00 100644 --- a/WidgetKitCourse.xcodeproj/xcuserdata/flo.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/WidgetKitCourse.xcodeproj/xcuserdata/flo.xcuserdatad/xcschemes/xcschememanagement.plist @@ -4,11 +4,16 @@ SchemeUserState - WidgetKitCourse.xcscheme_^#shared#^_ + WidgetKitCourse WidgetExtension.xcscheme_^#shared#^_ orderHint 0 + WidgetKitCourse.xcscheme_^#shared#^_ + + orderHint + 1 + From b6a1b2453d70ad2ce2fba907a1f0327f99d38cf7 Mon Sep 17 00:00:00 2001 From: Florian Schweizer Date: Sat, 11 Dec 2021 10:03:48 +0100 Subject: [PATCH 2/2] Add MediumSIzeView & LargeSizeView, Add deeplinks to widget & main app --- WidgetKitCourse Widget/Provider.swift | 2 +- .../Views/LargeSizeView.swift | 54 +++++++++++++++++++ .../Views/MediumSizeView.swift | 40 ++++++++++++++ WidgetKitCourse Widget/Views/WidgetView.swift | 25 +++++++++ .../WidgetKitCourse_Widget.swift | 5 +- WidgetKitCourse Widget/WidgetView.swift | 17 ------ WidgetKitCourse.xcodeproj/project.pbxproj | 18 ++++++- .../xcschemes/xcschememanagement.plist | 4 +- .../Feature Targets/ContentView.swift | 22 ++++++++ 9 files changed, 164 insertions(+), 23 deletions(-) create mode 100644 WidgetKitCourse Widget/Views/LargeSizeView.swift create mode 100644 WidgetKitCourse Widget/Views/MediumSizeView.swift create mode 100644 WidgetKitCourse Widget/Views/WidgetView.swift delete mode 100644 WidgetKitCourse Widget/WidgetView.swift diff --git a/WidgetKitCourse Widget/Provider.swift b/WidgetKitCourse Widget/Provider.swift index c6f80ed..a786628 100644 --- a/WidgetKitCourse Widget/Provider.swift +++ b/WidgetKitCourse Widget/Provider.swift @@ -17,7 +17,7 @@ struct Provider: TimelineProvider { completion(entry) } - func getTimeline(in context: Context, completion: @escaping (Timeline) -> ()) { + func getTimeline(in context: Context, completion: @escaping (Timeline) -> ()) { var entries: [SimpleEntry] = [] // Generate a timeline consisting of five entries an hour apart, starting from the current date. diff --git a/WidgetKitCourse Widget/Views/LargeSizeView.swift b/WidgetKitCourse Widget/Views/LargeSizeView.swift new file mode 100644 index 0000000..56bf19b --- /dev/null +++ b/WidgetKitCourse Widget/Views/LargeSizeView.swift @@ -0,0 +1,54 @@ +// +// LargeSizeView.swift +// WidgetKitCourse WidgetExtension +// +// Created by Florian Schweizer on 10.12.21. +// + +import WidgetKit +import SwiftUI + +struct LargeSizeView: View { + var entry: SimpleEntry + + var body: some View { + VStack { + HStack(spacing: 16) { + Text("My Todos") + + Text(Date.now, format: .dateTime) + + Spacer() + } + .padding(8) + .background(.blue) + .foregroundColor(.white) + .clipped() + .shadow(radius: 5) + + ForEach(0..<6, id: \.self) { _ in + Link(destination: URL(string: "myapp://todo/1")!) { + HStack { + Circle() + .stroke(lineWidth: 2) + .frame(width: 30, height: 30) + .overlay { + if true { + Image(systemName: "checkmark") + } + } + + Text("todo title") + + Spacer() + } + .padding(.horizontal) + } + + Divider() + } + + Spacer() + } + } +} diff --git a/WidgetKitCourse Widget/Views/MediumSizeView.swift b/WidgetKitCourse Widget/Views/MediumSizeView.swift new file mode 100644 index 0000000..34b59d6 --- /dev/null +++ b/WidgetKitCourse Widget/Views/MediumSizeView.swift @@ -0,0 +1,40 @@ +// +// MediumSizeView.swift +// WidgetKitCourse WidgetExtension +// +// Created by Florian Schweizer on 10.12.21. +// + +import WidgetKit +import SwiftUI + +struct MediumSizeView: View { + var entry: SimpleEntry + + var body: some View { + GroupBox { + HStack { + Image(systemName: "person") + .resizable() + .scaledToFit() + .foregroundColor(.secondary) + + Divider() + + VStack(alignment: .leading) { + Text("todo title") + .font(.headline) + + Text("Completed") + .font(.subheadline) + } + + Spacer() + } + .padding() + } label: { + Label("My Todos", systemImage: "list.dash") + } + .widgetURL(URL(string: "myapp://todo/1")) + } +} diff --git a/WidgetKitCourse Widget/Views/WidgetView.swift b/WidgetKitCourse Widget/Views/WidgetView.swift new file mode 100644 index 0000000..4e94513 --- /dev/null +++ b/WidgetKitCourse Widget/Views/WidgetView.swift @@ -0,0 +1,25 @@ +// +// WidgetView.swift +// WidgetKitCourse WidgetExtension +// +// Created by Florian Schweizer on 06.12.21. +// + +import WidgetKit +import SwiftUI + +struct WidgetView: View { + @Environment(\.widgetFamily) var widgetFamily + var entry: Provider.Entry + + var body: some View { + switch widgetFamily { + case .systemMedium: + MediumSizeView(entry: entry) + case .systemLarge: + LargeSizeView(entry: entry) + default: + Text("Not implemented!") + } + } +} diff --git a/WidgetKitCourse Widget/WidgetKitCourse_Widget.swift b/WidgetKitCourse Widget/WidgetKitCourse_Widget.swift index 2e8e4b4..68ca4ab 100644 --- a/WidgetKitCourse Widget/WidgetKitCourse_Widget.swift +++ b/WidgetKitCourse Widget/WidgetKitCourse_Widget.swift @@ -16,8 +16,9 @@ struct WidgetKitCourse_Widget: Widget { StaticConfiguration(kind: kind, provider: Provider()) { entry in WidgetView(entry: entry) } - .configurationDisplayName("My Widget") - .description("This is an example widget.") + .supportedFamilies([.systemMedium, .systemLarge]) + .configurationDisplayName("My Todos") + .description("View your latest todo(s).") } } diff --git a/WidgetKitCourse Widget/WidgetView.swift b/WidgetKitCourse Widget/WidgetView.swift deleted file mode 100644 index 103844b..0000000 --- a/WidgetKitCourse Widget/WidgetView.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// WidgetView.swift -// WidgetKitCourse WidgetExtension -// -// Created by Florian Schweizer on 06.12.21. -// - -import WidgetKit -import SwiftUI - -struct WidgetView: View { - var entry: Provider.Entry - - var body: some View { - Text(entry.date, style: .time) - } -} diff --git a/WidgetKitCourse.xcodeproj/project.pbxproj b/WidgetKitCourse.xcodeproj/project.pbxproj index 71b5222..76387be 100644 --- a/WidgetKitCourse.xcodeproj/project.pbxproj +++ b/WidgetKitCourse.xcodeproj/project.pbxproj @@ -21,6 +21,8 @@ 5CA9F7CB275E586200EAA6D2 /* Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA9F7CA275E586200EAA6D2 /* Provider.swift */; }; 5CA9F7CD275E588B00EAA6D2 /* SimpleEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA9F7CC275E588B00EAA6D2 /* SimpleEntry.swift */; }; 5CA9F7CF275E58A100EAA6D2 /* WidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA9F7CE275E58A100EAA6D2 /* WidgetView.swift */; }; + 5CE387322763C69A0045EDA0 /* MediumSizeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE387312763C69A0045EDA0 /* MediumSizeView.swift */; }; + 5CE387342763C6A30045EDA0 /* LargeSizeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE387332763C6A30045EDA0 /* LargeSizeView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -64,6 +66,8 @@ 5CA9F7CA275E586200EAA6D2 /* Provider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Provider.swift; sourceTree = ""; }; 5CA9F7CC275E588B00EAA6D2 /* SimpleEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleEntry.swift; sourceTree = ""; }; 5CA9F7CE275E58A100EAA6D2 /* WidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetView.swift; sourceTree = ""; }; + 5CE387312763C69A0045EDA0 /* MediumSizeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediumSizeView.swift; sourceTree = ""; }; + 5CE387332763C6A30045EDA0 /* LargeSizeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeSizeView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -154,8 +158,8 @@ 5CA9F7BD275E56D600EAA6D2 /* WidgetKitCourse Widget */ = { isa = PBXGroup; children = ( + 5CE387352763C6AA0045EDA0 /* Views */, 5CA9F7BE275E56D600EAA6D2 /* WidgetKitCourse_Widget.swift */, - 5CA9F7CE275E58A100EAA6D2 /* WidgetView.swift */, 5CA9F7C0275E56D700EAA6D2 /* Assets.xcassets */, 5CA9F7C2275E56D700EAA6D2 /* Info.plist */, 5CA9F7CA275E586200EAA6D2 /* Provider.swift */, @@ -164,6 +168,16 @@ path = "WidgetKitCourse Widget"; sourceTree = ""; }; + 5CE387352763C6AA0045EDA0 /* Views */ = { + isa = PBXGroup; + children = ( + 5CA9F7CE275E58A100EAA6D2 /* WidgetView.swift */, + 5CE387332763C6A30045EDA0 /* LargeSizeView.swift */, + 5CE387312763C69A0045EDA0 /* MediumSizeView.swift */, + ); + path = Views; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -278,6 +292,8 @@ files = ( 5CA9F7CD275E588B00EAA6D2 /* SimpleEntry.swift in Sources */, 5CA9F7CB275E586200EAA6D2 /* Provider.swift in Sources */, + 5CE387322763C69A0045EDA0 /* MediumSizeView.swift in Sources */, + 5CE387342763C6A30045EDA0 /* LargeSizeView.swift in Sources */, 5CA9F7CF275E58A100EAA6D2 /* WidgetView.swift in Sources */, 5CA9F7BF275E56D600EAA6D2 /* WidgetKitCourse_Widget.swift in Sources */, ); diff --git a/WidgetKitCourse.xcodeproj/xcuserdata/flo.xcuserdatad/xcschemes/xcschememanagement.plist b/WidgetKitCourse.xcodeproj/xcuserdata/flo.xcuserdatad/xcschemes/xcschememanagement.plist index bb7fe00..9732e2e 100644 --- a/WidgetKitCourse.xcodeproj/xcuserdata/flo.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/WidgetKitCourse.xcodeproj/xcuserdata/flo.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ WidgetKitCourse WidgetExtension.xcscheme_^#shared#^_ orderHint - 0 + 1 WidgetKitCourse.xcscheme_^#shared#^_ orderHint - 1 + 0 diff --git a/WidgetKitCourse/Feature Targets/ContentView.swift b/WidgetKitCourse/Feature Targets/ContentView.swift index 2228382..b7232d5 100644 --- a/WidgetKitCourse/Feature Targets/ContentView.swift +++ b/WidgetKitCourse/Feature Targets/ContentView.swift @@ -43,6 +43,28 @@ struct ContentView: View { } .padding() } + .onOpenURL { url in + guard + url.scheme == "myapp", + url.host == "todo", + let id = Int(url.pathComponents[1]) + else { + print("issue") + return + } + + Task { + do { + let todo = try await TodoService.shared.getTodo(with: id) + DispatchQueue.main.async { + selectedTodo = todo + } + } catch { + // handle error in an adequate way + print(error) + } + } + } } } }