Make Article icons/avatars match Timeline icons/avatars Issue #1274

This commit is contained in:
Maurice Parker 2019-11-07 14:29:16 -06:00
parent 5d2cac32e0
commit 4f294c4d20
8 changed files with 83 additions and 25 deletions

View File

@ -60,6 +60,7 @@
513C5D0C232574DA003D4054 /* RSTree.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F9520DD8CFE00CA8CF5 /* RSTree.framework */; };
513C5D0E232574E4003D4054 /* SyncDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; };
5141E7392373C18B0013FF27 /* FeedInspectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5141E7382373C18B0013FF27 /* FeedInspectorViewController.swift */; };
5141E7562374A2890013FF27 /* ArticleIconSchemeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5141E7552374A2890013FF27 /* ArticleIconSchemeHandler.swift */; };
5142192A23522B5500E07E2C /* ImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5142192923522B5500E07E2C /* ImageViewController.swift */; };
514219372352510100E07E2C /* ImageScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514219362352510100E07E2C /* ImageScrollView.swift */; };
5142194B2353C1CF00E07E2C /* main_mac.js in Resources */ = {isa = PBXBuildFile; fileRef = 5142194A2353C1CF00E07E2C /* main_mac.js */; };
@ -1229,6 +1230,7 @@
513C5CEB232571C2003D4054 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
513C5CED232571C2003D4054 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5141E7382373C18B0013FF27 /* FeedInspectorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedInspectorViewController.swift; sourceTree = "<group>"; };
5141E7552374A2890013FF27 /* ArticleIconSchemeHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleIconSchemeHandler.swift; sourceTree = "<group>"; };
5142192923522B5500E07E2C /* ImageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageViewController.swift; sourceTree = "<group>"; };
514219362352510100E07E2C /* ImageScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageScrollView.swift; sourceTree = "<group>"; };
5142194A2353C1CF00E07E2C /* main_mac.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = main_mac.js; sourceTree = "<group>"; };
@ -1913,6 +1915,7 @@
children = (
51C4527E2265092C00C03939 /* ArticleViewController.swift */,
517630222336657E00E15FFF /* ArticleViewControllerWebViewProvider.swift */,
5141E7552374A2890013FF27 /* ArticleIconSchemeHandler.swift */,
51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */,
5142192923522B5500E07E2C /* ImageViewController.swift */,
514219362352510100E07E2C /* ImageScrollView.swift */,
@ -3930,6 +3933,7 @@
51C45292226509C800C03939 /* TodayFeedDelegate.swift in Sources */,
51C452A222650A1900C03939 /* RSHTMLMetadata+Extension.swift in Sources */,
514B7D1F23219F3C00BAC947 /* AddControllerType.swift in Sources */,
5141E7562374A2890013FF27 /* ArticleIconSchemeHandler.swift in Sources */,
512AF9DD236F05230066F8BE /* InteractiveLabel.swift in Sources */,
51E3EB3D229AB08300645299 /* ErrorHandler.swift in Sources */,
5183CCE5226F4DFA0010922C /* RefreshInterval.swift in Sources */,

View File

