Skip to content

Commit

Permalink
Unify share API
Browse files Browse the repository at this point in the history
  • Loading branch information
Ste Prescott committed May 17, 2020
1 parent a3547ea commit a40addc
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 33 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
/Packages
/*.xcodeproj
xcuserdata/
.swiftpm/
7 changes: 0 additions & 7 deletions .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

This file was deleted.

This file was deleted.

20 changes: 4 additions & 16 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,11 @@ import PackageDescription
let package = Package(
name: "Share",
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "Share",
targets: ["Share"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.library(name: "Share", targets: ["Share"]),
],
dependencies: [ ],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "Share",
dependencies: []),
.testTarget(
name: "ShareTests",
dependencies: ["Share"]),
.target(name: "Share", dependencies: []),
.testTarget(name: "ShareTests", dependencies: ["Share"]),
]
)
52 changes: 50 additions & 2 deletions Sources/Share/Share.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,51 @@
struct Share {
var text = "Hello, World!"
#if os(macOS)
import Cocoa
#elseif os(iOS)
import UIKit
#endif

public protocol Sharable {
var shareItems: [Any] { get }
}

public protocol ShareDelegate {
func didChange(status: Share.Service.Status)
}

public struct Share { }

extension Share {
#if os(macOS)
public typealias Service = NSSharingService
#elseif os(iOS)
public typealias Service = UIActivity.ActivityType
#endif
}

extension Share.Service {
public enum Status {
case willShare([Any], via: Share.Service)
case didShare([Any], via: Share.Service)
case error(Share.Service.Status.Error, sharing:[Any])
}
}

extension Share.Service.Status {
public enum Error {
case cancelled(Share.Service?)
case other(Swift.Error, with: Share.Service?)

var service: Share.Service? {
switch self {
case .cancelled(let service): return service
case .other(_, with: let service): return service
}
}
}
}

extension Sharable {
public func shareSheet(delegate: ShareDelegate? = nil) -> Share.Sheet {
return Share.Sheet(for: self, delegate: delegate)
}
}
85 changes: 85 additions & 0 deletions Sources/Share/Sheet.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#if os(macOS)
import Cocoa

extension Share {
public class Sheet: NSSharingServicePicker, NSSharingServicePickerDelegate, NSSharingServiceDelegate {
let sharable: Sharable
let serviceDelegate: ShareDelegate?

private override init(items: [Any]) { fatalError("This is private") }

public init(for sharable: Sharable, delegate: ShareDelegate? = nil) {
self.sharable = sharable
serviceDelegate = delegate
super.init(items: sharable.shareItems)
}

// MARK:- NSSharingServicePickerDelegate
public func sharingServicePicker(_ sharingServicePicker: NSSharingServicePicker, didChoose service: NSSharingService?) {
guard service == nil
else { return }

serviceDelegate?.didChange(status: .error(.cancelled(service), sharing: sharable.shareItems))
}

public func sharingServicePicker(_ sharingServicePicker: NSSharingServicePicker, delegateFor sharingService: NSSharingService) -> NSSharingServiceDelegate? {
return self
}

// MARK:- NSSharingServiceDelegate

public func sharingService(_ sharingService: NSSharingService, willShareItems items: [Any]) {
serviceDelegate?.didChange(status: .willShare(items, via: sharingService))
}

public func sharingService(_ sharingService: NSSharingService, didShareItems items: [Any]) {
serviceDelegate?.didChange(status: .didShare(items, via: sharingService))
}

public func sharingService(_ sharingService: NSSharingService, didFailToShareItems items: [Any], error: Error) {
serviceDelegate?.didChange(status: .error(.other(error, with: sharingService), sharing: items))
}
}
}
#endif

#if os(iOS)
import UIKit

extension Share {
public class Sheet: UIActivityViewController {
let sharable: Sharable
let serviceDelegate: ShareDelegate?

public init(for sharable: Sharable, delegate: ShareDelegate? = nil) {
self.sharable = sharable
serviceDelegate = delegate

super.init(activityItems: sharable.shareItems, applicationActivities: nil)

completionWithItemsHandler = {(activityType: UIActivity.ActivityType?, completed: Bool, returnedItems:[Any]?, error: Error?) in
guard let service = activityType
else { self.report(error: .cancelled(activityType)); return }

if let error = error {
self.report(error: .other(error, with: service)); return
}

if !completed {
self.report(.willShare(sharable.shareItems, via: service))
} else {
self.report(.didShare(sharable.shareItems, via: service))
}
}
}

private func report(_ status: Share.Service.Status) {
serviceDelegate?.didChange(status: status)
}

private func report(error: Share.Service.Status.Error) {
serviceDelegate?.didChange(status: .error(error, sharing: sharable.shareItems))
}
}
}
#endif

0 comments on commit a40addc

Please sign in to comment.