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 */; };
|
513C5D0C232574DA003D4054 /* RSTree.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F9520DD8CFE00CA8CF5 /* RSTree.framework */; };
|
||||||
513C5D0E232574E4003D4054 /* SyncDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; };
|
513C5D0E232574E4003D4054 /* SyncDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; };
|
||||||
5141E7392373C18B0013FF27 /* FeedInspectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5141E7382373C18B0013FF27 /* FeedInspectorViewController.swift */; };
|
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 */; };
|
5142192A23522B5500E07E2C /* ImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5142192923522B5500E07E2C /* ImageViewController.swift */; };
|
||||||
514219372352510100E07E2C /* ImageScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514219362352510100E07E2C /* ImageScrollView.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 */; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
5142194A2353C1CF00E07E2C /* main_mac.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = main_mac.js; sourceTree = "<group>"; };
|
||||||
@ -1913,6 +1915,7 @@
|
|||||||
children = (
|
children = (
|
||||||
51C4527E2265092C00C03939 /* ArticleViewController.swift */,
|
51C4527E2265092C00C03939 /* ArticleViewController.swift */,
|
||||||
517630222336657E00E15FFF /* ArticleViewControllerWebViewProvider.swift */,
|
517630222336657E00E15FFF /* ArticleViewControllerWebViewProvider.swift */,
|
||||||
|
5141E7552374A2890013FF27 /* ArticleIconSchemeHandler.swift */,
|
||||||
51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */,
|
51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */,
|
||||||
5142192923522B5500E07E2C /* ImageViewController.swift */,
|
5142192923522B5500E07E2C /* ImageViewController.swift */,
|
||||||
514219362352510100E07E2C /* ImageScrollView.swift */,
|
514219362352510100E07E2C /* ImageScrollView.swift */,
|
||||||
@ -3930,6 +3933,7 @@
|
|||||||
51C45292226509C800C03939 /* TodayFeedDelegate.swift in Sources */,
|
51C45292226509C800C03939 /* TodayFeedDelegate.swift in Sources */,
|
||||||
51C452A222650A1900C03939 /* RSHTMLMetadata+Extension.swift in Sources */,
|
51C452A222650A1900C03939 /* RSHTMLMetadata+Extension.swift in Sources */,
|
||||||
514B7D1F23219F3C00BAC947 /* AddControllerType.swift in Sources */,
|
514B7D1F23219F3C00BAC947 /* AddControllerType.swift in Sources */,
|
||||||
|
5141E7562374A2890013FF27 /* ArticleIconSchemeHandler.swift in Sources */,
|
||||||
512AF9DD236F05230066F8BE /* InteractiveLabel.swift in Sources */,
|
512AF9DD236F05230066F8BE /* InteractiveLabel.swift in Sources */,
|
||||||
51E3EB3D229AB08300645299 /* ErrorHandler.swift in Sources */,
|
51E3EB3D229AB08300645299 /* ErrorHandler.swift in Sources */,
|
||||||
5183CCE5226F4DFA0010922C /* RefreshInterval.swift in Sources */,
|
5183CCE5226F4DFA0010922C /* RefreshInterval.swift in Sources */,
|
||||||
|
@ -16,6 +16,8 @@ struct ArticleRenderer {
|
|||||||
typealias Rendering = (style: String, html: String)
|
typealias Rendering = (style: String, html: String)
|
||||||
typealias Page = (html: String, baseURL: URL)
|
typealias Page = (html: String, baseURL: URL)
|
||||||
|
|
||||||
|
static var imageIconScheme = "nnwImageIcon"
|
||||||
|
|
||||||
static var page: Page = {
|
static var page: Page = {
|
||||||
let pageURL = Bundle.main.url(forResource: "page", withExtension: "html")!
|
let pageURL = Bundle.main.url(forResource: "page", withExtension: "html")!
|
||||||
let html = try! String(contentsOf: pageURL)
|
let html = try! String(contentsOf: pageURL)
|
||||||
@ -29,8 +31,9 @@ struct ArticleRenderer {
|
|||||||
private let title: String
|
private let title: String
|
||||||
private let body: String
|
private let body: String
|
||||||
private let baseURL: 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.article = article
|
||||||
self.extractedArticle = extractedArticle
|
self.extractedArticle = extractedArticle
|
||||||
self.articleStyle = style
|
self.articleStyle = style
|
||||||
@ -42,12 +45,13 @@ struct ArticleRenderer {
|
|||||||
self.body = article?.body ?? ""
|
self.body = article?.body ?? ""
|
||||||
self.baseURL = article?.baseURL?.absoluteString
|
self.baseURL = article?.baseURL?.absoluteString
|
||||||
}
|
}
|
||||||
|
self.useImageIcon = useImageIcon
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - API
|
// MARK: - API
|
||||||
|
|
||||||
static func articleHTML(article: Article, extractedArticle: ExtractedArticle? = nil, style: ArticleStyle) -> Rendering {
|
static func articleHTML(article: Article, extractedArticle: ExtractedArticle? = nil, style: ArticleStyle, useImageIcon: Bool = false) -> Rendering {
|
||||||
let renderer = ArticleRenderer(article: article, extractedArticle: extractedArticle, style: style)
|
let renderer = ArticleRenderer(article: article, extractedArticle: extractedArticle, style: style, useImageIcon: useImageIcon)
|
||||||
return (renderer.styleString(), renderer.articleHTML)
|
return (renderer.styleString(), renderer.articleHTML)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,6 +235,10 @@ private extension ArticleRenderer {
|
|||||||
return cachedImgTag
|
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 iconImage = appDelegate.feedIconDownloader.icon(for: feed) {
|
||||||
if let s = base64String(forImage: iconImage.image) {
|
if let s = base64String(forImage: iconImage.image) {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
@ -281,7 +289,8 @@ private extension ArticleRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func avatarImgTag() -> String? {
|
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)
|
return Avatar(imageURL: imageURL, url: author.url).html(dimension: ArticleRenderer.avatarDimension)
|
||||||
}
|
}
|
||||||
if let feed = article?.feed, let imgTag = feedIconImgTag(forFeed: feed) {
|
if let feed = article?.feed, let imgTag = feedIconImgTag(forFeed: feed) {
|
||||||
|
@ -65,11 +65,15 @@ extension Article {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func iconImage() -> IconImage? {
|
func iconImage() -> IconImage? {
|
||||||
if let authors = authors {
|
if let authors = authors, authors.count == 1, let author = authors.first {
|
||||||
for author in authors {
|
if let image = appDelegate.authorAvatarDownloader.image(for: author) {
|
||||||
if let image = appDelegate.authorAvatarDownloader.image(for: author) {
|
return image
|
||||||
return image
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let authors = feed?.authors, authors.count == 1, let author = authors.first {
|
||||||
|
if let image = appDelegate.authorAvatarDownloader.image(for: author) {
|
||||||
|
return image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +92,6 @@ extension Article {
|
|||||||
|
|
||||||
return FaviconGenerator.favicon(feed)
|
return FaviconGenerator.favicon(feed)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: PathIDUserInfoProvider
|
// 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:
|
case .loading:
|
||||||
rendering = ArticleRenderer.loadingHTML(style: style)
|
rendering = ArticleRenderer.loadingHTML(style: style)
|
||||||
case .article(let article):
|
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):
|
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)
|
let templateData = TemplateData(style: rendering.style, body: rendering.html)
|
||||||
@ -180,6 +180,7 @@ class ArticleViewController: UIViewController {
|
|||||||
render = "render(\(json));"
|
render = "render(\(json));"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArticleViewControllerWebViewProvider.shared.articleIconSchemeHandler.currentArticle = currentArticle
|
||||||
webView?.scrollView.setZoomScale(1.0, animated: false)
|
webView?.scrollView.setZoomScale(1.0, animated: false)
|
||||||
webView?.evaluateJavaScript(render)
|
webView?.evaluateJavaScript(render)
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@ class ArticleViewControllerWebViewProvider: NSObject, WKNavigationDelegate {
|
|||||||
|
|
||||||
static let shared = ArticleViewControllerWebViewProvider()
|
static let shared = ArticleViewControllerWebViewProvider()
|
||||||
|
|
||||||
|
let articleIconSchemeHandler = ArticleIconSchemeHandler()
|
||||||
|
|
||||||
private let minimumQueueDepth = 3
|
private let minimumQueueDepth = 3
|
||||||
private let maximumQueueDepth = 6
|
private let maximumQueueDepth = 6
|
||||||
private var queue: [WKWebView] = []
|
private var queue: [WKWebView] = []
|
||||||
@ -72,6 +74,7 @@ class ArticleViewControllerWebViewProvider: NSObject, WKNavigationDelegate {
|
|||||||
configuration.setValue(true, forKey: "allowUniversalAccessFromFileURLs")
|
configuration.setValue(true, forKey: "allowUniversalAccessFromFileURLs")
|
||||||
configuration.allowsInlineMediaPlayback = true
|
configuration.allowsInlineMediaPlayback = true
|
||||||
configuration.mediaTypesRequiringUserActionForPlayback = .video
|
configuration.mediaTypesRequiringUserActionForPlayback = .video
|
||||||
|
configuration.setURLSchemeHandler(articleIconSchemeHandler, forURLScheme: ArticleRenderer.imageIconScheme)
|
||||||
|
|
||||||
let webView = WKWebView(frame: .zero, configuration: configuration)
|
let webView = WKWebView(frame: .zero, configuration: configuration)
|
||||||
enqueueWebView(webView)
|
enqueueWebView(webView)
|
||||||
|
@ -16,18 +16,12 @@ final class IconView: UIView {
|
|||||||
imageView.image = iconImage?.image
|
imageView.image = iconImage?.image
|
||||||
|
|
||||||
if self.traitCollection.userInterfaceStyle == .dark {
|
if self.traitCollection.userInterfaceStyle == .dark {
|
||||||
DispatchQueue.global(qos: .default).async {
|
if self.iconImage?.isDark ?? false {
|
||||||
if self.iconImage?.isDark ?? false {
|
self.isDisconcernable = false
|
||||||
DispatchQueue.main.async {
|
self.setNeedsLayout()
|
||||||
self.isDisconcernable = false
|
} else {
|
||||||
self.setNeedsLayout()
|
self.isDisconcernable = true
|
||||||
}
|
self.setNeedsLayout()
|
||||||
} else {
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
self.isDisconcernable = true
|
|
||||||
self.setNeedsLayout()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.setNeedsLayout()
|
self.setNeedsLayout()
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit ff75719c1e1ab5b9b3e8ec6dae0d8886ebd60ee6
|
Subproject commit 972ff3237f819a2250e0bc1ca2814bafe328fa69
|
Loading…
x
Reference in New Issue
Block a user