Adds Widgets.md

This commit is contained in:
Stuart Breckenridge 2020-11-18 13:42:32 +08:00
parent 58e18f4bcb
commit a3135da6a8
2 changed files with 62 additions and 11 deletions

View File

@ -38,7 +38,7 @@
176813F52564BB2C00D98635 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 176813F42564BB2C00D98635 /* WidgetKit.framework */; };
176813F72564BB2C00D98635 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 176813F62564BB2C00D98635 /* SwiftUI.framework */; };
176813FC2564BB2D00D98635 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 176813FB2564BB2D00D98635 /* Assets.xcassets */; };
176814002564BB2D00D98635 /* NetNewsWire Widget Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 176813F32564BB2C00D98635 /* NetNewsWire Widget Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
176814002564BB2D00D98635 /* NetNewsWire iOS Widget Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 176813F32564BB2C00D98635 /* NetNewsWire iOS Widget Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
1768140B2564BB8300D98635 /* NetNewsWire_iOSwidgetextension_target.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 1768140A2564BB8300D98635 /* NetNewsWire_iOSwidgetextension_target.xcconfig */; };
176814132564BC8A00D98635 /* WidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 176814122564BC8A00D98635 /* WidgetBundle.swift */; };
1768142D2564BCA800D98635 /* TimelineProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1768142C2564BCA800D98635 /* TimelineProvider.swift */; };
@ -1334,7 +1334,7 @@
dstSubfolderSpec = 13;
files = (
513C5CF0232571C2003D4054 /* NetNewsWire iOS Share Extension.appex in Embed App Extensions */,
176814002564BB2D00D98635 /* NetNewsWire Widget Extension.appex in Embed App Extensions */,
176814002564BB2D00D98635 /* NetNewsWire iOS Widget Extension.appex in Embed App Extensions */,
5131463E235A7BBE00387FDC /* NetNewsWire iOS Intents Extension.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
@ -1490,7 +1490,7 @@
176813BD2564BA2800D98635 /* WidgetDataEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetDataEncoder.swift; sourceTree = "<group>"; };
176813C92564BA5400D98635 /* WidgetDataDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetDataDecoder.swift; sourceTree = "<group>"; };
176813D82564BA8700D98635 /* WidgetDeepLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetDeepLinks.swift; sourceTree = "<group>"; };
176813F32564BB2C00D98635 /* NetNewsWire Widget Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "NetNewsWire Widget Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
176813F32564BB2C00D98635 /* NetNewsWire iOS Widget Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "NetNewsWire iOS Widget Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
176813F42564BB2C00D98635 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
176813F62564BB2C00D98635 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
176813FB2564BB2D00D98635 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@ -3340,7 +3340,7 @@
51C0513D24A77DF800194D5E /* NetNewsWire.app */,
51C0514424A77DF800194D5E /* NetNewsWire.app */,
510C415C24E5CDE3008226FD /* NetNewsWire Share Extension.appex */,
176813F32564BB2C00D98635 /* NetNewsWire Widget Extension.appex */,
176813F32564BB2C00D98635 /* NetNewsWire iOS Widget Extension.appex */,
);
name = Products;
sourceTree = "<group>";
@ -3686,9 +3686,9 @@
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
176813F22564BB2C00D98635 /* NetNewsWire Widget Extension */ = {
176813F22564BB2C00D98635 /* NetNewsWire iOS Widget Extension */ = {
isa = PBXNativeTarget;
buildConfigurationList = 176814012564BB2D00D98635 /* Build configuration list for PBXNativeTarget "NetNewsWire Widget Extension" */;
buildConfigurationList = 176814012564BB2D00D98635 /* Build configuration list for PBXNativeTarget "NetNewsWire iOS Widget Extension" */;
buildPhases = (
176813EF2564BB2C00D98635 /* Sources */,
176813F02564BB2C00D98635 /* Frameworks */,
@ -3698,9 +3698,9 @@
);
dependencies = (
);
name = "NetNewsWire Widget Extension";
name = "NetNewsWire iOS Widget Extension";
productName = "NetNewsWire WidgetExtension";
productReference = 176813F32564BB2C00D98635 /* NetNewsWire Widget Extension.appex */;
productReference = 176813F32564BB2C00D98635 /* NetNewsWire iOS Widget Extension.appex */;
productType = "com.apple.product-type.app-extension";
};
510C415B24E5CDE3008226FD /* NetNewsWire Share Extension */ = {
@ -4101,11 +4101,11 @@
65ED4090235DEF770081F399 /* Subscribe to Feed MAS */,
513C5CE5232571C2003D4054 /* NetNewsWire iOS Share Extension */,
51314636235A7BBE00387FDC /* NetNewsWire iOS Intents Extension */,
176813F22564BB2C00D98635 /* NetNewsWire iOS Widget Extension */,
518B2ED12351B3DD00400001 /* NetNewsWire-iOSTests */,
51C0513C24A77DF800194D5E /* Multiplatform iOS */,
51C0514324A77DF800194D5E /* Multiplatform macOS */,
510C415B24E5CDE3008226FD /* NetNewsWire Share Extension */,
176813F22564BB2C00D98635 /* NetNewsWire Widget Extension */,
);
};
/* End PBXProject section */
@ -5535,7 +5535,7 @@
/* Begin PBXTargetDependency section */
176813FF2564BB2D00D98635 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 176813F22564BB2C00D98635 /* NetNewsWire Widget Extension */;
target = 176813F22564BB2C00D98635 /* NetNewsWire iOS Widget Extension */;
targetProxy = 176813FE2564BB2D00D98635 /* PBXContainerItemProxy */;
};
510C416824E5CDE3008226FD /* PBXTargetDependency */ = {
@ -6062,7 +6062,7 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
176814012564BB2D00D98635 /* Build configuration list for PBXNativeTarget "NetNewsWire Widget Extension" */ = {
176814012564BB2D00D98635 /* Build configuration list for PBXNativeTarget "NetNewsWire iOS Widget Extension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
176814022564BB2D00D98635 /* Debug */,

51
Technotes/Widgets.md Normal file
View File

@ -0,0 +1,51 @@
# Widgets on iOS
There are _currently_ four widgets available for iOS:
- 1x small widget that displays the current count of each of the Smart Feeds.
- 3x medium widgets—one for each of the smart feeds.
## Widget Data
The widget does not have access to the parent app's database. To surface data to the widget, a small amount of article data is encoded to JSON (see `WidgetDataEncoder`) and saved to the AppGroup container.
Widget data is written at three points:
1. After applicationDidFinishLaunching
2. As part of a background refresh
3. When the scene enters the background
The widget timeline is refreshed—via `WidgetCenter.shared.reloadAllTimelines()`—after each of the above.
## Deep Links
The medium widgets support deep links for each of the articles that are surfaced.
If the user taps on an unread article in the unread widget, the widget opens the parent app with a deep link URL (see `WidgetDeepLink`), for example: `nnw://showunread?id={articeID}`. Once the app is opened, `scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>)` is called and is then determined what should be presented to the user. If there is no `id` parameter, the relevant smart feed controller is displayed.
## Data Models
```swift
struct WidgetData: Codable {
let currentUnreadCount: Int
let currentTodayCount: Int
let currentStarredCount: Int
let unreadArticles: [LatestArticle]
let starredArticles: [LatestArticle]
let todayArticles: [LatestArticle]
let lastUpdateTime: Date
}
struct LatestArticle: Codable, Identifiable {
var id: String // articleID
let feedTitle: String
let articleTitle: String?
let articleSummary: String?
let feedIcon: Data? // Base64 encoded image
let pubDate: String
}
```