Do the first parts of showing feed avatars.

This commit is contained in:
Brent Simmons 2017-11-28 21:39:09 -08:00
parent 1e528ee8b0
commit dd05a24704
6 changed files with 87 additions and 38 deletions

View File

@ -15,6 +15,7 @@ final class FeaturedImageDownloader {
private let imageDownloader: ImageDownloader
private var articleURLToFeaturedImageURLCache = [String: String]()
private var articleURLsWithNoFeaturedImage = Set<String>()
private var urlsInProgress = Set<String>()
init(imageDownloader: ImageDownloader) {
@ -66,8 +67,15 @@ private extension FeaturedImageDownloader {
func findFeaturedImageURL(for articleURL: String) {
guard !urlsInProgress.contains(articleURL) else {
return
}
urlsInProgress.insert(articleURL)
HTMLMetadataDownloader.downloadMetadata(for: articleURL) { (metadata) in
self.urlsInProgress.remove(articleURL)
guard let metadata = metadata else {
return
}

View File

@ -16,7 +16,8 @@ public final class FeedIconDownloader {
private let imageDownloader: ImageDownloader
private var homePageToIconURLCache = [String: String]()
private var homePagesWithNoIconURL = Set<String>()
private var homePageDownloadsInProgress = Set<String>()
private var urlsInProgress = Set<String>()
private var cache = [Feed: NSImage]()
init(imageDownloader: ImageDownloader) {
@ -25,12 +26,22 @@ public final class FeedIconDownloader {
func icon(for feed: Feed) -> NSImage? {
if let cachedImage = cache[feed] {
return cachedImage
}
if let iconURL = feed.iconURL {
return icon(forURL: iconURL)
if let image = icon(forURL: iconURL) {
cache[feed] = image
return image
}
}
if let homePageURL = feed.homePageURL {
return icon(forHomePageURL: homePageURL)
if let image = icon(forHomePageURL: homePageURL) {
cache[feed] = image
return image
}
}
return nil
@ -71,14 +82,14 @@ private extension FeedIconDownloader {
func findIconURLForHomePageURL(_ homePageURL: String) {
guard !homePageDownloadsInProgress.contains(homePageURL) else {
guard !urlsInProgress.contains(homePageURL) else {
return
}
homePageDownloadsInProgress.insert(homePageURL)
urlsInProgress.insert(homePageURL)
HTMLMetadataDownloader.downloadMetadata(for: homePageURL) { (metadata) in
self.homePageDownloadsInProgress.remove(homePageURL)
self.urlsInProgress.remove(homePageURL)
guard let metadata = metadata else {
return
}

View File

@ -36,36 +36,44 @@ struct TimelineCellAppearance {
let boxLeftMargin: CGFloat
let gridColor: NSColor
let avatarSize: NSSize
let avatarMarginRight: CGFloat
let avatarAdjustmentTop: CGFloat
init(theme: VSTheme, fontSize: FontSize) {
let actualFontSize = AppDefaults.actualFontSize(for: fontSize)
cellPadding = theme.edgeInsets(forKey: "MainWindow.Timeline.cell.padding")
self.cellPadding = theme.edgeInsets(forKey: "MainWindow.Timeline.cell.padding")
feedNameColor = theme.color(forKey: "MainWindow.Timeline.cell.feedNameColor")
feedNameFont = NSFont.systemFont(ofSize: actualFontSize)
faviconFeedNameSpacing = theme.float(forKey: "MainWindow.Timeline.cell.faviconFeedNameSpacing")
self.feedNameColor = theme.color(forKey: "MainWindow.Timeline.cell.feedNameColor")
self.feedNameFont = NSFont.systemFont(ofSize: actualFontSize)
self.faviconFeedNameSpacing = theme.float(forKey: "MainWindow.Timeline.cell.faviconFeedNameSpacing")
dateColor = theme.color(forKey: "MainWindow.Timeline.cell.dateColor")
self.dateColor = theme.color(forKey: "MainWindow.Timeline.cell.dateColor")
let actualDateFontSize = AppDefaults.actualFontSize(for: fontSize)
dateFont = NSFont.systemFont(ofSize: actualDateFontSize)
dateMarginLeft = theme.float(forKey: "MainWindow.Timeline.cell.dateMarginLeft")
self.dateFont = NSFont.systemFont(ofSize: actualDateFontSize)
self.dateMarginLeft = theme.float(forKey: "MainWindow.Timeline.cell.dateMarginLeft")
titleColor = theme.color(forKey: "MainWindow.Timeline.cell.titleColor")
titleFont = NSFont.systemFont(ofSize: actualFontSize, weight: NSFont.Weight.bold)
titleBottomMargin = theme.float(forKey: "MainWindow.Timeline.cell.titleMarginBottom")
self.titleColor = theme.color(forKey: "MainWindow.Timeline.cell.titleColor")
self.titleFont = NSFont.systemFont(ofSize: actualFontSize, weight: NSFont.Weight.bold)
self.titleBottomMargin = theme.float(forKey: "MainWindow.Timeline.cell.titleMarginBottom")
textColor = theme.color(forKey: "MainWindow.Timeline.cell.textColor")
textFont = NSFont.systemFont(ofSize: actualFontSize)
self.textColor = theme.color(forKey: "MainWindow.Timeline.cell.textColor")
self.textFont = NSFont.systemFont(ofSize: actualFontSize)
unreadCircleColor = theme.color(forKey: "MainWindow.Timeline.cell.unreadCircleColor")
unreadCircleDimension = theme.float(forKey: "MainWindow.Timeline.cell.unreadCircleDimension")
unreadCircleMarginRight = theme.float(forKey: "MainWindow.Timeline.cell.unreadCircleMarginRight")
self.unreadCircleColor = theme.color(forKey: "MainWindow.Timeline.cell.unreadCircleColor")
self.unreadCircleDimension = theme.float(forKey: "MainWindow.Timeline.cell.unreadCircleDimension")
self.unreadCircleMarginRight = theme.float(forKey: "MainWindow.Timeline.cell.unreadCircleMarginRight")
boxLeftMargin = cellPadding.left + unreadCircleDimension + unreadCircleMarginRight
self.gridColor = theme.colorWithAlpha(forKey: "MainWindow.Timeline.gridColor")
self.avatarSize = theme.size(forKey: "MainWindow.Timeline.cell.avatar")
self.avatarMarginRight = theme.float(forKey: "MainWindow.Timeline.cell.avatarMarginRight")
self.avatarAdjustmentTop = theme.float(forKey: "MainWindow.Timeline.cell.avatarAdjustmentTop")
gridColor = theme.colorWithAlpha(forKey: "MainWindow.Timeline.gridColor")
self.boxLeftMargin = self.cellPadding.left + self.unreadCircleDimension + self.unreadCircleMarginRight + self.avatarSize.width + self.avatarMarginRight
}
}

View File

@ -43,7 +43,10 @@ struct TimelineCellLayout {
height = NSMaxY(feedNameRect)
}
height = height + paddingBottom
let heightOfImage = avatarImageRect.maxY + paddingBottom
height = max(height, heightOfImage)
self.height = height
}
}
@ -59,11 +62,8 @@ private func rectForDate(_ cellData: TimelineCellData, _ width: CGFloat, _ appea
r.origin.y = NSMaxY(titleRect) + appearance.titleBottomMargin
r.origin.x = appearance.boxLeftMargin
r.size.width = width - (r.origin.x + appearance.cellPadding.right)
if r.size.width < 15 {
return NSZeroRect
}
r.size.width = max(width - (r.origin.x + appearance.cellPadding.right), 0.0)
return r
}
@ -118,7 +118,8 @@ private func rectsForTitle(_ cellData: TimelineCellData, _ width: CGFloat, _ app
let measurements = renderer.measurements(forWidth: textWidth)
r.size = NSSize(width: textWidth, height: CGFloat(measurements.height))
r.size.width = max(r.size.width, 0.0)
var rline1 = r
rline1.size.height = CGFloat(measurements.heightOfFirstLine)
@ -139,10 +140,14 @@ private func rectForUnreadIndicator(_ cellData: TimelineCellData, _ appearance:
return r
}
private func rectForAvatar(_ cellData: TimelineCellData, _ appearance: TimelineCellAppearance, _ unreadIndictarRect: NSRect) -> NSRect {
private func rectForAvatar(_ cellData: TimelineCellData, _ appearance: TimelineCellAppearance, _ titleLine1Rect: NSRect) -> NSRect {
// TODO
return NSRect.zero
var r = NSRect.zero
r.size = appearance.avatarSize
r.origin.x = appearance.cellPadding.left + appearance.unreadCircleDimension + appearance.unreadCircleMarginRight
r.origin.y = titleLine1Rect.minY + appearance.avatarAdjustmentTop
return r
}
func timelineCellLayout(_ width: CGFloat, cellData: TimelineCellData, appearance: TimelineCellAppearance) -> TimelineCellLayout {
@ -153,7 +158,7 @@ func timelineCellLayout(_ width: CGFloat, cellData: TimelineCellData, appearance
let feedNameRect = rectForFeedName(cellData, width, appearance, titleRect)
let faviconRect = rectForFavicon(cellData, appearance, feedNameRect)
let unreadIndicatorRect = rectForUnreadIndicator(cellData, appearance, titleLine1Rect)
let avatarImageRect = rectForAvatar(cellData, appearance, unreadIndicatorRect)
let avatarImageRect = rectForAvatar(cellData, appearance, titleLine1Rect)
return TimelineCellLayout(width: width, faviconRect: faviconRect, feedNameRect: feedNameRect, dateRect: dateRect, titleRect: titleRect, unreadIndicatorRect: unreadIndicatorRect, avatarImageRect: avatarImageRect, paddingBottom: appearance.cellPadding.bottom)
}

View File

@ -122,6 +122,7 @@ class TimelineTableCellView: NSTableCellView {
unreadIndicatorView.rs_setFrameIfNotEqual(layoutRects.unreadIndicatorRect)
dateView.rs_setFrameIfNotEqual(layoutRects.dateRect)
feedNameView.rs_setFrameIfNotEqual(layoutRects.feedNameRect)
avatarImageView.rs_setFrameIfNotEqual(layoutRects.avatarImageRect)
}
override func updateLayer() {
@ -173,12 +174,26 @@ class TimelineTableCellView: NSTableCellView {
}
}
private func updateAvatar() {
if let image = cellData.avatar {
if avatarImageView.image !== image {
avatarImageView.image = image
}
avatarImageView.isHidden = false
}
else {
avatarImageView.isHidden = true
}
}
private func updateSubviews() {
updateTitleView()
updateDateView()
updateFeedNameView()
updateUnreadIndicator()
updateAvatar()
}
private func updateAppearance() {

View File

@ -94,11 +94,13 @@
<key>unreadCircleMarginRight</key>
<integer>8</integer>
<key>avatarHeight</key>
<string>64</string>
<integer>42</integer>
<key>avatarWidth</key>
<string>64</string>
<integer>42</integer>
<key>avatarMarginRight</key>
<string>8</string>
<integer>8</integer>
<key>avatarAdjustmentTop</key>
<integer>4</integer>
</dict>
</dict>
</dict>