-
-
Notifications
You must be signed in to change notification settings - Fork 385
iOS Blog Feed Widget #2834
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
r3econ
wants to merge
64
commits into
lichess-org:main
Choose a base branch
from
r3econ:ios-lichess-blog-feed-widget
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
iOS Blog Feed Widget #2834
Changes from all commits
Commits
Show all changes
64 commits
Select commit
Hold shift + click to select a range
4e87a76
Add Lichess dummy widget
r3econ 8e65783
Add FeedKit dependency to the iOS widget target
r3econ f10db6c
Replace dummy content with real data
r3econ 31cb26c
Fetch and show more items
r3econ af07476
Fix the daily feed
r3econ a985d74
Add image fetching
r3econ 1e6cacf
Tweak the max number of posts
r3econ 9f03429
Add logo
r3econ 5ef327b
Refactor
r3econ 16b3376
Wrap the title
r3econ d932dbb
Tweak the design
r3econ 5b6a536
Add URL to the blog items that trigger a deeplink
r3econ f429656
Handle deeplink in the app
r3econ 4a86240
Add readme
r3econ 3f198c7
Simplify logic
r3econ aa64426
Improve the design
r3econ 505fcbe
Rename the widget
r3econ 461632d
Add user widgets
r3econ 3f93af1
Tweak the design
r3econ be83a36
Make the content scale base on available space
r3econ 7fef951
Fix the font sizes
r3econ e5ee514
Remove previews
r3econ 7181bad
Update the placeholder logic
r3econ 4fd1a69
Fix problem with the small widget
r3econ af6f649
Remove image from the small widget
r3econ 5c2aac4
Bottom align the publication date
r3econ aa30674
Fix image sizing bug
r3econ 4c1119f
Refactor
r3econ a23b2bb
Update placeholder
r3econ c9183af
Refactor
r3econ f2788d0
Improve architecture
r3econ 37cf871
Simplify code
r3econ eeb5c91
Merge branch 'main' of https://github.com/r3econ/mobile into ios-lich…
r3econ 176ea91
Reorganize folder structure
r3econ a4c5a7e
Simplify placeholders
r3econ 4950581
Update placeholder names
r3econ 5dc1d76
Remove news feed
r3econ ecf6e44
Add readme to the project
r3econ 89c0cd7
Update project file
r3econ f2d512d
Remove not needed URL
r3econ 52b8024
Show author in the community feed
r3econ c98af98
Improve date formatting
r3econ dedbb56
Extract date logic into an extension
r3econ a03ea42
Format
r3econ 6e315b6
Fix deprecation warning
r3econ 4328d47
Fix filenames
r3econ 9cd6be6
Introduce kLichessUriScheme
r3econ efbd89e
Separate blog widget into 3 distinct widgets
r3econ b1fc597
Add test scheme
r3econ 2a4cd29
Update placeholder logic
r3econ a44bb90
Add placeholder images
r3econ c1214c4
Update placeholder content
r3econ b2d4893
Update widget order
r3econ ed5dadd
Rename
r3econ 928cc27
Refactor
r3econ d244d94
Simplify feed fetching
r3econ 5f9adc4
Fix warning
r3econ cdb6f12
Extract layout constants
r3econ 34c0e00
Improve error layout
r3econ f5ceab6
Update formatting
r3econ 3325e52
Update extension readme
r3econ 191d621
Add widget identifier to matchfile and fastfile
r3econ daba1a0
Update extension readme
r3econ 69ff30e
Merge branch 'main' into ios-lichess-blog-feed-widget
r3econ File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| # iOS Extensions | ||
|
|
||
| ## Building extensions as a contributor | ||
|
|
||
| Each iOS app extension (e.g. the Lichess widgets) is a separate Xcode target with its own bundle ID. For the extension to be installed on a device, that bundle ID must be registered in the Lichess Apple Developer account with a matching provisioning profile. | ||
|
|
||
| As an external contributor you won't have access to that account, so `flutter run` will silently drop the extension from the bundle — you can add the app to your home screen but the widget won't appear in the widget catalog. | ||
|
|
||
| ### Testing locally | ||
|
|
||
| You can still build and test extensions using your own Apple Developer account and iOS Simulator. A free account is enough for device testing. | ||
|
|
||
| 1. Open `ios/Runner.xcworkspace` in Xcode. | ||
| 2. Select the **Runner** target → **Signing & Capabilities** → set **Team** to your account and change the bundle ID to something you own (e.g. `com.yourname.lichess`). | ||
| 3. Do the same for the extension target (e.g. **LichessWidgetsExtension**), using a matching sub-ID (e.g. `com.yourname.lichess.widget`). | ||
| 4. Build and run from Xcode — the extension will be signed with your profile and work on your device. | ||
|
|
||
| These changes are local only and should not be committed. | ||
|
|
||
| ### Merging new extensions | ||
|
|
||
| When a PR that adds a new extension is ready to merge, a Lichess org member with Apple Developer access needs to: | ||
|
|
||
| 1. Register the new App ID (for the extension's bundle ID) in the Apple Developer portal. | ||
| 2. Create a provisioning profile for it. | ||
|
|
||
| ## Deploying extensions via fastlane | ||
|
|
||
| Extensions have their own bundle ID (`org.lichess.mobileV2.<ExtensionName>`) and require a separate provisioning profile managed by `match`. The `Matchfile` and `Fastfile` list all extension bundle IDs alongside the main app. | ||
|
|
||
| ### Adding a new extension to the fastlane setup | ||
|
|
||
| After registering the App ID in the developer portal (see above), run `match` once to create and store the provisioning profile: | ||
|
|
||
| ```sh | ||
| cd ios | ||
| bundle exec fastlane match appstore --app_identifier org.lichess.mobileV2.<ExtensionName> | ||
| ``` | ||
|
|
||
| This will generate the profile, push it to the certificates repo, and set the correct `PROVISIONING_PROFILE_SPECIFIER` in the Xcode project. After that, `fastlane beta` handles signing for all targets automatically — including in CI. | ||
|
|
||
| Also add the new bundle ID to both `app_identifier` arrays in `fastlane/Matchfile` and the `sync_code_signing` call in `fastlane/Fastfile`. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| import FeedKit | ||
| import UIKit | ||
| import WidgetKit | ||
| internal import XMLKit | ||
|
|
||
| struct BlogFeedFetcher { | ||
| static var nextUpdateDate: Date { | ||
| Calendar.current.date(byAdding: .hour, value: 1, to: .now)! | ||
| } | ||
|
|
||
| private func fetchThumbnail(urlString: String, spec: BlogThumbnailSpec) async -> Data? { | ||
| guard let url = URL(string: urlString), | ||
| let (data, _) = try? await URLSession.shared.data(from: url), | ||
| let source = UIImage(data: data) | ||
| else { return nil } | ||
| let scale = UITraitCollection.current.displayScale | ||
| let size = CGSize(width: spec.width * scale, height: spec.height * scale) | ||
| return await source.byPreparingThumbnail(ofSize: size)?.jpegData(compressionQuality: 0.85) | ||
| } | ||
|
|
||
| func fetchEntry(feed: BlogFeedChoice, username: String?, family: WidgetFamily) async -> BlogFeedEntry { | ||
| let (items, error) = await fetchFeed(feed: feed, username: username, family: family) | ||
| return BlogFeedEntry(date: .now, feed: feed, username: username, items: items, error: error) | ||
| } | ||
|
|
||
| private func fetchFeed(feed: BlogFeedChoice, | ||
| username: String?, | ||
| family: WidgetFamily) async -> (items: [BlogFeedItem], error: String?) { | ||
| guard let urlString = feed.feedURL(username: username) else { | ||
| return ([], "Enter a username in widget settings") | ||
| } | ||
| do { | ||
| guard case .atom(let atomFeed) = try await Feed(urlString: urlString) else { | ||
| return ([], "Unexpected feed format") | ||
| } | ||
| let thumbSpec = family.thumbnailSpec | ||
| let items = await withTaskGroup(of: (Int, BlogFeedItem).self) { group in | ||
| for (index, entry) in (atomFeed.entries ?? []).prefix(family.maxItems).enumerated() { | ||
| group.addTask { | ||
| let thumbData: Data? = if let thumbSpec, | ||
| let thumbURL = entry.media?.thumbnails?.first?.attributes?.url { | ||
| await fetchThumbnail(urlString: thumbURL, spec: thumbSpec) | ||
| } else { | ||
| nil | ||
| } | ||
| let entryURL = entry.links? | ||
| .first(where: { $0.attributes?.rel == "alternate" })? | ||
| .attributes?.href | ||
| ?? entry.links?.first?.attributes?.href | ||
| return (index, BlogFeedItem( | ||
| id: entry.id ?? "\(index)", | ||
| title: entry.title ?? "Untitled", | ||
| url: entryURL, | ||
| publishedDate: entry.published, | ||
| author: entry.authors?.first?.name, | ||
| thumbnailData: thumbData, | ||
| thumbnailImageName: nil | ||
| )) | ||
| } | ||
| } | ||
| var results: [(Int, BlogFeedItem)] = [] | ||
| for await result in group { results.append(result) } | ||
| return results.sorted { $0.0 < $1.0 }.map(\.1) | ||
| } | ||
| return (items, nil) | ||
| } catch { | ||
| return ([], error.localizedDescription) | ||
| } | ||
| } | ||
| } |
121 changes: 121 additions & 0 deletions
121
ios/LichessWidgets/Blog Feed Widget/BlogFeedPlaceholder.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| import Foundation | ||
| import WidgetKit | ||
|
|
||
| /// Static placeholder data shown in the widget gallery and while a widget loads. | ||
| enum BlogFeedPlaceholder { | ||
| static func entry(feed: BlogFeedChoice, username: String? = nil, family: WidgetFamily) -> BlogFeedEntry { | ||
| BlogFeedEntry( | ||
| date: .now, | ||
| feed: feed, | ||
| username: username, | ||
| items: Array(items(for: feed).prefix(family.maxItems)), | ||
| error: nil | ||
| ) | ||
| } | ||
|
|
||
| private static func items(for feed: BlogFeedChoice) -> [BlogFeedItem] { | ||
| switch feed { | ||
| case .officialBlog: return officialBlogItems | ||
| case .communityBlog: return communityBlogItems | ||
| case .userBlog: return userBlogItems | ||
| } | ||
| } | ||
|
|
||
| // MARK: Official Blog | ||
|
|
||
| private static let officialBlogItems: [BlogFeedItem] = [ | ||
| BlogFeedItem(id: "1", | ||
| title: "Lichess Mobile App Update", | ||
| url: nil, | ||
| publishedDate: daysAgo(1), | ||
| author: nil, | ||
| thumbnailData: nil, | ||
| thumbnailImageName: "OfficialBlogPlaceholderImage1"), | ||
| BlogFeedItem(id: "2", | ||
| title: "Queens' Online Chess Festival", | ||
| url: nil, | ||
| publishedDate: daysAgo(31), | ||
| author: nil, | ||
| thumbnailData: nil, | ||
| thumbnailImageName: "OfficialBlogPlaceholderImage2"), | ||
| BlogFeedItem(id: "3", | ||
| title: "Announcing the ChessMood 20/20 Grand Prix 2026", | ||
| url: nil, | ||
| publishedDate: daysAgo(35), | ||
| author: nil, | ||
| thumbnailData: nil, | ||
| thumbnailImageName: "OfficialBlogPlaceholderImage3"), | ||
| BlogFeedItem(id: "4", | ||
| title: "Streamer Arenas Announcement — February to July 2026", | ||
| url: nil, | ||
| publishedDate: daysAgo(39), | ||
| author: nil, | ||
| thumbnailData: nil, | ||
| thumbnailImageName: "OfficialBlogPlaceholderImage4"), | ||
| ] | ||
|
|
||
| // MARK: Community Blog | ||
|
|
||
| private static let communityBlogItems: [BlogFeedItem] = [ | ||
| BlogFeedItem(id: "1", | ||
| title: "How To Analyse Your Game Like a 2000-Rated Player", | ||
| url: nil, | ||
| publishedDate: daysAgo(0), | ||
| author: "VihaanRathodBhuj", | ||
| thumbnailData: nil, | ||
| thumbnailImageName: "CommunityBlogPlaceholderImage1"), | ||
| BlogFeedItem(id: "2", | ||
| title: "What a Figure Skater Can Teach You About Chess Improvement", | ||
| url: nil, | ||
| publishedDate: daysAgo(0), | ||
| author: "FM MattyDPerrine", | ||
| thumbnailData: nil, | ||
| thumbnailImageName: "CommunityBlogPlaceholderImage2"), | ||
| BlogFeedItem(id: "3", title: "Slow Growth in Chess: The Truth Most People Don't Want to Hear", | ||
| url: nil, publishedDate: daysAgo(2), | ||
| author: "IM nikhildixit", | ||
| thumbnailData: nil, | ||
| thumbnailImageName: "CommunityBlogPlaceholderImage3"), | ||
| BlogFeedItem(id: "4", title: "Everyone's favorite: A modern Kortchnoi seeking to change his history", | ||
| url: nil, | ||
| publishedDate: daysAgo(0), | ||
| author: "FM Reynold9402", | ||
| thumbnailData: nil, | ||
| thumbnailImageName: "CommunityBlogPlaceholderImage4"), | ||
| ] | ||
|
|
||
| // MARK: User Blog | ||
|
|
||
| private static let userBlogItems: [BlogFeedItem] = [ | ||
| BlogFeedItem(id: "1", | ||
| title: "Did you know Lichess can do this? Opening Explorer and Tablebase", | ||
| url: nil, | ||
| publishedDate: daysAgo(2), | ||
| author: nil, | ||
| thumbnailData: nil, | ||
| thumbnailImageName: "UserBlogPlaceholderImage1"), | ||
| BlogFeedItem(id: "2", | ||
| title: "Annotated: Sicilian Accelerated Dragon Deep Dive", | ||
| url: nil, | ||
| publishedDate: daysAgo(7), | ||
| author: nil, | ||
| thumbnailData: nil, thumbnailImageName: "UserBlogPlaceholderImage2"), | ||
| BlogFeedItem(id: "3", | ||
| title: "Tournament Report: City Open 2026", | ||
| url: nil, | ||
| publishedDate: daysAgo(14), | ||
| author: nil, | ||
| thumbnailData: nil, thumbnailImageName: "UserBlogPlaceholderImage3"), | ||
| BlogFeedItem(id: "4", | ||
| title: "Endgame Studies I Recommend", | ||
| url: nil, | ||
| publishedDate: daysAgo(21), | ||
| author: nil, | ||
| thumbnailData: nil, | ||
| thumbnailImageName: "UserBlogPlaceholderImage4"), | ||
| ] | ||
|
|
||
| private static func daysAgo(_ days: Int) -> Date? { | ||
| Calendar.current.date(byAdding: .day, value: -days, to: .now) | ||
| } | ||
| } |
17 changes: 17 additions & 0 deletions
17
ios/LichessWidgets/Blog Feed Widget/CommunityBlogWidget.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import SwiftUI | ||
| import WidgetKit | ||
|
|
||
| struct CommunityBlogWidget: Widget { | ||
| let kind = "CommunityBlogWidget" | ||
|
|
||
| var body: some WidgetConfiguration { | ||
| StaticConfiguration(kind: kind, | ||
| provider: GenericBlogFeedProvider(feed: .communityBlog)) { entry in | ||
| BlogFeedWidgetEntryView(entry: entry) | ||
| .containerBackground(.background, for: .widget) | ||
| } | ||
| .configurationDisplayName("Community Blog") | ||
| .description("Latest posts from the Lichess community blog.") | ||
| .supportedFamilies([.systemSmall, .systemMedium, .systemLarge]) | ||
| } | ||
| } |
30 changes: 30 additions & 0 deletions
30
ios/LichessWidgets/Blog Feed Widget/GenericBlogFeedProvider.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import SwiftUI | ||
| import WidgetKit | ||
|
|
||
| struct GenericBlogFeedProvider: TimelineProvider { | ||
| let feed: BlogFeedChoice | ||
| private let fetcher = BlogFeedFetcher() | ||
|
|
||
| func placeholder(in context: Context) -> BlogFeedEntry { | ||
| BlogFeedPlaceholder.entry(feed: feed, family: context.family) | ||
| } | ||
|
|
||
| func getSnapshot(in context: Context, completion: @escaping (BlogFeedEntry) -> Void) { | ||
| if context.isPreview { completion(placeholder(in: context)); return } | ||
| Task { | ||
| completion(await fetcher.fetchEntry(feed: feed, | ||
| username: nil, | ||
| family: context.family)) | ||
| } | ||
| } | ||
|
|
||
| func getTimeline(in context: Context, completion: @escaping (Timeline<BlogFeedEntry>) -> Void) { | ||
| Task { | ||
| let entry = await fetcher.fetchEntry(feed: feed, | ||
| username: nil, | ||
| family: context.family) | ||
| let nextUpdate = BlogFeedFetcher.nextUpdateDate | ||
| completion(Timeline(entries: [entry], policy: .after(nextUpdate))) | ||
| } | ||
| } | ||
| } |
25 changes: 25 additions & 0 deletions
25
ios/LichessWidgets/Blog Feed Widget/Model/BlogFeedChoice.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| import Foundation | ||
|
|
||
| enum BlogFeedChoice: String { | ||
| case officialBlog | ||
| case communityBlog | ||
| case userBlog | ||
|
|
||
| var displayName: String { | ||
| switch self { | ||
| case .officialBlog: return "Official Blog" | ||
| case .communityBlog: return "Community Blog" | ||
| case .userBlog: return "User Blog" | ||
| } | ||
| } | ||
|
|
||
| func feedURL(username: String?) -> String? { | ||
| switch self { | ||
| case .officialBlog: return "https://lichess.org/@/Lichess/blog.atom" | ||
| case .communityBlog: return "https://lichess.org/blog/community.atom" | ||
| case .userBlog: | ||
| guard let username, !username.isEmpty else { return nil } | ||
| return "https://lichess.org/@/\(username)/blog.atom" | ||
| } | ||
| } | ||
| } |
17 changes: 17 additions & 0 deletions
17
ios/LichessWidgets/Blog Feed Widget/Model/BlogFeedEntry.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import WidgetKit | ||
|
|
||
| struct BlogFeedEntry: TimelineEntry { | ||
| let date: Date | ||
| let feed: BlogFeedChoice | ||
| let username: String? | ||
| let items: [BlogFeedItem] | ||
| let error: String? | ||
|
|
||
| /// Display name for the widget header. | ||
| var headerTitle: String { | ||
| if feed == .userBlog, let username, !username.isEmpty { | ||
| return "@\(username)" | ||
| } | ||
| return feed.displayName | ||
| } | ||
| } |
12 changes: 12 additions & 0 deletions
12
ios/LichessWidgets/Blog Feed Widget/Model/BlogFeedItem.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| import Foundation | ||
|
|
||
| struct BlogFeedItem: Identifiable { | ||
| let id: String | ||
| let title: String | ||
| let url: String? | ||
| let publishedDate: Date? | ||
| let author: String? | ||
| let thumbnailData: Data? | ||
| /// Asset catalog image name, used for static placeholder items only. | ||
| let thumbnailImageName: String? | ||
| } |
7 changes: 7 additions & 0 deletions
7
ios/LichessWidgets/Blog Feed Widget/Model/BlogThumbnailSpec.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import Foundation | ||
|
|
||
| struct BlogThumbnailSpec { | ||
| let width: CGFloat | ||
| let aspectRatio: CGFloat // height = width * aspectRatio | ||
| var height: CGFloat { width * aspectRatio } | ||
| } |
17 changes: 17 additions & 0 deletions
17
ios/LichessWidgets/Blog Feed Widget/OfficialBlogWidget.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import SwiftUI | ||
| import WidgetKit | ||
|
|
||
| struct OfficialBlogWidget: Widget { | ||
| let kind = "OfficialBlogWidget" | ||
|
|
||
| var body: some WidgetConfiguration { | ||
| StaticConfiguration(kind: kind, | ||
| provider: GenericBlogFeedProvider(feed: .officialBlog)) { entry in | ||
| BlogFeedWidgetEntryView(entry: entry) | ||
| .containerBackground(.background, for: .widget) | ||
| } | ||
| .configurationDisplayName("Official Blog") | ||
| .description("Latest posts from the Lichess official blog.") | ||
| .supportedFamilies([.systemSmall, .systemMedium, .systemLarge]) | ||
| } | ||
| } |
24 changes: 24 additions & 0 deletions
24
ios/LichessWidgets/Blog Feed Widget/UserBlogFeedProvider.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import WidgetKit | ||
|
|
||
| struct UserBlogFeedProvider: AppIntentTimelineProvider { | ||
| private let fetcher = BlogFeedFetcher() | ||
|
|
||
| func placeholder(in context: Context) -> BlogFeedEntry { | ||
| BlogFeedPlaceholder.entry(feed: .userBlog, username: "ChessNoob2009", family: context.family) | ||
| } | ||
|
|
||
| func snapshot(for configuration: UserBlogFeedIntent, in context: Context) async -> BlogFeedEntry { | ||
| if context.isPreview { return placeholder(in: context) } | ||
| return await fetcher.fetchEntry(feed: .userBlog, | ||
| username: configuration.username, | ||
| family: context.family) | ||
| } | ||
|
|
||
| func timeline(for configuration: UserBlogFeedIntent, in context: Context) async -> Timeline<BlogFeedEntry> { | ||
| let entry = await fetcher.fetchEntry(feed: .userBlog, | ||
| username: configuration.username, | ||
| family: context.family) | ||
| let nextUpdate = BlogFeedFetcher.nextUpdateDate | ||
| return Timeline(entries: [entry], policy: .after(nextUpdate)) | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're using fastlane match for code signing in release mode in this project. It would be nice to update these instructions to take that into account.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, definitely. I added fastlane instructions in daba1a0. They might require some fine-tuning once you create a build and see how fastlane handles the new widget extension. Hopefully it works with no changes 🚀