@ -16,6 +16,8 @@ struct ArticleRenderer {
typealias Rendering = (style: String, html: String)
typealias Page = (html: String, baseURL: URL)
static var imageIconScheme = "nnwImageIcon"
static var page: Page = {
let pageURL = Bundle.main.url(forResource: "page", withExtension: "html")!
let html = try! String(contentsOf: pageURL)
@ -29,8 +31,9 @@ struct ArticleRenderer {
private let title: String
private let body: String
private let baseURL: String?
private let useImageIcon: Bool
private init(article: Article?, extractedArticle: ExtractedArticle?, style: ArticleStyle) {
private init(article: Article?, extractedArticle: ExtractedArticle?, style: ArticleStyle, useImageIcon: Bool = false) {
self.article = article
self.extractedArticle = extractedArticle
self.articleStyle = style
@ -42,12 +45,13 @@ struct ArticleRenderer {
self.body = article?.body ?? ""
self.baseURL = article?.baseURL?.absoluteString
}
self.useImageIcon = useImageIcon
}
// MARK: - API
static func articleHTML(article: Article, extractedArticle: ExtractedArticle? = nil, style: ArticleStyle) -> Rendering {
let renderer = ArticleRenderer(article: article, extractedArticle: extractedArticle, style: style)
static func articleHTML(article: Article, extractedArticle: ExtractedArticle? = nil, style: ArticleStyle, useImageIcon: Bool = false) -> Rendering {
let renderer = ArticleRenderer(article: article, extractedArticle: extractedArticle, style: style, useImageIcon: useImageIcon)
return (renderer.styleString(), renderer.articleHTML)
}
@ -231,6 +235,10 @@ private extension ArticleRenderer {
return cachedImgTag
}
if useImageIcon {
return "<img src=\"\(ArticleRenderer.imageIconScheme)://article.png\" height=48 width=48 />"
}
if let iconImage = appDelegate.feedIconDownloader.icon(for: feed) {
if let s = base64String(forImage: iconImage.image) {
#if os(macOS)
@ -281,7 +289,8 @@ private extension ArticleRenderer {
}
func avatarImgTag() -> String? {
if let author = singleArticleSpecifiedAuthor(), let imageURL = author.avatarURL {
if let author = singleArticleSpecifiedAuthor(), let authorImageURL = author.avatarURL {
let imageURL = useImageIcon ? ArticleRenderer.imageIconScheme : authorImageURL
return Avatar(imageURL: imageURL, url: author.url).html(dimension: ArticleRenderer.avatarDimension)
}
if let feed = article?.feed, let imgTag = feedIconImgTag(forFeed: feed) {

View File

@ -65,14 +65,18 @@ extension Article {
}
func iconImage() -> IconImage? {
if let authors = authors {
for author in authors {
if let image = appDelegate.authorAvatarDownloader.image(for: author) {
return image
}
if let authors = authors, authors.count == 1, let author = authors.first {
if let image = appDelegate.authorAvatarDownloader.image(for: author) {
return image
}
}
if let authors = feed?.authors, authors.count == 1, let author = authors.first {
if let image = appDelegate.authorAvatarDownloader.image(for: author) {
return image
}
}
guard let feed = feed else {
return nil
}
@ -88,7 +92,6 @@ extension Article {
return FaviconGenerator.favicon(feed)
}
}
// MARK: PathIDUserInfoProvider

View File

@ -0,0 +1,44 @@
//
// AccountViewControllerSchemeHandler.swift
// NetNewsWire-iOS
//
// Created by Maurice Parker on 11/7/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import Foundation
import WebKit
import Articles
class ArticleIconSchemeHandler: NSObject, WKURLSchemeHandler {
var currentArticle: Article?
func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
DispatchQueue.main.async {
guard let responseURL = urlSchemeTask.request.url, let iconImage = self.currentArticle?.iconImage() else {
urlSchemeTask.didFailWithError(URLError(.fileDoesNotExist))
return
}
let iconView = IconView(frame: CGRect(x: 0, y: 0, width: 48, height: 48))
iconView.iconImage = iconImage
let renderedImage = iconView.asImage()
guard let data = renderedImage.dataRepresentation() else {
urlSchemeTask.didFailWithError(URLError(.fileDoesNotExist))
return
}
let response = URLResponse(url: responseURL, mimeType: "image/png", expectedContentLength: data.count, textEncodingName: nil);
urlSchemeTask.didReceive(response)
urlSchemeTask.didReceive(data)
urlSchemeTask.didFinish()
}
}
func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
urlSchemeTask.didFailWithError(URLError(.unknown))
}
}

View File

@ -166,9 +166,9 @@ class ArticleViewController: UIViewController {
case .loading:
rendering = ArticleRenderer.loadingHTML(style: style)
case .article(let article):
rendering = ArticleRenderer.articleHTML(article: article, style: style)
rendering = ArticleRenderer.articleHTML(article: article, style: style, useImageIcon: true)
case .extracted(let article, let extractedArticle):
rendering = ArticleRenderer.articleHTML(article: article, extractedArticle: extractedArticle, style: style)
rendering = ArticleRenderer.articleHTML(article: article, extractedArticle: extractedArticle, style: style, useImageIcon: true)
}
let templateData = TemplateData(style: rendering.style, body: rendering.html)
@ -180,6 +180,7 @@ class ArticleViewController: UIViewController {
render = "render(\(json));"
}
ArticleViewControllerWebViewProvider.shared.articleIconSchemeHandler.currentArticle = currentArticle
webView?.scrollView.setZoomScale(1.0, animated: false)
webView?.evaluateJavaScript(render)

View File

@ -15,6 +15,8 @@ class ArticleViewControllerWebViewProvider: NSObject, WKNavigationDelegate {
static let shared = ArticleViewControllerWebViewProvider()
let articleIconSchemeHandler = ArticleIconSchemeHandler()
private let minimumQueueDepth = 3
private let maximumQueueDepth = 6
private var queue: [WKWebView] = []
@ -72,6 +74,7 @@ class ArticleViewControllerWebViewProvider: NSObject, WKNavigationDelegate {
configuration.setValue(true, forKey: "allowUniversalAccessFromFileURLs")
configuration.allowsInlineMediaPlayback = true
configuration.mediaTypesRequiringUserActionForPlayback = .video
configuration.setURLSchemeHandler(articleIconSchemeHandler, forURLScheme: ArticleRenderer.imageIconScheme)
let webView = WKWebView(frame: .zero, configuration: configuration)
enqueueWebView(webView)

View File

@ -16,18 +16,12 @@ final class IconView: UIView {
imageView.image = iconImage?.image
if self.traitCollection.userInterfaceStyle == .dark {
DispatchQueue.global(qos: .default).async {
if self.iconImage?.isDark ?? false {
DispatchQueue.main.async {
self.isDisconcernable = false
self.setNeedsLayout()
}
} else {
DispatchQueue.main.async {
self.isDisconcernable = true
self.setNeedsLayout()
}
}
if self.iconImage?.isDark ?? false {
self.isDisconcernable = false
self.setNeedsLayout()
} else {
self.isDisconcernable = true
self.setNeedsLayout()
}
} else {
self.setNeedsLayout()

@ -1 +1 @@
Subproject commit ff75719c1e1ab5b9b3e8ec6dae0d8886ebd60ee6
Subproject commit 972ff3237f819a2250e0bc1ca2814bafe328fa69