Use the new layout for all the widget views.

This commit is contained in:
Brent Simmons
2024-12-26 17:11:38 -08:00
parent 1288160de5
commit fac18d61c7
6 changed files with 83 additions and 85 deletions

View File

@@ -289,6 +289,7 @@
843E2F1E2CF2B8D300ED170F /* RSWeb in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 843E2F1C2CF2B8D300ED170F /* RSWeb */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
84411E711FE5FBFA004B527F /* SmallIconProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84411E701FE5FBFA004B527F /* SmallIconProvider.swift */; };
8444C8F21FED81840051386C /* OPMLExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8444C8F11FED81840051386C /* OPMLExporter.swift */; };
8448F1E22D1E2DA30048BA50 /* WidgetLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8448F1E12D1E2DA30048BA50 /* WidgetLayout.swift */; };
844B5B591FE9FE4F00C7C76A /* SidebarKeyboardDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B5B581FE9FE4F00C7C76A /* SidebarKeyboardDelegate.swift */; };
844B5B5B1FEA00FB00C7C76A /* TimelineKeyboardDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B5B5A1FEA00FB00C7C76A /* TimelineKeyboardDelegate.swift */; };
844B5B651FEA11F200C7C76A /* GlobalKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 844B5B641FEA11F200C7C76A /* GlobalKeyboardShortcuts.plist */; };
@@ -793,6 +794,7 @@
843E2F152CF2B43700ED170F /* RSWeb */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = RSWeb; sourceTree = "<group>"; };
84411E701FE5FBFA004B527F /* SmallIconProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmallIconProvider.swift; sourceTree = "<group>"; };
8444C8F11FED81840051386C /* OPMLExporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OPMLExporter.swift; sourceTree = "<group>"; };
8448F1E12D1E2DA30048BA50 /* WidgetLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetLayout.swift; sourceTree = "<group>"; };
844B5B581FE9FE4F00C7C76A /* SidebarKeyboardDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarKeyboardDelegate.swift; sourceTree = "<group>"; };
844B5B5A1FEA00FB00C7C76A /* TimelineKeyboardDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineKeyboardDelegate.swift; sourceTree = "<group>"; };
844B5B641FEA11F200C7C76A /* GlobalKeyboardShortcuts.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = GlobalKeyboardShortcuts.plist; sourceTree = "<group>"; };
@@ -1136,6 +1138,7 @@
1768143D2564BCC800D98635 /* TodayWidget.swift */,
176814452564BCD200D98635 /* StarredWidget.swift */,
1768144D2564BCE000D98635 /* SmartFeedSummaryWidget.swift */,
8448F1E12D1E2DA30048BA50 /* WidgetLayout.swift */,
);
path = "Widget Views";
sourceTree = "<group>";
@@ -2561,6 +2564,7 @@
1768142D2564BCA800D98635 /* TimelineProvider.swift in Sources */,
1701E1E725689D1E009453D8 /* Localized.swift in Sources */,
176814652564BD7F00D98635 /* WidgetData.swift in Sources */,
8448F1E22D1E2DA30048BA50 /* WidgetLayout.swift in Sources */,
1768145E2564BD7B00D98635 /* WidgetDataDecoder.swift in Sources */,
176814132564BC8A00D98635 /* WidgetBundle.swift in Sources */,
17E0084625941887000C23F0 /* SizeCategories.swift in Sources */,

View File

