mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Fix lint issues.
This commit is contained in:
@@ -34,4 +34,3 @@ public extension Int {
|
||||
return UInt32(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ public struct KeyboardKey: Hashable {
|
||||
|
||||
var integerValue = 0
|
||||
|
||||
switch(s) {
|
||||
switch s {
|
||||
case "[space]":
|
||||
integerValue = " ".keyboardIntegerValue!
|
||||
case "[uparrow]":
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
#if os(macOS)
|
||||
import AppKit
|
||||
|
||||
//let keypadEnter: unichar = 3
|
||||
// let keypadEnter: unichar = 3
|
||||
|
||||
@objc public protocol KeyboardDelegate: AnyObject {
|
||||
|
||||
|
||||
// Return true if handled.
|
||||
func keydown(_: NSEvent, in view: NSView) -> Bool
|
||||
}
|
||||
|
||||
@@ -69,8 +69,7 @@ public extension NSOutlineView {
|
||||
selectRowAndScrollToVisible(row)
|
||||
return
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return // if there are no more items, we’re out of rows
|
||||
}
|
||||
}
|
||||
@@ -180,4 +179,3 @@ public extension NSOutlineView {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -9,22 +9,21 @@
|
||||
import AppKit
|
||||
|
||||
public extension NSResponder {
|
||||
|
||||
|
||||
func hasAncestor(_ ancestor: NSResponder) -> Bool {
|
||||
|
||||
|
||||
var nomad: NSResponder = self
|
||||
while(true) {
|
||||
while true {
|
||||
if nomad === ancestor {
|
||||
return true
|
||||
}
|
||||
if let _ = nomad.nextResponder {
|
||||
nomad = nomad.nextResponder!
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
import AppKit
|
||||
|
||||
public extension NSTableView {
|
||||
|
||||
|
||||
var selectionIsEmpty: Bool {
|
||||
return selectedRowIndexes.startIndex == selectedRowIndexes.endIndex
|
||||
}
|
||||
|
||||
|
||||
func indexesOfAvailableRowsPassingTest(_ test: (Int) -> Bool) -> IndexSet? {
|
||||
|
||||
// Checks visible and in-flight rows.
|
||||
@@ -43,12 +43,12 @@ public extension NSTableView {
|
||||
let documentVisibleRect = scrollView.documentVisibleRect
|
||||
|
||||
let r = rect(ofRow: row)
|
||||
if NSContainsRect(documentVisibleRect, r) {
|
||||
if documentVisibleRect.contains(r) {
|
||||
return
|
||||
}
|
||||
|
||||
let rMidY = NSMidY(r)
|
||||
var scrollPoint = NSZeroPoint;
|
||||
let rMidY = r.midY
|
||||
var scrollPoint = NSPoint.zero
|
||||
scrollPoint.y = floor(rMidY - (documentVisibleRect.size.height / 2.0)) + CGFloat(extraHeight)
|
||||
scrollPoint.y = max(scrollPoint.y, 0)
|
||||
|
||||
@@ -57,7 +57,7 @@ public extension NSTableView {
|
||||
|
||||
let clipView = scrollView.contentView
|
||||
|
||||
let rClipView = NSMakeRect(scrollPoint.x, scrollPoint.y, NSWidth(clipView.bounds), NSHeight(clipView.bounds))
|
||||
let rClipView = NSRect(x: scrollPoint.x, y: scrollPoint.y, width: clipView.bounds.width, height: clipView.bounds.height)
|
||||
|
||||
clipView.animator().bounds = rClipView
|
||||
}
|
||||
|
||||
@@ -9,16 +9,16 @@
|
||||
import AppKit
|
||||
|
||||
extension NSView {
|
||||
|
||||
|
||||
public func asImage() -> NSImage {
|
||||
let rep = bitmapImageRepForCachingDisplay(in: bounds)!
|
||||
cacheDisplay(in: bounds, to: rep)
|
||||
|
||||
|
||||
let img = NSImage(size: bounds.size)
|
||||
img.addRepresentation(rep)
|
||||
return img
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public extension NSView {
|
||||
|
||||
@@ -13,11 +13,11 @@ public class RSAppMovementMonitor: NSObject {
|
||||
|
||||
// If provided, the handler will be consulted when the app is moved.
|
||||
// Return true to indicate that the default handler should be invoked.
|
||||
public var appMovementHandler: ((RSAppMovementMonitor) -> Bool)? = nil
|
||||
public var appMovementHandler: ((RSAppMovementMonitor) -> Bool)?
|
||||
|
||||
// DispatchSource offers a monitoring mechanism based on an open file descriptor
|
||||
var fileDescriptor: Int32 = -1
|
||||
var dispatchSource: DispatchSourceFileSystemObject? = nil
|
||||
var dispatchSource: DispatchSourceFileSystemObject?
|
||||
|
||||
// Save the original location of the app in a file reference URL, which will track its new location.
|
||||
// Note this is NSURL, not URL, because file reference URLs violate value-type assumptions of URL.
|
||||
@@ -77,7 +77,7 @@ public class RSAppMovementMonitor: NSObject {
|
||||
// every time the app becomes active. This catches a good number of edge-case
|
||||
// changes to the app bundle's path, such as when a containing folder or the
|
||||
// volume name changes.
|
||||
NotificationCenter.default.addObserver(forName: NSApplication.didBecomeActiveNotification, object: nil, queue: nil) { notification in
|
||||
NotificationCenter.default.addObserver(forName: NSApplication.didBecomeActiveNotification, object: nil, queue: nil) { _ in
|
||||
// Removing observer in invalidate doesn't seem to prevent this getting called? Maybe
|
||||
// because it's on the same invocation of the runloop?
|
||||
if self.isValid() && self.originalAppURL != self.appTrackingURL?.absoluteURL {
|
||||
@@ -130,7 +130,7 @@ public class RSAppMovementMonitor: NSObject {
|
||||
// at the given URL with the "new instance" option to prevent it simply reactivating us.
|
||||
let configuration = NSWorkspace.OpenConfiguration()
|
||||
configuration.createsNewApplicationInstance = true
|
||||
NSWorkspace.shared.openApplication(at: appURL, configuration: configuration) { _,_ in
|
||||
NSWorkspace.shared.openApplication(at: appURL, configuration: configuration) { _, _ in
|
||||
NSApp.terminate(self)
|
||||
}
|
||||
}
|
||||
@@ -139,7 +139,7 @@ public class RSAppMovementMonitor: NSObject {
|
||||
let quitAlert = NSAlert()
|
||||
quitAlert.alertStyle = .critical
|
||||
quitAlert.addButton(withTitle: self.alertRelaunchButtonText)
|
||||
|
||||
|
||||
quitAlert.messageText = self.alertMessageText
|
||||
quitAlert.informativeText = self.alertInformativeText
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ private extension RSToolbarItem {
|
||||
return false
|
||||
}
|
||||
|
||||
while(true) {
|
||||
while true {
|
||||
if let validated = validateWithResponder(responder!) {
|
||||
return validated
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@ import AppKit
|
||||
public final class UserApp {
|
||||
|
||||
public let bundleID: String
|
||||
public var icon: NSImage? = nil
|
||||
public var icon: NSImage?
|
||||
public var existsOnDisk = false
|
||||
public var path: String? = nil
|
||||
public var runningApplication: NSRunningApplication? = nil
|
||||
public var path: String?
|
||||
public var runningApplication: NSRunningApplication?
|
||||
|
||||
public var isRunning: Bool {
|
||||
|
||||
@@ -47,8 +47,7 @@ public final class UserApp {
|
||||
if app == runningApplication {
|
||||
break
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if !app.isTerminated {
|
||||
runningApplication = app
|
||||
break
|
||||
@@ -61,8 +60,7 @@ public final class UserApp {
|
||||
icon = runningApplication.icon
|
||||
if let bundleURL = runningApplication.bundleURL {
|
||||
path = bundleURL.path
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
path = NSWorkspace.shared.urlForApplication(withBundleIdentifier: bundleID)?.path
|
||||
}
|
||||
if icon == nil, let path = path {
|
||||
@@ -77,8 +75,7 @@ public final class UserApp {
|
||||
icon = NSWorkspace.shared.icon(forFile: path)
|
||||
}
|
||||
existsOnDisk = true
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
existsOnDisk = false
|
||||
icon = nil
|
||||
}
|
||||
@@ -146,4 +143,3 @@ public final class UserApp {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ public extension Array {
|
||||
Array(self[$0 ..< Swift.min($0 + size, count)])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public extension Array where Element: Equatable {
|
||||
|
||||
@@ -23,7 +23,7 @@ public final class BatchUpdate {
|
||||
|
||||
/// The shared batch update object.
|
||||
public static let shared = BatchUpdate()
|
||||
|
||||
|
||||
private var count = 0
|
||||
|
||||
/// Is updating in progress?
|
||||
@@ -50,15 +50,15 @@ public final class BatchUpdate {
|
||||
public func end() {
|
||||
precondition(Thread.isMainThread)
|
||||
decrementCount()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension BatchUpdate {
|
||||
|
||||
|
||||
func incrementCount() {
|
||||
count = count + 1
|
||||
}
|
||||
|
||||
|
||||
func decrementCount() {
|
||||
count = count - 1
|
||||
if count < 1 {
|
||||
@@ -67,7 +67,7 @@ private extension BatchUpdate {
|
||||
postBatchUpdateDidPerform()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func postBatchUpdateDidPerform() {
|
||||
if !Thread.isMainThread {
|
||||
DispatchQueue.main.sync {
|
||||
@@ -77,5 +77,5 @@ private extension BatchUpdate {
|
||||
NotificationCenter.default.post(name: .BatchUpdateDidPerform, object: nil, userInfo: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -39,23 +39,19 @@ public struct BinaryDiskCache {
|
||||
get {
|
||||
do {
|
||||
return try data(forKey: key)
|
||||
}
|
||||
catch {}
|
||||
} catch {}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
set {
|
||||
if let data = newValue {
|
||||
do {
|
||||
try setData(data, forKey: key)
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
else {
|
||||
} catch {}
|
||||
} else {
|
||||
do {
|
||||
try deleteData(forKey: key)
|
||||
}
|
||||
catch{}
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,5 +26,5 @@ public extension Calendar {
|
||||
static var startOfToday: Date {
|
||||
cached.startOfDay(for: Date())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
|
||||
public extension Character {
|
||||
|
||||
|
||||
var isSimpleEmoji: Bool {
|
||||
guard let firstScalar = unicodeScalars.first else { return false }
|
||||
return firstScalar.properties.isEmoji && firstScalar.value > 0x238C
|
||||
|
||||
@@ -13,16 +13,16 @@ import CloudKit
|
||||
public class CloudKitError: LocalizedError {
|
||||
|
||||
public let error: Error
|
||||
|
||||
|
||||
public init(_ error: Error) {
|
||||
self.error = error
|
||||
}
|
||||
|
||||
|
||||
public var errorDescription: String? {
|
||||
guard let ckError = error as? CKError else {
|
||||
return error.localizedDescription
|
||||
}
|
||||
|
||||
|
||||
switch ckError.code {
|
||||
case .alreadyShared:
|
||||
return NSLocalizedString("Already Shared: a record or share cannot be saved because doing so would cause the same hierarchy of records to exist in multiple shares.", comment: "Known iCloud Error")
|
||||
@@ -94,5 +94,5 @@ public class CloudKitError: LocalizedError {
|
||||
return NSLocalizedString("Unhandled Error.", comment: "Unknown iCloud Error")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public enum CloudKitZoneError: LocalizedError {
|
||||
}
|
||||
|
||||
public protocol CloudKitZoneDelegate: AnyObject {
|
||||
func cloudKitDidModify(changed: [CKRecord], deleted: [CloudKitRecordKey], completion: @escaping (Result<Void, Error>) -> Void);
|
||||
func cloudKitDidModify(changed: [CKRecord], deleted: [CloudKitRecordKey], completion: @escaping (Result<Void, Error>) -> Void)
|
||||
}
|
||||
|
||||
public typealias CloudKitRecordKey = (recordType: CKRecord.RecordType, recordID: CKRecord.ID)
|
||||
@@ -54,7 +54,7 @@ public protocol CloudKitZone: AnyObject {
|
||||
func subscribeToZoneChanges()
|
||||
|
||||
/// Process a remove notification
|
||||
func receiveRemoteNotification(userInfo: [AnyHashable : Any], completion: @escaping () -> Void)
|
||||
func receiveRemoteNotification(userInfo: [AnyHashable: Any], completion: @escaping () -> Void)
|
||||
|
||||
}
|
||||
|
||||
@@ -111,21 +111,21 @@ public extension CloudKitZone {
|
||||
return CKRecord.ID(recordName: UUID().uuidString, zoneID: zoneID)
|
||||
}
|
||||
|
||||
func retryIfPossible(after: Double, block: @escaping () -> ()) {
|
||||
func retryIfPossible(after: Double, block: @escaping () -> Void) {
|
||||
let delayTime = DispatchTime.now() + after
|
||||
DispatchQueue.main.asyncAfter(deadline: delayTime, execute: {
|
||||
block()
|
||||
})
|
||||
}
|
||||
|
||||
func receiveRemoteNotification(userInfo: [AnyHashable : Any], completion: @escaping () -> Void) {
|
||||
func receiveRemoteNotification(userInfo: [AnyHashable: Any], completion: @escaping () -> Void) {
|
||||
let note = CKRecordZoneNotification(fromRemoteNotificationDictionary: userInfo)
|
||||
guard note?.recordZoneID?.zoneName == zoneID.zoneName else {
|
||||
completion()
|
||||
return
|
||||
}
|
||||
|
||||
fetchChangesInZone() { result in
|
||||
fetchChangesInZone { result in
|
||||
if case .failure(let error) = result {
|
||||
os_log(.error, log: self.log, "%@ zone remote notification fetch error: %@", self.zoneID.zoneName, error.localizedDescription)
|
||||
}
|
||||
@@ -140,7 +140,7 @@ public extension CloudKitZone {
|
||||
return
|
||||
}
|
||||
|
||||
database.save(CKRecordZone(zoneID: zoneID)) { (recordZone, error) in
|
||||
database.save(CKRecordZone(zoneID: zoneID)) { (_, error) in
|
||||
if let error = error {
|
||||
DispatchQueue.main.async {
|
||||
completion(.failure(CloudKitError(error)))
|
||||
@@ -211,7 +211,7 @@ public extension CloudKitZone {
|
||||
switch CloudKitZoneResult.resolve(error) {
|
||||
|
||||
case .zoneNotFound:
|
||||
self.createZoneRecord() { result in
|
||||
self.createZoneRecord { result in
|
||||
switch result {
|
||||
case .success:
|
||||
self.query(ckQuery, desiredKeys: desiredKeys, completion: completion)
|
||||
@@ -285,7 +285,7 @@ public extension CloudKitZone {
|
||||
switch CloudKitZoneResult.resolve(error) {
|
||||
|
||||
case .zoneNotFound:
|
||||
self.createZoneRecord() { result in
|
||||
self.createZoneRecord { result in
|
||||
switch result {
|
||||
case .success:
|
||||
self.query(cursor: cursor, desiredKeys: desiredKeys, carriedRecords: records, completion: completion)
|
||||
@@ -315,7 +315,6 @@ public extension CloudKitZone {
|
||||
database?.add(op)
|
||||
}
|
||||
|
||||
|
||||
/// Fetch a CKRecord by using its externalID
|
||||
func fetch(externalID: String?, completion: @escaping (Result<CKRecord, Error>) -> Void) {
|
||||
guard let externalID = externalID else {
|
||||
@@ -341,7 +340,7 @@ public extension CloudKitZone {
|
||||
}
|
||||
}
|
||||
case .zoneNotFound:
|
||||
self.createZoneRecord() { result in
|
||||
self.createZoneRecord { result in
|
||||
switch result {
|
||||
case .success:
|
||||
self.fetch(externalID: externalID, completion: completion)
|
||||
@@ -405,7 +404,7 @@ public extension CloudKitZone {
|
||||
}
|
||||
|
||||
case .zoneNotFound:
|
||||
self.createZoneRecord() { result in
|
||||
self.createZoneRecord { result in
|
||||
switch result {
|
||||
case .success:
|
||||
self.saveIfNew(records, completion: completion)
|
||||
@@ -473,7 +472,7 @@ public extension CloudKitZone {
|
||||
completion(.success((savedSubscription!)))
|
||||
}
|
||||
case .zoneNotFound:
|
||||
self.createZoneRecord() { result in
|
||||
self.createZoneRecord { result in
|
||||
switch result {
|
||||
case .success:
|
||||
self.save(subscription, completion: completion)
|
||||
@@ -666,7 +665,7 @@ public extension CloudKitZone {
|
||||
switch CloudKitZoneResult.resolve(error) {
|
||||
|
||||
case .zoneNotFound:
|
||||
self.createZoneRecord() { result in
|
||||
self.createZoneRecord { result in
|
||||
switch result {
|
||||
case .success:
|
||||
self.modify(recordsToSave: recordsToSave, recordIDsToDelete: recordIDsToDelete, completion: completion)
|
||||
@@ -727,7 +726,7 @@ public extension CloudKitZone {
|
||||
}
|
||||
}
|
||||
|
||||
saveChunks() { result in
|
||||
saveChunks { result in
|
||||
switch result {
|
||||
case .success:
|
||||
deleteChunks()
|
||||
@@ -763,11 +762,11 @@ public extension CloudKitZone {
|
||||
op.fetchAllChanges = true
|
||||
op.qualityOfService = Self.qualityOfService
|
||||
|
||||
op.recordZoneChangeTokensUpdatedBlock = { zoneID, token, _ in
|
||||
op.recordZoneChangeTokensUpdatedBlock = { _, token, _ in
|
||||
savedChangeToken = token
|
||||
}
|
||||
|
||||
op.recordWasChangedBlock = { recordID, result in
|
||||
op.recordWasChangedBlock = { _, result in
|
||||
if let record = try? result.get() {
|
||||
changedRecords.append(record)
|
||||
}
|
||||
@@ -778,7 +777,7 @@ public extension CloudKitZone {
|
||||
deletedRecordKeys.append(recordKey)
|
||||
}
|
||||
|
||||
op.recordZoneFetchResultBlock = { recordZoneID, result in
|
||||
op.recordZoneFetchResultBlock = { _, result in
|
||||
if let (token, _, _) = try? result.get() {
|
||||
savedChangeToken = token
|
||||
}
|
||||
@@ -809,7 +808,7 @@ public extension CloudKitZone {
|
||||
switch CloudKitZoneResult.resolve(error) {
|
||||
|
||||
case .zoneNotFound:
|
||||
self.createZoneRecord() { result in
|
||||
self.createZoneRecord { result in
|
||||
switch result {
|
||||
case .success:
|
||||
self.fetchChangesInZone(completion: completion)
|
||||
|
||||
@@ -19,15 +19,15 @@ public enum CloudKitZoneResult {
|
||||
case zoneNotFound
|
||||
case userDeletedZone
|
||||
case failure(error: Error)
|
||||
|
||||
|
||||
public static func resolve(_ error: Error?) -> CloudKitZoneResult {
|
||||
|
||||
|
||||
guard error != nil else { return .success }
|
||||
|
||||
|
||||
guard let ckError = error as? CKError else {
|
||||
return .failure(error: error!)
|
||||
}
|
||||
|
||||
|
||||
switch ckError.code {
|
||||
case .serviceUnavailable, .requestRateLimited, .zoneBusy:
|
||||
if let retry = ckError.userInfo[CKErrorRetryAfterKey] as? NSNumber {
|
||||
@@ -60,22 +60,22 @@ public enum CloudKitZoneResult {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private extension CloudKitZoneResult {
|
||||
|
||||
|
||||
static func anyRequestErrors(_ errors: [AnyHashable: CKError]) -> CloudKitZoneResult? {
|
||||
if errors.values.contains(where: { $0.code == .changeTokenExpired } ) {
|
||||
if errors.values.contains(where: { $0.code == .changeTokenExpired }) {
|
||||
return .changeTokenExpired
|
||||
}
|
||||
if errors.values.contains(where: { $0.code == .zoneNotFound } ) {
|
||||
if errors.values.contains(where: { $0.code == .zoneNotFound }) {
|
||||
return .zoneNotFound
|
||||
}
|
||||
if errors.values.contains(where: { $0.code == .userDeletedZone } ) {
|
||||
if errors.values.contains(where: { $0.code == .userDeletedZone }) {
|
||||
return .userDeletedZone
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ struct QueueCall: Equatable {
|
||||
|
||||
func perform() {
|
||||
|
||||
let _ = target?.perform(selector)
|
||||
_ = target?.perform(selector)
|
||||
}
|
||||
|
||||
static func ==(lhs: QueueCall, rhs: QueueCall) -> Bool {
|
||||
@@ -38,7 +38,7 @@ struct QueueCall: Equatable {
|
||||
private let interval: TimeInterval
|
||||
private let maxInterval: TimeInterval
|
||||
private var lastCallTime = Date.distantFuture
|
||||
private var timer: Timer? = nil
|
||||
private var timer: Timer?
|
||||
private var calls = [QueueCall]()
|
||||
|
||||
public init(name: String, interval: TimeInterval = 0.05, maxInterval: TimeInterval = 2.0) {
|
||||
@@ -63,12 +63,12 @@ struct QueueCall: Equatable {
|
||||
call.perform()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func timerDidFire(_ sender: Any?) {
|
||||
lastCallTime = Date()
|
||||
performCallsImmediately()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private extension CoalescingQueue {
|
||||
|
||||
@@ -16,7 +16,7 @@ extension Notification.Name {
|
||||
/// A type that provides a name for display to the user.
|
||||
|
||||
public protocol DisplayNameProvider {
|
||||
|
||||
|
||||
var nameForDisplay: String { get }
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import Foundation
|
||||
|
||||
public extension FileManager {
|
||||
|
||||
|
||||
/// Returns whether a path refers to a folder.
|
||||
///
|
||||
/// - Parameter path: The file path to check.
|
||||
@@ -82,7 +81,7 @@ public extension FileManager {
|
||||
guard let filenames = self.filenames(inFolder: folder) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
let url = URL(fileURLWithPath: folder)
|
||||
return filenames.map { url.appendingPathComponent($0).path }
|
||||
}
|
||||
@@ -101,7 +100,7 @@ private extension FileManager {
|
||||
assert(fileExists(atPath: source))
|
||||
|
||||
if fileExists(atPath: destination) {
|
||||
if (overwriting) {
|
||||
if overwriting {
|
||||
try removeItem(atPath: destination)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@ public extension CGRect {
|
||||
/// - Returns: A new rectangle, cenetered vertically in `containerRect`,
|
||||
/// with the same size as the source rectangle.
|
||||
func centeredVertically(in containerRect: CGRect) -> CGRect {
|
||||
var r = self;
|
||||
r.origin.y = containerRect.midY - (r.height / 2.0);
|
||||
r = r.integral;
|
||||
r.size = self.size;
|
||||
return r;
|
||||
var r = self
|
||||
r.origin.y = containerRect.midY - (r.height / 2.0)
|
||||
r = r.integral
|
||||
r.size = self.size
|
||||
return r
|
||||
}
|
||||
|
||||
/// Centers a rectangle horizontally in another rectangle.
|
||||
@@ -29,11 +29,11 @@ public extension CGRect {
|
||||
/// - Returns: A new rectangle, cenetered horizontally in `containerRect`,
|
||||
/// with the same size as the source rectangle.
|
||||
func centeredHorizontally(in containerRect: CGRect) -> CGRect {
|
||||
var r = self;
|
||||
r.origin.x = containerRect.midX - (r.width / 2.0);
|
||||
r = r.integral;
|
||||
r.size = self.size;
|
||||
return r;
|
||||
var r = self
|
||||
r.origin.x = containerRect.midX - (r.width / 2.0)
|
||||
r = r.integral
|
||||
r.size = self.size
|
||||
return r
|
||||
}
|
||||
|
||||
/// Centers a rectangle in another rectangle.
|
||||
|
||||
@@ -89,8 +89,7 @@ public extension MainThreadOperation {
|
||||
}
|
||||
if Thread.isMainThread {
|
||||
operationDelegate?.operationDidComplete(self)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
self.informOperationDelegateOfCompletion()
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ public final class MainThreadOperationQueue {
|
||||
/// those operations will be canceled also.
|
||||
public func cancelOperations(_ operations: [MainThreadOperation]) {
|
||||
precondition(Thread.isMainThread)
|
||||
let operationIDsToCancel = operations.map{ ensureOperationID($0) }
|
||||
let operationIDsToCancel = operations.map { ensureOperationID($0) }
|
||||
assert(allOperationIDsArePendingOrCurrent(operationIDsToCancel))
|
||||
assert(allOperationIDsAreInStorage(operationIDsToCancel))
|
||||
|
||||
@@ -182,8 +182,7 @@ private extension MainThreadOperationQueue {
|
||||
|
||||
if operation.isCanceled {
|
||||
dependencies.operationIDWasCanceled(operationID)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
dependencies.operationIDDidComplete(operationID)
|
||||
}
|
||||
|
||||
@@ -249,7 +248,7 @@ private extension MainThreadOperationQueue {
|
||||
guard !operationIDs.isEmpty else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let operationIDsToCancel = operationIDsByAddingChildOperationIDs(operationIDs)
|
||||
setCanceledAndRemoveDelegate(for: operationIDsToCancel)
|
||||
callCompletionBlockForOperationIDs(operationIDsToCancel)
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
@preconcurrency import Foundation
|
||||
|
||||
public final class ManagedResourceFile: NSObject, NSFilePresenter {
|
||||
|
||||
|
||||
private var isDirty = false {
|
||||
didSet {
|
||||
queueSaveToDiskIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private var isLoading = false
|
||||
private let fileURL: URL
|
||||
private let operationQueue: OperationQueue
|
||||
@@ -30,63 +30,63 @@ public final class ManagedResourceFile: NSObject, NSFilePresenter {
|
||||
saveQueue = CoalescingQueue(name: "ManagedResourceFile Save Queue", interval: saveInterval)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public var presentedItemURL: URL? {
|
||||
return fileURL
|
||||
}
|
||||
|
||||
|
||||
public var presentedItemOperationQueue: OperationQueue {
|
||||
return operationQueue
|
||||
}
|
||||
|
||||
|
||||
public init(fileURL: URL, load: @escaping () -> Void, save: @escaping () -> Void) {
|
||||
|
||||
|
||||
self.fileURL = fileURL
|
||||
self.loadCallback = load
|
||||
self.saveCallback = save
|
||||
|
||||
|
||||
saveQueue = CoalescingQueue(name: "ManagedResourceFile Save Queue", interval: saveInterval)
|
||||
operationQueue = OperationQueue()
|
||||
operationQueue.qualityOfService = .userInteractive
|
||||
operationQueue.maxConcurrentOperationCount = 1
|
||||
|
||||
|
||||
super.init()
|
||||
|
||||
|
||||
NSFileCoordinator.addFilePresenter(self)
|
||||
}
|
||||
|
||||
|
||||
public func presentedItemDidChange() {
|
||||
guard !isDirty else { return }
|
||||
DispatchQueue.main.async {
|
||||
self.load()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func savePresentedItemChanges(completionHandler: @escaping (Error?) -> Void) {
|
||||
saveIfNecessary()
|
||||
completionHandler(nil)
|
||||
}
|
||||
|
||||
|
||||
public func relinquishPresentedItem(toReader reader: @escaping ((() -> Void)?) -> Void) {
|
||||
saveQueue.isPaused = true
|
||||
reader() {
|
||||
reader {
|
||||
self.saveQueue.isPaused = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func relinquishPresentedItem(toWriter writer: @escaping ((() -> Void)?) -> Void) {
|
||||
saveQueue.isPaused = true
|
||||
writer() {
|
||||
writer {
|
||||
self.saveQueue.isPaused = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func markAsDirty() {
|
||||
if !isLoading {
|
||||
isDirty = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func queueSaveToDiskIfNeeded() {
|
||||
saveQueue.add(self, #selector(saveToDiskIfNeeded))
|
||||
}
|
||||
@@ -96,27 +96,27 @@ public final class ManagedResourceFile: NSObject, NSFilePresenter {
|
||||
loadCallback()
|
||||
isLoading = false
|
||||
}
|
||||
|
||||
|
||||
public func saveIfNecessary() {
|
||||
saveQueue.performCallsImmediately()
|
||||
}
|
||||
|
||||
|
||||
public func resume() {
|
||||
NSFileCoordinator.addFilePresenter(self)
|
||||
}
|
||||
|
||||
|
||||
public func suspend() {
|
||||
NSFileCoordinator.removeFilePresenter(self)
|
||||
}
|
||||
|
||||
|
||||
deinit {
|
||||
NSFileCoordinator.removeFilePresenter(self)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private extension ManagedResourceFile {
|
||||
|
||||
|
||||
@objc func saveToDiskIfNeeded() {
|
||||
if isDirty {
|
||||
isDirty = false
|
||||
|
||||
@@ -11,7 +11,7 @@ import Foundation
|
||||
// These functions eat errors.
|
||||
|
||||
public func propertyList(withData data: Data) -> Any? {
|
||||
|
||||
|
||||
do {
|
||||
return try PropertyListSerialization.propertyList(from: data, options: [], format: nil)
|
||||
} catch {
|
||||
@@ -22,11 +22,10 @@ public func propertyList(withData data: Data) -> Any? {
|
||||
// Create a binary plist.
|
||||
|
||||
public func data(withPropertyList plist: Any) -> Data? {
|
||||
|
||||
|
||||
do {
|
||||
return try PropertyListSerialization.data(fromPropertyList: plist, format: .binary, options: 0)
|
||||
}
|
||||
catch {
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,25 +25,25 @@ public extension RSImage {
|
||||
/// - Parameter color: The color with which to fill the mask image.
|
||||
/// - Returns: A new masked image.
|
||||
func maskWithColor(color: CGColor) -> RSImage? {
|
||||
|
||||
|
||||
#if os(macOS)
|
||||
guard let maskImage = cgImage(forProposedRect: nil, context: nil, hints: nil) else { return nil }
|
||||
#else
|
||||
guard let maskImage = cgImage else { return nil }
|
||||
#endif
|
||||
|
||||
|
||||
let width = size.width
|
||||
let height = size.height
|
||||
let bounds = CGRect(x: 0, y: 0, width: width, height: height)
|
||||
|
||||
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
|
||||
let context = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)!
|
||||
|
||||
|
||||
context.clip(to: bounds, mask: maskImage)
|
||||
context.setFillColor(color)
|
||||
context.fill(bounds)
|
||||
|
||||
|
||||
if let cgImage = context.makeImage() {
|
||||
#if os(macOS)
|
||||
let coloredImage = RSImage(cgImage: cgImage, size: CGSize(width: cgImage.width, height: cgImage.height))
|
||||
@@ -54,7 +54,7 @@ public extension RSImage {
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#if os(iOS)
|
||||
@@ -112,11 +112,11 @@ public extension RSImage {
|
||||
/// - data: The data object containing the image data.
|
||||
/// - maxPixelSize: The maximum dimension of the image.
|
||||
static func scaleImage(_ data: Data, maxPixelSize: Int) -> CGImage? {
|
||||
|
||||
|
||||
guard let imageSource = CGImageSourceCreateWithData(data as CFData, nil) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
let numberOfImages = CGImageSourceGetCount(imageSource)
|
||||
|
||||
// If the image size matches exactly, then return it.
|
||||
@@ -134,14 +134,14 @@ public extension RSImage {
|
||||
if imagePixelWidth.intValue != maxPixelSize {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
guard let imagePixelHeight = imageProperties[kCGImagePropertyPixelHeight] as? NSNumber else {
|
||||
continue
|
||||
}
|
||||
if imagePixelHeight.intValue != maxPixelSize {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
return CGImageSourceCreateImageAtIndex(imageSource, i, nil)
|
||||
}
|
||||
|
||||
@@ -171,23 +171,22 @@ public extension RSImage {
|
||||
return CGImageSourceCreateImageAtIndex(imageSource, i, nil)
|
||||
}
|
||||
|
||||
|
||||
// If the image data contains a smaller image than the max size, just return it.
|
||||
for i in 0..<numberOfImages {
|
||||
|
||||
|
||||
guard let cfImageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, i, nil) else {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
let imageProperties = cfImageProperties as NSDictionary
|
||||
|
||||
|
||||
guard let imagePixelWidth = imageProperties[kCGImagePropertyPixelWidth] as? NSNumber else {
|
||||
continue
|
||||
}
|
||||
if imagePixelWidth.intValue < 1 || imagePixelWidth.intValue > maxPixelSize {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
guard let imagePixelHeight = imageProperties[kCGImagePropertyPixelHeight] as? NSNumber else {
|
||||
continue
|
||||
}
|
||||
@@ -197,9 +196,9 @@ public extension RSImage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return RSImage.createThumbnail(imageSource, maxPixelSize: maxPixelSize)
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// Create a thumbnail from a CGImageSource.
|
||||
@@ -208,10 +207,10 @@ public extension RSImage {
|
||||
/// - imageSource: The `CGImageSource` from which to create the thumbnail.
|
||||
/// - maxPixelSize: The maximum dimension of the resulting image.
|
||||
static func createThumbnail(_ imageSource: CGImageSource, maxPixelSize: Int) -> CGImage? {
|
||||
let options = [kCGImageSourceCreateThumbnailWithTransform : true,
|
||||
kCGImageSourceCreateThumbnailFromImageIfAbsent : true,
|
||||
kCGImageSourceThumbnailMaxPixelSize : NSNumber(value: maxPixelSize)]
|
||||
let options = [kCGImageSourceCreateThumbnailWithTransform: true,
|
||||
kCGImageSourceCreateThumbnailFromImageIfAbsent: true,
|
||||
kCGImageSourceThumbnailMaxPixelSize: NSNumber(value: maxPixelSize)]
|
||||
return CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,5 @@ public protocol Renamable {
|
||||
/// - completion: A block called when the renaming completes or fails.
|
||||
/// - result: The result of the renaming.
|
||||
func rename(to: String, completion: @escaping (_ result: Result<Void, Error>) -> Void)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import Foundation
|
||||
|
||||
public struct SendToBlogEditorApp {
|
||||
|
||||
///The target descriptor of the application.
|
||||
/// The target descriptor of the application.
|
||||
///
|
||||
/// The easiest way to get this is probably `UserApp.targetDescriptor` or `NSAppleEventDescriptor(runningApplication:)`.
|
||||
///
|
||||
@@ -49,7 +49,6 @@ public struct SendToBlogEditorApp {
|
||||
self.sourceFeedURL = sourceFeedURL
|
||||
}
|
||||
|
||||
|
||||
/// Sends the receiver's data to the blog editor application described by `targetDescriptor`.
|
||||
public func send() {
|
||||
|
||||
@@ -57,7 +56,7 @@ public struct SendToBlogEditorApp {
|
||||
|
||||
appleEvent.setParam(paramDescriptor, forKeyword: keyDirectObject)
|
||||
|
||||
let _ = try? appleEvent.sendEvent(options: [.noReply, .canSwitchLayer, .alwaysInteract], timeout: .AEDefaultTimeout)
|
||||
_ = try? appleEvent.sendEvent(options: [.noReply, .canSwitchLayer, .alwaysInteract], timeout: .AEDefaultTimeout)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -46,4 +46,3 @@ public protocol SendToCommand {
|
||||
/// - selectedText: The currently selected text.
|
||||
func sendObject(_ object: Any?, selectedText: String?)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ public extension Set {
|
||||
|
||||
return self[index]
|
||||
}
|
||||
|
||||
|
||||
func anyObject() -> Element? {
|
||||
|
||||
|
||||
if self.isEmpty {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -25,14 +25,14 @@ public extension String {
|
||||
static func htmlWithLink(_ link: String) -> String {
|
||||
return link.htmlByAddingLink(link)
|
||||
}
|
||||
|
||||
|
||||
func hmacUsingSHA1(key: String) -> String {
|
||||
var digest = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH))
|
||||
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), key, key.count, self, self.count, &digest)
|
||||
let data = Data(digest)
|
||||
return data.map { String(format: "%02hhx", $0) }.joined()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public extension String {
|
||||
@@ -87,7 +87,7 @@ public extension String {
|
||||
|
||||
let s = self.trimmingWhitespace
|
||||
|
||||
if (s.isEmpty || (!s.contains(".") && !s.mayBeIPv6URL && !s.hostMayBeLocalhost)) {
|
||||
if s.isEmpty || (!s.contains(".") && !s.mayBeIPv6URL && !s.hostMayBeLocalhost) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ public extension String {
|
||||
return self.replacingCharacters(in: range, with: "")
|
||||
}
|
||||
|
||||
return self;
|
||||
return self
|
||||
}
|
||||
|
||||
/// Removes an HTML tag and everything between its start and end tags.
|
||||
@@ -264,7 +264,7 @@ public extension String {
|
||||
|
||||
if let maxCharacters = maxCharacters {
|
||||
charactersAdded += 1
|
||||
if (charactersAdded >= maxCharacters) {
|
||||
if charactersAdded >= maxCharacters {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -309,7 +309,6 @@ public extension String {
|
||||
return s.replacingOccurrences(of: "\\n{3,}", with: "\n\n", options: .regularExpression)
|
||||
}
|
||||
|
||||
|
||||
/// Returns a Boolean value indicating whether the string contains another string, case-insensitively.
|
||||
///
|
||||
/// - Parameter string: The string to search for.
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
import UIKit
|
||||
|
||||
extension UIResponder {
|
||||
|
||||
private weak static var _currentFirstResponder: UIResponder? = nil
|
||||
|
||||
private weak static var _currentFirstResponder: UIResponder?
|
||||
|
||||
public static var isFirstResponderTextField: Bool {
|
||||
var isTextField = false
|
||||
@@ -27,7 +27,7 @@ extension UIResponder {
|
||||
UIApplication.shared.sendAction(#selector(findFirstResponder(sender:)), to: nil, from: nil, for: nil)
|
||||
return UIResponder._currentFirstResponder
|
||||
}
|
||||
|
||||
|
||||
public static func resignCurrentFirstResponder() {
|
||||
if let responder = currentFirstResponder {
|
||||
responder.resignFirstResponder()
|
||||
@@ -37,6 +37,6 @@ extension UIResponder {
|
||||
@objc internal func findFirstResponder(sender: AnyObject) {
|
||||
UIResponder._currentFirstResponder = self
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -10,32 +10,32 @@
|
||||
import UIKit
|
||||
|
||||
extension UIView {
|
||||
|
||||
|
||||
public func setFrameIfNotEqual(_ rect: CGRect) {
|
||||
if !self.frame.equalTo(rect) {
|
||||
self.frame = rect
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func addChildAndPin(_ view: UIView) {
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(view)
|
||||
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
safeAreaLayoutGuide.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
safeAreaLayoutGuide.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
safeAreaLayoutGuide.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: view.bottomAnchor)
|
||||
])
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public func asImage() -> UIImage {
|
||||
let renderer = UIGraphicsImageRenderer(bounds: bounds)
|
||||
return renderer.image { rendererContext in
|
||||
layer.render(in: rendererContext.cgContext)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -10,14 +10,14 @@ import UIKit
|
||||
import SwiftUI
|
||||
|
||||
extension UIViewController {
|
||||
|
||||
|
||||
// MARK: Autolayout
|
||||
|
||||
|
||||
public func addChildAndPinView(_ controller: UIViewController) {
|
||||
view.addChildAndPin(controller.view)
|
||||
addChild(controller)
|
||||
}
|
||||
|
||||
|
||||
public func replaceChildAndPinView(_ controller: UIViewController) {
|
||||
for subview in view.subviews {
|
||||
subview.removeFromSuperview()
|
||||
@@ -27,9 +27,9 @@ extension UIViewController {
|
||||
}
|
||||
addChildAndPinView(controller)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Error Handling
|
||||
|
||||
|
||||
public func presentError(title: String, message: String, dismiss: (() -> Void)? = nil) {
|
||||
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
|
||||
let dismissTitle = NSLocalizedString("OK", comment: "OK")
|
||||
@@ -39,7 +39,7 @@ extension UIViewController {
|
||||
alertController.addAction(dismissAction)
|
||||
self.present(alertController, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: SwiftUI
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
import UIKit
|
||||
|
||||
extension UIWindow {
|
||||
|
||||
|
||||
public var topViewController: UIViewController? {
|
||||
|
||||
|
||||
var top = self.rootViewController
|
||||
while true {
|
||||
if let presented = top?.presentedViewController {
|
||||
@@ -33,10 +33,10 @@ extension UIWindow {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return top
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -23,15 +23,15 @@ extension UndoableCommand {
|
||||
public func registerUndo() {
|
||||
|
||||
undoManager.setActionName(undoActionName)
|
||||
undoManager.registerUndo(withTarget: self) { (target) in
|
||||
undoManager.registerUndo(withTarget: self) { (_) in
|
||||
self.undo()
|
||||
}
|
||||
}
|
||||
|
||||
public func registerRedo() {
|
||||
|
||||
|
||||
undoManager.setActionName(redoActionName)
|
||||
undoManager.registerUndo(withTarget: self) { (target) in
|
||||
undoManager.registerUndo(withTarget: self) { (_) in
|
||||
self.perform()
|
||||
}
|
||||
}
|
||||
@@ -40,33 +40,33 @@ extension UndoableCommand {
|
||||
// Useful for view controllers.
|
||||
|
||||
public protocol UndoableCommandRunner: AnyObject {
|
||||
|
||||
|
||||
var undoableCommands: [UndoableCommand] { get set }
|
||||
var undoManager: UndoManager? { get }
|
||||
|
||||
|
||||
func runCommand(_ undoableCommand: UndoableCommand)
|
||||
func clearUndoableCommands()
|
||||
}
|
||||
|
||||
public extension UndoableCommandRunner {
|
||||
|
||||
|
||||
func runCommand(_ undoableCommand: UndoableCommand) {
|
||||
|
||||
|
||||
pushUndoableCommand(undoableCommand)
|
||||
undoableCommand.perform()
|
||||
}
|
||||
|
||||
|
||||
func pushUndoableCommand(_ undoableCommand: UndoableCommand) {
|
||||
|
||||
|
||||
undoableCommands += [undoableCommand]
|
||||
}
|
||||
|
||||
|
||||
func clearUndoableCommands() {
|
||||
|
||||
|
||||
// Useful, for example, when timeline is reloaded and the list of articles changes.
|
||||
// Otherwise things like Redo Mark Read are ambiguous.
|
||||
// (Do they apply to the previous articles or to the current articles?)
|
||||
|
||||
|
||||
guard let undoManager else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -67,5 +67,3 @@ private final class IndeterminateProgressWindowController: NSWindowController {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ public final class WebViewWindowController: NSWindowController {
|
||||
|
||||
@IBOutlet private var webview: WKWebView!
|
||||
private var title: String!
|
||||
|
||||
|
||||
public convenience init(title: String) {
|
||||
self.init(window: nil)
|
||||
self.title = title
|
||||
@@ -29,7 +29,7 @@ public final class WebViewWindowController: NSWindowController {
|
||||
|
||||
// We assume there might be images, style sheets, etc. contained by the folder that the file appears in, so we get read access to the parent folder.
|
||||
|
||||
let _ = self.window
|
||||
_ = self.window
|
||||
|
||||
let fileURL = URL(fileURLWithPath: path)
|
||||
let folderURL = fileURL.deletingLastPathComponent()
|
||||
|
||||
Reference in New Issue
Block a user