mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Implement share/activity button on iOS
This commit is contained in:
@@ -11,6 +11,7 @@ import SwiftUI
|
||||
struct ArticleToolbarModifier: ViewModifier {
|
||||
|
||||
@EnvironmentObject private var sceneModel: SceneModel
|
||||
@State private var showActivityView = false
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
@@ -98,11 +99,17 @@ struct ArticleToolbarModifier: ViewModifier {
|
||||
|
||||
ToolbarItem(placement: .bottomBar) {
|
||||
Button {
|
||||
showActivityView.toggle()
|
||||
} label: {
|
||||
AppAssets.shareImage.font(.title3)
|
||||
}
|
||||
.disabled(sceneModel.shareButtonState == nil)
|
||||
.help("Share")
|
||||
.sheet(isPresented: $showActivityView) {
|
||||
if let article = sceneModel.selectedArticles.first, let link = article.preferredLink, let url = URL(string: link) {
|
||||
ActivityViewController(title: article.title, url: url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,6 +24,10 @@ final class SceneModel: ObservableObject {
|
||||
@Published var openInBrowserButtonState: Bool?
|
||||
@Published var shareButtonState: Bool?
|
||||
|
||||
var selectedArticles: [Article] {
|
||||
timelineModel.selectedArticles
|
||||
}
|
||||
|
||||
private var refreshProgressModel: RefreshProgressModel? = nil
|
||||
private var articleIconSchemeHandler: ArticleIconSchemeHandler? = nil
|
||||
|
||||
|
||||
33
Multiplatform/iOS/Article/ActivityViewController.swift
Normal file
33
Multiplatform/iOS/Article/ActivityViewController.swift
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// ArticleShareView.swift
|
||||
// Multiplatform iOS
|
||||
//
|
||||
// Created by Maurice Parker on 7/13/20.
|
||||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
import Articles
|
||||
|
||||
extension UIActivityViewController {
|
||||
convenience init(url: URL, title: String?, applicationActivities: [UIActivity]?) {
|
||||
let itemSource = ArticleActivityItemSource(url: url, subject: title)
|
||||
let titleSource = TitleActivityItemSource(title: title)
|
||||
self.init(activityItems: [titleSource, itemSource], applicationActivities: applicationActivities)
|
||||
}
|
||||
}
|
||||
|
||||
struct ActivityViewController: UIViewControllerRepresentable {
|
||||
|
||||
var title: String?
|
||||
var url: URL
|
||||
|
||||
func makeUIViewController(context: Context) -> UIActivityViewController {
|
||||
return UIActivityViewController(url: url, title: title, applicationActivities: [FindInArticleActivity(), OpenInSafariActivity()])
|
||||
}
|
||||
|
||||
func updateUIViewController(_ controller: UIActivityViewController, context: Context) {
|
||||
}
|
||||
|
||||
}
|
||||
33
Multiplatform/iOS/Article/ArticleActivityItemSource.swift
Normal file
33
Multiplatform/iOS/Article/ArticleActivityItemSource.swift
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// ArticleActivityItemSource.swift
|
||||
// Multiplatform iOS
|
||||
//
|
||||
// Created by Maurice Parker on 7/13/20.
|
||||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class ArticleActivityItemSource: NSObject, UIActivityItemSource {
|
||||
|
||||
private let url: URL
|
||||
private let subject: String?
|
||||
|
||||
init(url: URL, subject: String?) {
|
||||
self.url = url
|
||||
self.subject = subject
|
||||
}
|
||||
|
||||
func activityViewControllerPlaceholderItem(_ : UIActivityViewController) -> Any {
|
||||
return url
|
||||
}
|
||||
|
||||
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
|
||||
return url
|
||||
}
|
||||
|
||||
func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivity.ActivityType?) -> String {
|
||||
return subject ?? ""
|
||||
}
|
||||
|
||||
}
|
||||
@@ -156,3 +156,8 @@ private extension ArticleViewController {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public extension Notification.Name {
|
||||
static let FindInArticle = Notification.Name("FindInArticle")
|
||||
static let EndFindInArticle = Notification.Name("EndFindInArticle")
|
||||
}
|
||||
|
||||
40
Multiplatform/iOS/Article/FindInArticleActivity.swift
Normal file
40
Multiplatform/iOS/Article/FindInArticleActivity.swift
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// FindInArticleActivity.swift
|
||||
// NetNewsWire-iOS
|
||||
//
|
||||
// Created by Brian Sanders on 5/7/20.
|
||||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FindInArticleActivity: UIActivity {
|
||||
override var activityTitle: String? {
|
||||
NSLocalizedString("Find in Article", comment: "Find in Article")
|
||||
}
|
||||
|
||||
override var activityType: UIActivity.ActivityType? {
|
||||
UIActivity.ActivityType(rawValue: "com.ranchero.NetNewsWire.find")
|
||||
}
|
||||
|
||||
override var activityImage: UIImage? {
|
||||
UIImage(systemName: "magnifyingglass", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular))
|
||||
}
|
||||
|
||||
override class var activityCategory: UIActivity.Category {
|
||||
.action
|
||||
}
|
||||
|
||||
override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
override func prepare(withActivityItems activityItems: [Any]) {
|
||||
|
||||
}
|
||||
|
||||
override func perform() {
|
||||
NotificationCenter.default.post(Notification(name: .FindInArticle))
|
||||
activityDidFinish(true)
|
||||
}
|
||||
}
|
||||
49
Multiplatform/iOS/Article/OpenInSafariActivity.swift
Normal file
49
Multiplatform/iOS/Article/OpenInSafariActivity.swift
Normal file
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// OpenInSafariActivity.swift
|
||||
// Multiplatform iOS
|
||||
//
|
||||
// Created by Maurice Parker on 7/13/20.
|
||||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class OpenInSafariActivity: UIActivity {
|
||||
|
||||
private var activityItems: [Any]?
|
||||
|
||||
override var activityTitle: String? {
|
||||
return NSLocalizedString("Open in Safari", comment: "Open in Safari")
|
||||
}
|
||||
|
||||
override var activityImage: UIImage? {
|
||||
return UIImage(systemName: "safari", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular))
|
||||
}
|
||||
|
||||
override var activityType: UIActivity.ActivityType? {
|
||||
return UIActivity.ActivityType(rawValue: "com.rancharo.NetNewsWire-Evergreen.safari")
|
||||
}
|
||||
|
||||
override class var activityCategory: UIActivity.Category {
|
||||
return .action
|
||||
}
|
||||
|
||||
override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
override func prepare(withActivityItems activityItems: [Any]) {
|
||||
self.activityItems = activityItems
|
||||
}
|
||||
|
||||
override func perform() {
|
||||
guard let url = activityItems?.first(where: { $0 is URL }) as? URL else {
|
||||
activityDidFinish(false)
|
||||
return
|
||||
}
|
||||
|
||||
UIApplication.shared.open(url, options: [:], completionHandler: nil)
|
||||
activityDidFinish(true)
|
||||
}
|
||||
|
||||
}
|
||||
40
Multiplatform/iOS/Article/TitleActivityItemSource.swift
Normal file
40
Multiplatform/iOS/Article/TitleActivityItemSource.swift
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// TitleActivityItemSource.swift
|
||||
// Multiplatform iOS
|
||||
//
|
||||
// Created by Maurice Parker on 7/13/20.
|
||||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class TitleActivityItemSource: NSObject, UIActivityItemSource {
|
||||
|
||||
private let title: String?
|
||||
|
||||
init(title: String?) {
|
||||
self.title = title
|
||||
}
|
||||
|
||||
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
|
||||
return title as Any
|
||||
}
|
||||
|
||||
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
|
||||
guard let activityType = activityType,
|
||||
let title = title else {
|
||||
return NSNull()
|
||||
}
|
||||
|
||||
switch activityType.rawValue {
|
||||
case "com.omnigroup.OmniFocus3.iOS.QuickEntry",
|
||||
"com.culturedcode.ThingsiPhone.ShareExtension",
|
||||
"com.tapbots.Tweetbot4.shareextension",
|
||||
"com.buffer.buffer.Buffer":
|
||||
return title
|
||||
default:
|
||||
return NSNull()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user