Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Ensure the share extension shows the correct details #697

Merged
merged 1 commit into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/Sources/BookmarksCore/Pinboard/Pinboard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ public class Pinboard {
}
}

func postsGet(url: URL) async throws -> Posts {
public func postsGet(url: URL) async throws -> Posts {
let requestURL = endpoint(for: .postsGet)
.appending(queryItems: [
URLQueryItem(name: "url", value: url.absoluteString)
Expand Down
2 changes: 1 addition & 1 deletion core/Sources/BookmarksCore/Pinboard/Post.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ extension Pinboard {
meta: String = "",
shared: Bool = true,
tags: [String] = [],
time: Date = Date(),
time: Date? = Date(),
toRead: Bool = false) {
self.href = href
self.description = description
Expand Down
8 changes: 4 additions & 4 deletions core/Sources/BookmarksCore/Pinboard/Posts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ import Foundation

extension Pinboard {

struct Posts: Codable {
public struct Posts: Codable {

let date: Date
let user: String
let posts: [Post]
public let date: Date
public let user: String
public let posts: [Post]

}

Expand Down
37 changes: 0 additions & 37 deletions ios/Bookmarks Share Extension/Extensions/NSItemProvider.swift

This file was deleted.

93 changes: 34 additions & 59 deletions ios/Bookmarks Share Extension/Model/ShareExtensionModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,92 +26,67 @@ import Interact

import BookmarksCore

protocol ShareExtensionDataSource: NSObject {

var extensionContext: NSExtensionContext? { get }

}

// TODO: MainActor assertions
class ShareExtensionModel: ObservableObject, Runnable {

static let shared = ShareExtensionModel()

@Published var items: [NSExtensionItem] = []
@MainActor @Published var urls: [URL] = []
@MainActor @Published var url: URL? = nil
@MainActor @Published var error: Error? = nil
@MainActor @Published var post: Pinboard.Post? = nil

@MainActor private var cancellables: Set<AnyCancellable> = []

let pinboard: Pinboard? = {
weak var dataSource: ShareExtensionDataSource? = nil

var pinboard: Pinboard? {
let settings = Settings()
guard let apiKey = settings.pinboardApiKey else {
return nil
}
return Pinboard(token: apiKey)
}()

@MainActor var extensionContext: NSExtensionContext? = nil {
didSet {
dispatchPrecondition(condition: .onQueue(.main))
guard let extensionItems = extensionContext?.inputItems as? [NSExtensionItem] else {
return
}
urls = []
extensionItems
.compactMap { $0.attachments }
.reduce([], +)
.filter { $0.hasItemConformingToTypeIdentifier(UTType.url.identifier) }
.forEach { itemProvider in
itemProvider.loadItem(forTypeIdentifier: UTType.url.identifier) { object, error in
DispatchQueue.main.async { [weak self] in
guard let self else {
return
}
guard let url = object as? URL else {
return
}
self.urls.append(url)
}
}
}
}
}

init() {

}

@MainActor func start() {

// Get the first URL.
$urls
.map { $0.first }
.receive(on: DispatchQueue.main)
.assign(to: \.url, on: self)
.store(in: &cancellables)

// Create the post with initial values.
$url
.compactMap { $0 }
.asyncMap { url in
do {
let title = try await url.title()
return Pinboard.Post(href: url, description: title ?? "")
} catch {
print("Failed to get contents with error \(error).")
// TODO:
return nil
@MainActor func load() {
dispatchPrecondition(condition: .onQueue(.main))
guard let extensionItem = dataSource?.extensionContext?.inputItems.first as? NSExtensionItem,
let attachment = extensionItem.attachments?.first
else {
return
}
Task {
guard let url = try await attachment.loadItem(forTypeIdentifier: UTType.url.identifier) as? URL else {
return
}
if let post = try await pinboard?.postsGet(url: url).posts.first {
await MainActor.run {
self.post = post
}
} else {
let title = try await url.title() ?? ""
await MainActor.run {
self.post = Pinboard.Post(href: url, description: title, time: nil)
}
}
.assign(to: \.post, on: self)
.store(in: &cancellables)
}
}

@MainActor func start() {

}

@MainActor func stop() {
cancellables.removeAll()
}


// TODO: Get the page title; can I do this from the share item?

@MainActor func save(toRead: Bool = false) {
guard let pinboard,
var post else {
Expand All @@ -134,11 +109,11 @@ class ShareExtensionModel: ObservableObject, Runnable {
}

@MainActor func dismiss() {
extensionContext?.completeRequest(returningItems: nil)
dataSource?.extensionContext?.completeRequest(returningItems: nil)
}

@MainActor func cancel() {
extensionContext?.cancelRequest(withError: CancellationError())
dataSource?.extensionContext?.cancelRequest(withError: CancellationError())
}

}
15 changes: 10 additions & 5 deletions ios/Bookmarks Share Extension/ShareViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,20 @@
import SwiftUI
import UIKit

class ShareViewController: UIHostingController<RootView> {
class ShareViewController: UIHostingController<RootView>, ShareExtensionDataSource {

let extensionModel: ShareExtensionModel

required init?(coder aDecoder: NSCoder) {
super.init(rootView: RootView(extensionModel: ShareExtensionModel.shared))
let extensionModel = ShareExtensionModel()
self.extensionModel = extensionModel
super.init(rootView: RootView(extensionModel: extensionModel))
extensionModel.dataSource = self
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
ShareExtensionModel.shared.extensionContext = extensionContext
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
extensionModel.load()
}

}
41 changes: 21 additions & 20 deletions ios/Bookmarks Share Extension/Views/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,34 @@ struct ContentView: View {
@EnvironmentObject var extensionModel: ShareExtensionModel

var body: some View {
List {
VStack {
if let post = Binding($extensionModel.post) {
EditorView(post: post)
}
}
.safeAreaInset(edge: .bottom) {
VStack {
Button {
extensionModel.save()
} label: {
Text("Save")
.frame(maxWidth: .infinity)
List {
EditorView(post: post)
}
.buttonStyle(.borderedProminent)
Button {
extensionModel.save(toRead: true)
} label: {
Text("Read Later")
.frame(maxWidth: .infinity)
} else {
PlaceholderView {
ProgressView()
}
.buttonStyle(.bordered)
}
.controlSize(.large)
.padding()
}
.navigationTitle("Add Bookmark")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Menu {
Button("Read Later") {
extensionModel.save(toRead: true)
}
}
label: {
Text("Save")
} primaryAction: {
extensionModel.save()
}
.disabled(extensionModel.post == nil)
}
}
.dismissable(.cancel) {
extensionModel.dismiss()
}
Expand Down
14 changes: 14 additions & 0 deletions ios/Bookmarks Share Extension/Views/EditorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ struct EditorView: View {
return []
}
}
if let url = post.href {
Section {
Link(destination: url) {
Text(url.absoluteString)
.multilineTextAlignment(.leading)
}
} header: {

} footer: {
if let time = post.time {
Text("Created \(time.formatted())")
}
}
}
}

}
2 changes: 1 addition & 1 deletion ios/Bookmarks Share Extension/Views/RootView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ struct RootView: View {
@ObservedObject var extensionModel: ShareExtensionModel

var body: some View {
NavigationView {
NavigationStack {
ContentView()
.environmentObject(extensionModel)
}
Expand Down
12 changes: 0 additions & 12 deletions ios/Bookmarks-iOS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
D889F9282A4E19A6000B0AA8 /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D889F9272A4E19A6000B0AA8 /* RootView.swift */; };
D889F92B2A4E19EC000B0AA8 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D889F92A2A4E19EC000B0AA8 /* ContentView.swift */; };
D889F92E2A4E1A29000B0AA8 /* ShareExtensionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D889F92D2A4E1A29000B0AA8 /* ShareExtensionModel.swift */; };
D889F9312A4E1A6E000B0AA8 /* NSItemProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D889F9302A4E1A6E000B0AA8 /* NSItemProvider.swift */; };
D889F9332A4E347B000B0AA8 /* EditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D889F9322A4E347B000B0AA8 /* EditorView.swift */; };
D89CF2132A4DE8B5000E2B1C /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D89CF2122A4DE8B5000E2B1C /* ShareViewController.swift */; };
D89CF2162A4DE8B5000E2B1C /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D89CF2142A4DE8B5000E2B1C /* MainInterface.storyboard */; };
Expand Down Expand Up @@ -74,7 +73,6 @@
D889F9272A4E19A6000B0AA8 /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = "<group>"; };
D889F92A2A4E19EC000B0AA8 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
D889F92D2A4E1A29000B0AA8 /* ShareExtensionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareExtensionModel.swift; sourceTree = "<group>"; };
D889F9302A4E1A6E000B0AA8 /* NSItemProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSItemProvider.swift; sourceTree = "<group>"; };
D889F9322A4E347B000B0AA8 /* EditorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditorView.swift; sourceTree = "<group>"; };
D89C65E326AF5A8E00D49D11 /* Common.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Common.xcconfig; sourceTree = "<group>"; };
D89C65E426AF5A8E00D49D11 /* Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
Expand Down Expand Up @@ -176,21 +174,12 @@
path = Model;
sourceTree = "<group>";
};
D889F92F2A4E1A54000B0AA8 /* Extensions */ = {
isa = PBXGroup;
children = (
D889F9302A4E1A6E000B0AA8 /* NSItemProvider.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
D89CF2112A4DE8B5000E2B1C /* Bookmarks Share Extension */ = {
isa = PBXGroup;
children = (
D89CF2212A4E1144000E2B1C /* Bookmarks Share Extension.entitlements */,
D89CF2172A4DE8B5000E2B1C /* Info.plist */,
D89CF2122A4DE8B5000E2B1C /* ShareViewController.swift */,
D889F92F2A4E1A54000B0AA8 /* Extensions */,
D89CF2142A4DE8B5000E2B1C /* MainInterface.storyboard */,
D889F92C2A4E1A16000B0AA8 /* Model */,
D889F9292A4E19CC000B0AA8 /* Views */,
Expand Down Expand Up @@ -431,7 +420,6 @@
buildActionMask = 2147483647;
files = (
D889F9282A4E19A6000B0AA8 /* RootView.swift in Sources */,
D889F9312A4E1A6E000B0AA8 /* NSItemProvider.swift in Sources */,
D889F92E2A4E1A29000B0AA8 /* ShareExtensionModel.swift in Sources */,
D889F9332A4E347B000B0AA8 /* EditorView.swift in Sources */,
D89CF2132A4DE8B5000E2B1C /* ShareViewController.swift in Sources */,
Expand Down