-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Fix "Please adopt containerBackgroundAPI" for iOS 17 Widgets #21705
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
Changes from all commits
aa6e017
dfaf4e8
478e075
5aab0b7
190578f
3356e3d
94fc839
bb41a62
a1d932f
b02d1a3
7130ef2
42c03e8
ca4673e
1e80d49
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,9 +31,11 @@ struct LockScreenMultiStatView: View { | |
| Spacer() | ||
| } | ||
| } | ||
| .removableWidgetBackground() | ||
| .accessibilityElement(children: .combine) | ||
| } else { | ||
| Text("Not implemented for widget family \(family.debugDescription)") | ||
| .removableWidgetBackground() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just curious about the Swift UI architecture, which is not my strong suit. Would it have been possible to group the conditional logic, e.g. in an
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question. I think it would be possible 👍 |
||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import SwiftUI | ||
|
|
||
| /// A card with a title and a string value that is shown on LockScreen without background | ||
| struct LockScreenFlexibleCard: View { | ||
| let title: LocalizedString | ||
| let description: LocalizedString | ||
| let lineLimit: Int | ||
|
|
||
| init(title: LocalizedString, description: LocalizedString, lineLimit: Int = 1) { | ||
| self.title = title | ||
| self.description = description | ||
| self.lineLimit = lineLimit | ||
| } | ||
|
|
||
| var body: some View { | ||
| VStack(alignment: .leading) { | ||
| HStack(alignment: .firstTextBaseline, spacing: 4) { | ||
| Image("icon-jetpack") | ||
| .resizable() | ||
| .frame(width: 14, height: 14) | ||
| Text(description) | ||
| .font(Appearance.textFont) | ||
| .fontWeight(Appearance.textFontWeight) | ||
| .foregroundColor(Appearance.textColor) | ||
| .lineLimit(lineLimit) | ||
| } | ||
| Text(title) | ||
| .font(Appearance.titleFont) | ||
| .foregroundColor(Appearance.titleColor) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // MARK: - Appearance | ||
| extension LockScreenFlexibleCard { | ||
| private enum Appearance { | ||
| static let textFont = Font.headline | ||
| static let textFontWeight = Font.Weight.semibold | ||
| static let textColor = Color(.label) | ||
|
|
||
| static let titleFont = Font.subheadline | ||
| static let titleColor = Color(.secondaryLabel) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import SwiftUI | ||
|
|
||
| /// A card with a title and a value stacked vertically shown on LockScreen without background | ||
| struct LockScreenVerticalCard: View { | ||
| let title: LocalizedString | ||
| let value: Int | ||
|
|
||
| private var accessibilityLabel: Text { | ||
| // The colon makes VoiceOver pause between elements | ||
| Text(title) + Text(": ") + Text(value.abbreviatedString()) | ||
| } | ||
|
|
||
| var body: some View { | ||
| VStack(alignment: .leading) { | ||
| StatsValueView(value: value, | ||
| font: Appearance.extraLargeTextFont, | ||
| fontWeight: .heavy, | ||
| foregroundColor: Appearance.textColor, | ||
| lineLimit: nil) | ||
| .accessibility(label: accessibilityLabel) | ||
| Text(title) | ||
| .font(Appearance.titleFont) | ||
| .fontWeight(Appearance.titleFontWeight) | ||
| .foregroundColor(Appearance.titleColor) | ||
| .accessibility(hidden: true) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // MARK: - Appearance | ||
| extension LockScreenVerticalCard { | ||
| private enum Appearance { | ||
| static let titleFont = Font.headline | ||
| static let titleFontWeight = Font.Weight.semibold | ||
| static let titleColor = Color(UIColor.label) | ||
| static let extraLargeTextFont = Font.system(size: 48, weight: .bold) | ||
| static let textColor = Color(UIColor.label) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,5 +30,6 @@ struct StatsValueView: View { | |
| .fontWeight(fontWeight) | ||
| .foregroundColor(foregroundColor) | ||
| .lineLimit(lineLimit) | ||
| .minimumScaleFactor(0.5) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why 0.5?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 0.5 is an arbitrary value, could be smaller or a bit larget as well. Previously created rectangular widgets can now appear without a background on iPadOS Horizontal Lock Screen. Since they appear without a background, I increased font sizes to have less space and resemble the look of other widgets without a background. However, when numbers become large, I want font to Value font to shrink, to be fully displayed. |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import SwiftUI | ||
| import WidgetKit | ||
|
|
||
| extension View { | ||
| func removableWidgetBackground(_ backgroundView: some View = EmptyView()) -> some View { | ||
| if #available(iOSApplicationExtension 17.0, *) { | ||
| return containerBackground(for: .widget) { | ||
| backgroundView | ||
| } | ||
| } else { | ||
| return background(backgroundView) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| extension WidgetConfiguration { | ||
| func iOS17ContentMarginsDisabled() -> some WidgetConfiguration { | ||
| if #available(iOSApplicationExtension 17.0, *) { | ||
| return contentMarginsDisabled() | ||
| } else { | ||
| return self | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,6 +34,7 @@ struct ListStatsView: View { | |
| } | ||
| } | ||
| } | ||
| .removableWidgetBackground() | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,19 +1,59 @@ | ||
| import SwiftUI | ||
| import WidgetKit | ||
|
|
||
| struct SingleStatView: View { | ||
| let title: String | ||
| let description: String | ||
| let valueTitle: String | ||
| let value: Int | ||
|
|
||
| let viewData: GroupedViewData | ||
| @Environment(\.showsWidgetContainerBackground) var showsWidgetContainerBackground: Bool | ||
|
|
||
| init(viewData: GroupedViewData) { | ||
| self.title = viewData.widgetTitle | ||
| self.description = viewData.siteName | ||
| self.valueTitle = viewData.upperLeftTitle | ||
| self.value = viewData.upperLeftValue | ||
| } | ||
|
Comment on lines
+12
to
+17
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you consider delegating to
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good observation. I'll use |
||
|
|
||
| init(title: String, description: String, valueTitle: String, value: Int) { | ||
| self.title = title | ||
| self.description = description | ||
| self.valueTitle = valueTitle | ||
| self.value = value | ||
| } | ||
|
|
||
|
|
||
| var body: some View { | ||
| HStack { | ||
| VStack(alignment: .leading) { | ||
| FlexibleCard(axis: .vertical, title: viewData.widgetTitle, value: .description(viewData.siteName), lineLimit: 2) | ||
|
|
||
| Spacer() | ||
| VerticalCard(title: viewData.upperLeftTitle, value: viewData.upperLeftValue, largeText: true) | ||
| if showsWidgetContainerBackground { | ||
| VStack(alignment: .leading) { | ||
| FlexibleCard(axis: .vertical, title: title, value: .description(description), lineLimit: 2) | ||
| Spacer() | ||
| VerticalCard(title: valueTitle, value: value, largeText: true) | ||
| } | ||
| .padding() | ||
| } else { | ||
| VStack(alignment: .leading) { | ||
| Spacer() | ||
| LockScreenFlexibleCard(title: title, description: description, lineLimit: 2) | ||
| Spacer().frame(height: 4) | ||
| LockScreenVerticalCard(title: valueTitle, value: value) | ||
| Spacer() | ||
| } | ||
| } | ||
| Spacer() | ||
| } | ||
| .removableWidgetBackground() | ||
| } | ||
| } | ||
|
|
||
| @available(iOS 16.0, *) | ||
| struct SingleStatView_Previews: PreviewProvider { | ||
| static var previews: some View { | ||
| SingleStatView(title: "Today", description: "My WordPress Site", valueTitle: "Views", value: 124909) | ||
| .previewContext( | ||
| WidgetPreviewContext(family: .systemSmall) | ||
| ) | ||
| } | ||
| } | ||


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.
Super nitpick,
///is a documentation comment, as opposed to the standard//. With///Xcode and other tools will render the comment as documentation reading tags and markdown. However, the comment needs to be on a type or method declaration. We don't need to "document" method calls. I just wanted to point it out but I don't expect this to be addressed. 👍 😄