@@ -22,7 +22,7 @@ struct ArticleItemView: View {
if iconImage != nil {
iconImage!
.resizable()
.frame(width: 24, height: 24)
.frame(width: WidgetLayout.feedIconSize, height: WidgetLayout.feedIconSize)
.cornerRadius(4)
}

View File

@@ -10,12 +10,12 @@ import WidgetKit
import SwiftUI
struct StarredWidgetView : View {
@Environment(\.widgetFamily) var family: WidgetFamily
@Environment(\.sizeCategory) var sizeCategory: ContentSizeCategory
var entry: Provider.Entry
var body: some View {
if entry.widgetData.starredArticles.count == 0 {
inboxZero
@@ -23,40 +23,28 @@ struct StarredWidgetView : View {
}
else {
GeometryReader { metrics in
HStack {
VStack {
starredImage
.padding(.vertical, 12)
.padding(.leading, 8)
Spacer()
}
}
.frame(width: metrics.size.width * 0.15)
Spacer()
starredImage
.frame(width: WidgetLayout.titleImageSize, alignment: .leading)
VStack(alignment:.leading, spacing: 0) {
ForEach(0..<maxCount(), id: \.self, content: { i in
if i != 0 {
Divider()
ArticleItemView(article: entry.widgetData.starredArticles[i],
deepLink: WidgetDeepLink.starredArticle(id: entry.widgetData.starredArticles[i].id).url)
.padding(.top, 8)
.padding(.bottom, 4)
.padding(.top, WidgetLayout.articleItemViewPaddingTop)
.padding(.bottom, WidgetLayout.articleItemViewPaddingBottom)
} else {
ArticleItemView(article: entry.widgetData.starredArticles[i],
deepLink: WidgetDeepLink.starredArticle(id: entry.widgetData.starredArticles[i].id).url)
.padding(.bottom, 4)
.padding(.bottom, WidgetLayout.articleItemViewPaddingBottom)
}
})
Spacer()
}
.padding(.leading, metrics.size.width * 0.175)
.padding(.leading, WidgetLayout.leftSideWidth)
.padding([.bottom, .trailing])
.padding(.top, 12)
.overlay(
VStack {
VStack {
Spacer()
HStack {
Spacer()
@@ -68,35 +56,34 @@ struct StarredWidgetView : View {
}
}
}
.padding(.horizontal)
.padding(.bottom, 6)
.padding(.horizontal)
)
}.widgetURL(WidgetDeepLink.starred.url)
}
.widgetURL(WidgetDeepLink.starred.url)
}
}
var starredImage: some View {
Image(systemName: "star.fill")
.resizable()
.frame(width: 30, height: 30, alignment: .center)
.frame(width: WidgetLayout.titleImageSize, height: WidgetLayout.titleImageSize, alignment: .top)
.cornerRadius(4)
.foregroundColor(.yellow)
}
func maxCount() -> Int {
var reduceAccessibilityCount: Int = 0
if SizeCategories().isSizeCategoryLarge(category: sizeCategory) {
reduceAccessibilityCount = 1
}
if family == .systemLarge {
return entry.widgetData.currentStarredCount >= 7 ? (7 - reduceAccessibilityCount) : entry.widgetData.currentStarredCount
}
return entry.widgetData.currentStarredCount >= 3 ? (3 - reduceAccessibilityCount) : entry.widgetData.currentStarredCount
}
var inboxZero: some View {
VStack(alignment: .center) {
Spacer()
@@ -105,12 +92,12 @@ struct StarredWidgetView : View {
.aspectRatio(contentMode: .fit)
.frame(width: 30)
.foregroundColor(.yellow)
Text(L10n.starredWidgetNoItemsTitle)
.font(.headline)
.foregroundColor(.primary)
Text(L10n.starredWidgetNoItems)
.font(.caption)
.foregroundColor(.gray)
@@ -119,5 +106,5 @@ struct StarredWidgetView : View {
.multilineTextAlignment(.center)
.padding()
}
}

View File

@@ -10,12 +10,12 @@ import WidgetKit
import SwiftUI
struct TodayWidgetView : View {
@Environment(\.widgetFamily) var family: WidgetFamily
@Environment(\.sizeCategory) var sizeCategory: ContentSizeCategory
var entry: Provider.Entry
var body: some View {
if entry.widgetData.todayArticles.count == 0 {
inboxZero
@@ -23,40 +23,28 @@ struct TodayWidgetView : View {
}
else {
GeometryReader { metrics in
HStack {
VStack {
todayImage
.padding(.vertical, 12)
.padding(.leading, 8)
Spacer()
}
}
.frame(width: metrics.size.width * 0.15)
Spacer()
todayImage
.frame(width: WidgetLayout.titleImageSize, alignment: .leading)
VStack(alignment:.leading, spacing: 0) {
ForEach(0..<maxCount(), id: \.self, content: { i in
if i != 0 {
Divider()
ArticleItemView(article: entry.widgetData.todayArticles[i],
deepLink: WidgetDeepLink.todayArticle(id: entry.widgetData.todayArticles[i].id).url)
.padding(.top, 8)
.padding(.bottom, 4)
.padding(.top, WidgetLayout.articleItemViewPaddingTop)
.padding(.bottom, WidgetLayout.articleItemViewPaddingBottom)
} else {
ArticleItemView(article: entry.widgetData.todayArticles[i],
deepLink: WidgetDeepLink.todayArticle(id: entry.widgetData.todayArticles[i].id).url)
.padding(.bottom, 4)
.padding(.bottom, WidgetLayout.articleItemViewPaddingBottom)
}
})
Spacer()
}
.padding(.leading, metrics.size.width * 0.175)
.padding(.leading, WidgetLayout.leftSideWidth)
.padding([.bottom, .trailing])
.padding(.top, 12)
.overlay(
VStack {
VStack {
Spacer()
HStack {
Spacer()
@@ -68,34 +56,34 @@ struct TodayWidgetView : View {
}
}
}
.padding(.horizontal)
.padding(.bottom, 6)
.padding(.horizontal)
)
}.widgetURL(WidgetDeepLink.today.url)
}
.widgetURL(WidgetDeepLink.today.url)
}
}
var todayImage: some View {
Image(systemName: "sun.max.fill")
.resizable()
.frame(width: 30, height: 30, alignment: .center)
.frame(width: WidgetLayout.titleImageSize, height: WidgetLayout.titleImageSize, alignment: .top)
.cornerRadius(4)
.foregroundColor(.orange)
}
func maxCount() -> Int {
var reduceAccessibilityCount: Int = 0
if SizeCategories().isSizeCategoryLarge(category: sizeCategory) {
reduceAccessibilityCount = 1
}
if family == .systemLarge {
return entry.widgetData.todayArticles.count >= 7 ? (7 - reduceAccessibilityCount) : entry.widgetData.todayArticles.count
}
return entry.widgetData.todayArticles.count >= 3 ? (3 - reduceAccessibilityCount) : entry.widgetData.todayArticles.count
}
var inboxZero: some View {
VStack(alignment: .center) {
Spacer()
@@ -104,12 +92,12 @@ struct TodayWidgetView : View {
.aspectRatio(contentMode: .fit)
.frame(width: 30)
.foregroundColor(.orange)
Text(L10n.todayWidgetNoItemsTitle)
.font(.headline)
.foregroundColor(.primary)
Text(L10n.todayWidgetNoItems)
.font(.caption)
.foregroundColor(.gray)
@@ -118,5 +106,5 @@ struct TodayWidgetView : View {
.multilineTextAlignment(.center)
.padding()
}
}

View File

@@ -10,12 +10,12 @@ import WidgetKit
import SwiftUI
struct UnreadWidgetView : View {
@Environment(\.widgetFamily) var family: WidgetFamily
@Environment(\.sizeCategory) var sizeCategory: ContentSizeCategory
var entry: Provider.Entry
var body: some View {
if entry.widgetData.currentUnreadCount == 0 {
inboxZero
@@ -24,24 +24,24 @@ struct UnreadWidgetView : View {
else {
GeometryReader { metrics in
unreadImage
.frame(width: metrics.size.width * 0.10, alignment: .leading)
.frame(width: WidgetLayout.titleImageSize, alignment: .leading)
VStack(alignment:.leading, spacing: 0) {
ForEach(0..<maxCount(), id: \.self, content: { i in
if i != 0 {
Divider()
ArticleItemView(article: entry.widgetData.unreadArticles[i],
deepLink: WidgetDeepLink.unreadArticle(id: entry.widgetData.unreadArticles[i].id).url)
.padding(.top, 8)
.padding(.bottom, 4)
.padding(.top, WidgetLayout.articleItemViewPaddingTop)
.padding(.bottom, WidgetLayout.articleItemViewPaddingBottom)
} else {
ArticleItemView(article: entry.widgetData.unreadArticles[i],
deepLink: WidgetDeepLink.unreadArticle(id: entry.widgetData.unreadArticles[i].id).url)
.padding(.bottom, 4)
.padding(.bottom, WidgetLayout.articleItemViewPaddingBottom)
}
})
Spacer()
}
.padding(.leading, metrics.size.width * 0.085)
.padding(.leading, WidgetLayout.leftSideWidth)
.padding([.bottom, .trailing])
.overlay(
VStack {
@@ -62,26 +62,26 @@ struct UnreadWidgetView : View {
.widgetURL(WidgetDeepLink.unread.url)
}
}
var unreadImage: some View {
Image(systemName: "largecircle.fill.circle")
.resizable()
.frame(width: 20, height: 20, alignment: .top)
.frame(width: WidgetLayout.titleImageSize, height: WidgetLayout.titleImageSize, alignment: .top)
.foregroundColor(.accentColor)
}
func maxCount() -> Int {
var reduceAccessibilityCount: Int = 0
if SizeCategories().isSizeCategoryLarge(category: sizeCategory) {
reduceAccessibilityCount = 1
}
if family == .systemLarge {
return entry.widgetData.unreadArticles.count >= 7 ? (7 - reduceAccessibilityCount) : entry.widgetData.unreadArticles.count
}
return entry.widgetData.unreadArticles.count >= 3 ? (3 - reduceAccessibilityCount) : entry.widgetData.unreadArticles.count
}
var inboxZero: some View {
VStack(alignment: .center) {
Spacer()
@@ -94,7 +94,7 @@ struct UnreadWidgetView : View {
Text(L10n.unreadWidgetNoItemsTitle)
.font(.headline)
.foregroundColor(.primary)
Text(L10n.unreadWidgetNoItems)
.font(.caption)
.foregroundColor(.gray)
@@ -103,6 +103,6 @@ struct UnreadWidgetView : View {
.multilineTextAlignment(.center)
.padding()
}
}

View File

@@ -0,0 +1,19 @@
//
// WidgetLayout.swift
// NetNewsWire iOS Widget Extension
//
// Created by Brent Simmons on 12/26/24.
// Copyright © 2024 Ranchero Software. All rights reserved.
//
import Foundation
struct WidgetLayout {
static let titleImageSize = CGFloat(20)
static let titleImagePaddingRight = CGFloat(6)
static let leftSideWidth = titleImageSize + titleImagePaddingRight
static let feedIconSize = CGFloat(24)
static let articleItemViewPaddingTop = CGFloat(8)
static let articleItemViewPaddingBottom = CGFloat(4)
}