Make Article icons/avatars match Timeline icons/avatars Issue #1274
This commit is contained in:
parent
5d2cac32e0
commit
4f294c4d20
@ -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 */,
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
44
iOS/Article/ArticleIconSchemeHandler.swift
Normal file
44
iOS/Article/ArticleIconSchemeHandler.swift
Normal 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))
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user