Skip to content

Commit

Permalink
Reader: RSS support improvements (#23751)
Browse files Browse the repository at this point in the history
  • Loading branch information
kean authored Nov 4, 2024
2 parents 4731816 + 9bbed96 commit 84ff82f
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ struct SiteIconView: View {
switch size {
case .small: 18
case .regular: 24
case .large: 34
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ struct SiteIconViewModel {
enum Size {
case small
case regular
case large

var width: CGFloat {
switch self {
case .small: 28
case .regular: 40
case .large: 72
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ final class ReaderPostCell: ReaderStreamBaseCell {

private var contentViewConstraints: [NSLayoutConstraint] = []

static let avatarSize: CGFloat = 28
static let avatarSize: CGFloat = SiteIconViewModel.Size.small.width

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ final class ReaderPostCellViewModel {
self.avatarURL = post.authorAvatarURL.flatMap(URL.init)
} else if let avatarURL = post.siteIconForDisplay(ofSize: Int(ReaderPostCell.avatarSize)) {
self.avatarURL = avatarURL
} else if let blogURL = post.blogURL.flatMap(URL.init) {
} else if let blogURL = post.blogURL.flatMap(URL.init), post.isExternal {
if let faviconURL = FaviconService.shared.cachedFavicon(forURL: blogURL) {
self.avatarURL = faviconURL
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class ReaderSiteHeaderView: UITableViewHeaderFooterView, ReaderStreamHeader {
assertionFailure("This header should only be used for site topics.")
return
}
headerViewModel.imageUrl = siteTopic.siteBlavatar
headerViewModel.site = siteTopic
headerViewModel.title = siteTopic.title
headerViewModel.siteUrl = URL(string: siteTopic.siteURL)?.host ?? ""
headerViewModel.siteDetails = siteTopic.siteDescription
Expand Down Expand Up @@ -78,19 +78,8 @@ struct ReaderSiteHeader: View {

var body: some View {
VStack(alignment: .leading, spacing: 12) {
AsyncImage(url: URL(string: viewModel.imageUrl)) { phase in
switch phase {
case .success(let image):
image
.resizable()
.frame(width: 72.0, height: 72.0)
.clipShape(Circle())
default:
Image(Constants.defaultSiteImage)
.resizable()
.frame(width: 72.0, height: 72.0)
.clipShape(Circle())
}
if let site = viewModel.site {
ReaderSiteIconView(site: site, size: .large)
}
VStack(alignment: .leading, spacing: 4) {
Text(viewModel.title)
Expand All @@ -104,7 +93,9 @@ struct ReaderSiteHeader: View {
.font(.subheadline)
.foregroundColor(.secondary)
}
countsDisplay
if viewModel.site?.isExternal == false {
countsDisplay
}
if !viewModel.isFollowHidden {
ReaderFollowButton(isFollowing: viewModel.isFollowingSite,
isEnabled: viewModel.isFollowEnabled,
Expand Down Expand Up @@ -134,7 +125,6 @@ struct ReaderSiteHeader: View {
}

struct Constants {
static let defaultSiteImage = "blavatar-default"
static let countsFormat = NSLocalizedString("reader.blog.header.values",
value: "%1$@ posts • %2$@ subscribers",
comment: "The formatted number of posts and followers for a site. " +
Expand All @@ -148,8 +138,7 @@ struct ReaderSiteHeader: View {
// MARK: - ReaderSiteHeaderViewModel

class ReaderSiteHeaderViewModel: ObservableObject {

@Published var imageUrl: String
@Published var site: ReaderSiteTopic?
@Published var title: String
@Published var siteUrl: String
@Published var siteDetails: String
Expand All @@ -161,8 +150,7 @@ class ReaderSiteHeaderViewModel: ObservableObject {

private let onFollowTap: (_ completion: @escaping () -> Void) -> Void

init(imageUrl: String = "",
title: String = "",
init(title: String = "",
siteUrl: String = "",
siteDetails: String = "",
postCount: String = "",
Expand All @@ -171,7 +159,6 @@ class ReaderSiteHeaderViewModel: ObservableObject {
isFollowHidden: Bool = false,
isFollowEnabled: Bool = true,
onFollowTap: @escaping (_ completion: @escaping () -> Void) -> Void = { _ in }) {
self.imageUrl = imageUrl
self.title = title
self.siteUrl = siteUrl
self.siteDetails = siteDetails
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ struct ReaderSidebarSubscriptionsSection: View {
Label {
Text(site.title)
} icon: {
SiteIconView(viewModel: SiteIconViewModel(readerSiteTopic: site, size: .small))
.frame(width: 28, height: 28)
ReaderSiteIconView(site: site, size: .small)
}
.lineLimit(1)
.tag(ReaderSidebarItem.subscription(TaggedManagedObjectID(site)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ struct ReaderSubscriptionCell: View {
var body: some View {
HStack(spacing: 0) {
HStack(spacing: 16) {
let size = SiteIconViewModel.Size.regular
SiteIconView(viewModel: .init(readerSiteTopic: site, size: size))
.frame(width: size.width, height: size.width)
ReaderSiteIconView(site: site, size: .regular)
.padding(.leading, 4)

VStack(alignment: .leading, spacing: 3) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import SwiftUI

struct ReaderSiteIconView: View, Hashable {
let site: ReaderSiteTopic
var size: SiteIconViewModel.Size = .small

var body: some View {
_ReaderSiteIconView(viewModel: .init(site: site, size: size))
.id(self) // important to ensure @StateObject is re-created if needed
.frame(width: size.width, height: size.width)
}
}

private struct _ReaderSiteIconView: View {
@StateObject var viewModel: ReaderSiteIconViewModel

var body: some View {
SiteIconView(viewModel: viewModel.icon)
.task { await viewModel.refresh() }
}
}

@MainActor
final class ReaderSiteIconViewModel: ObservableObject {
@Published private(set) var icon: SiteIconViewModel

let site: ReaderSiteTopic
let size: SiteIconViewModel.Size

init(site: ReaderSiteTopic, size: SiteIconViewModel.Size) {
self.site = site
self.size = size
self.icon = SiteIconViewModel(readerSiteTopic: site, size: size)
}

func refresh() async {
if site.isExternal, icon.imageURL == nil, let siteURL = URL(string: site.siteURL) {
if let faviconURL = FaviconService.shared.cachedFavicon(forURL: siteURL) {
icon.imageURL = faviconURL
} else {
icon.imageURL = try? await FaviconService.shared.favicon(forURL: siteURL)
}
}
}
}

0 comments on commit 84ff82f

Please sign in to comment.