Page MenuHomeMusing Studio

No OneTemporary

diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/AppIconExtension@2x.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/AppIconExtension@2x.png
deleted file mode 100644
index 75f2008..0000000
Binary files a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/AppIconExtension@2x.png and /dev/null differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/AppIconExtension@3x.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/AppIconExtension@3x.png
deleted file mode 100644
index 1fd381e..0000000
Binary files a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/AppIconExtension@3x.png and /dev/null differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/Contents.json b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/Contents.json
index 4dac38e..855b1ac 100644
--- a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/Contents.json
+++ b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/Contents.json
@@ -1,100 +1,116 @@
{
"images" : [
{
+ "filename" : "notification-icon@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
+ "filename" : "notification-icon@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
+ "filename" : "icon-small@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
+ "filename" : "icon-small@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
+ "filename" : "icon-40@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
+ "filename" : "icon-40@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
- "filename" : "AppIconExtension@2x.png",
+ "filename" : "icon-60@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
- "filename" : "AppIconExtension@3x.png",
+ "filename" : "icon-60@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
+ "filename" : "notification-icon~ipad.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
+ "filename" : "notification-icon~ipad@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
+ "filename" : "icon-small.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
+ "filename" : "icon-small@2x-1.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
+ "filename" : "icon-40.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
+ "filename" : "icon-40@2x-1.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
+ "filename" : "icon-76.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
+ "filename" : "icon-76@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
+ "filename" : "icon-83.5@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
+ "filename" : "ios-marketing.png",
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-40.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-40.png
new file mode 100644
index 0000000..662e8f4
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-40.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-40@2x-1.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-40@2x-1.png
new file mode 100644
index 0000000..19926ea
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-40@2x-1.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-40@2x.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-40@2x.png
new file mode 100644
index 0000000..19926ea
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-40@2x.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-40@3x.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-40@3x.png
new file mode 100644
index 0000000..fddce80
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-40@3x.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-60@2x.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-60@2x.png
new file mode 100644
index 0000000..fddce80
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-60@2x.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-60@3x.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-60@3x.png
new file mode 100644
index 0000000..8b73775
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-60@3x.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-76.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-76.png
new file mode 100644
index 0000000..795b55c
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-76.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-76@2x.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-76@2x.png
new file mode 100644
index 0000000..f64902d
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-76@2x.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-83.5@2x.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-83.5@2x.png
new file mode 100644
index 0000000..c07d304
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-83.5@2x.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-small.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-small.png
new file mode 100644
index 0000000..ebc122e
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-small.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-small@2x-1.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-small@2x-1.png
new file mode 100644
index 0000000..f30d38f
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-small@2x-1.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-small@2x.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-small@2x.png
new file mode 100644
index 0000000..f30d38f
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-small@2x.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-small@3x.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-small@3x.png
new file mode 100644
index 0000000..21db5a4
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/icon-small@3x.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/ios-marketing.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/ios-marketing.png
new file mode 100644
index 0000000..dbe9d5d
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/ios-marketing.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/notification-icon@2x.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/notification-icon@2x.png
new file mode 100644
index 0000000..662e8f4
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/notification-icon@2x.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/notification-icon@3x.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/notification-icon@3x.png
new file mode 100644
index 0000000..6855f65
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/notification-icon@3x.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/notification-icon~ipad.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/notification-icon~ipad.png
new file mode 100644
index 0000000..8b506c9
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/notification-icon~ipad.png differ
diff --git a/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/notification-icon~ipad@2x.png b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/notification-icon~ipad@2x.png
new file mode 100644
index 0000000..662e8f4
Binary files /dev/null and b/ActionExtension-iOS/Media.xcassets/AppIconExtension.appiconset/notification-icon~ipad@2x.png differ
diff --git a/Shared/Extensions/WriteFreelyModel+APIHandlers.swift b/Shared/Extensions/WriteFreelyModel+APIHandlers.swift
index 9a7447e..804dd41 100644
--- a/Shared/Extensions/WriteFreelyModel+APIHandlers.swift
+++ b/Shared/Extensions/WriteFreelyModel+APIHandlers.swift
@@ -1,301 +1,278 @@
import Foundation
import WriteFreely
extension WriteFreelyModel {
func loginHandler(result: Result<WFUser, Error>) {
DispatchQueue.main.async {
self.isLoggingIn = false
}
do {
let user = try result.get()
fetchUserCollections()
fetchUserPosts()
do {
try saveTokenToKeychain(user.token, username: user.username, server: account.server)
DispatchQueue.main.async {
self.account.login(user)
}
} catch {
DispatchQueue.main.async {
self.loginErrorMessage = "There was a problem storing your access token to the Keychain."
self.isPresentingLoginErrorAlert = true
}
}
} catch WFError.notFound {
DispatchQueue.main.async {
self.loginErrorMessage = AccountError.usernameNotFound.localizedDescription
self.isPresentingLoginErrorAlert = true
}
} catch WFError.unauthorized {
DispatchQueue.main.async {
self.loginErrorMessage = AccountError.invalidPassword.localizedDescription
self.isPresentingLoginErrorAlert = true
}
} catch {
if (error as NSError).domain == NSURLErrorDomain,
(error as NSError).code == -1003 {
DispatchQueue.main.async {
self.loginErrorMessage = AccountError.serverNotFound.localizedDescription
self.isPresentingLoginErrorAlert = true
}
} else {
DispatchQueue.main.async {
self.loginErrorMessage = error.localizedDescription
self.isPresentingLoginErrorAlert = true
}
}
}
}
func logoutHandler(result: Result<Bool, Error>) {
do {
_ = try result.get()
do {
try purgeTokenFromKeychain(username: account.user?.username, server: account.server)
client = nil
DispatchQueue.main.async {
self.account.logout()
LocalStorageManager.standard.purgeUserCollections()
self.posts.purgePublishedPosts()
}
} catch {
print("Something went wrong purging the token from the Keychain.")
}
} catch WFError.notFound {
// The user token is invalid or doesn't exist, so it's been invalidated by the server. Proceed with
// purging the token from the Keychain, destroying the client object, and setting the AccountModel to its
// logged-out state.
do {
try purgeTokenFromKeychain(username: account.user?.username, server: account.server)
client = nil
DispatchQueue.main.async {
self.account.logout()
LocalStorageManager.standard.purgeUserCollections()
self.posts.purgePublishedPosts()
}
} catch {
print("Something went wrong purging the token from the Keychain.")
}
} catch {
// We get a 'cannot parse response' (similar to what we were seeing in the Swift package) NSURLError here,
// so we're using a hacky workaround — if we get the NSURLError, but the AccountModel still thinks we're
// logged in, try calling the logout function again and see what we get.
// Conditional cast from 'Error' to 'NSError' always succeeds but is the only way to check error properties.
if (error as NSError).domain == NSURLErrorDomain,
(error as NSError).code == NSURLErrorCannotParseResponse {
if account.isLoggedIn {
self.logout()
}
}
}
}
func fetchUserCollectionsHandler(result: Result<[WFCollection], Error>) {
// We're done with the network request.
DispatchQueue.main.async {
self.isProcessingRequest = false
}
do {
let fetchedCollections = try result.get()
for fetchedCollection in fetchedCollections {
DispatchQueue.main.async {
let localCollection = WFACollection(context: LocalStorageManager.standard.container.viewContext)
localCollection.alias = fetchedCollection.alias
localCollection.blogDescription = fetchedCollection.description
localCollection.email = fetchedCollection.email
localCollection.isPublic = fetchedCollection.isPublic ?? false
localCollection.styleSheet = fetchedCollection.styleSheet
localCollection.title = fetchedCollection.title
localCollection.url = fetchedCollection.url
}
}
DispatchQueue.main.async {
LocalStorageManager.standard.saveContext()
}
} catch WFError.unauthorized {
DispatchQueue.main.async {
self.loginErrorMessage = "Something went wrong, please try logging in again."
self.isPresentingLoginErrorAlert = true
}
self.logout()
} catch {
print(error)
}
}
func fetchUserPostsHandler(result: Result<[WFPost], Error>) {
// We're done with the network request.
DispatchQueue.main.async {
self.isProcessingRequest = false
}
let request = WFAPost.createFetchRequest()
do {
let locallyCachedPosts = try LocalStorageManager.standard.container.viewContext.fetch(request)
do {
var postsToDelete = locallyCachedPosts.filter { $0.status != PostStatus.local.rawValue }
let fetchedPosts = try result.get()
for fetchedPost in fetchedPosts {
if let managedPost = locallyCachedPosts.first(where: { $0.postId == fetchedPost.postId }) {
DispatchQueue.main.async {
managedPost.wasDeletedFromServer = false
if let fetchedPostUpdatedDate = fetchedPost.updatedDate,
let localPostUpdatedDate = managedPost.updatedDate {
managedPost.hasNewerRemoteCopy = fetchedPostUpdatedDate > localPostUpdatedDate
} else { print("Error: could not determine which copy of post is newer") }
postsToDelete.removeAll(where: { $0.postId == fetchedPost.postId })
}
} else {
DispatchQueue.main.async {
let managedPost = WFAPost(context: LocalStorageManager.standard.container.viewContext)
- managedPost.postId = fetchedPost.postId
- managedPost.slug = fetchedPost.slug
- managedPost.appearance = fetchedPost.appearance
- managedPost.language = fetchedPost.language
- managedPost.rtl = fetchedPost.rtl ?? false
- managedPost.createdDate = fetchedPost.createdDate
- managedPost.updatedDate = fetchedPost.updatedDate
- managedPost.title = fetchedPost.title ?? ""
- managedPost.body = fetchedPost.body
+ self.importData(from: fetchedPost, into: managedPost)
managedPost.collectionAlias = fetchedPost.collectionAlias
- managedPost.status = PostStatus.published.rawValue
managedPost.wasDeletedFromServer = false
}
}
}
DispatchQueue.main.async {
for post in postsToDelete { post.wasDeletedFromServer = true }
LocalStorageManager.standard.saveContext()
}
} catch {
print(error)
}
} catch WFError.unauthorized {
DispatchQueue.main.async {
self.loginErrorMessage = "Something went wrong, please try logging in again."
self.isPresentingLoginErrorAlert = true
}
self.logout()
} catch {
print("Error: Failed to fetch cached posts")
}
}
func publishHandler(result: Result<WFPost, Error>) {
// We're done with the network request.
DispatchQueue.main.async {
self.isProcessingRequest = false
}
// ⚠️ NOTE:
// The API does not return a collection alias, so we take care not to overwrite the
// cached post's collection alias with the 'nil' value from the fetched post.
// See: https://github.com/writeas/writefreely-swift/issues/20
do {
let fetchedPost = try result.get()
// If this is an updated post, check it against postToUpdate.
if let updatingPost = self.postToUpdate {
- updatingPost.appearance = fetchedPost.appearance
- updatingPost.body = fetchedPost.body
- updatingPost.createdDate = fetchedPost.createdDate
- updatingPost.language = fetchedPost.language
- updatingPost.postId = fetchedPost.postId
- updatingPost.rtl = fetchedPost.rtl ?? false
- updatingPost.slug = fetchedPost.slug
- updatingPost.status = PostStatus.published.rawValue
- updatingPost.title = fetchedPost.title ?? ""
- updatingPost.updatedDate = fetchedPost.updatedDate
+ importData(from: fetchedPost, into: updatingPost)
DispatchQueue.main.async {
LocalStorageManager.standard.saveContext()
}
} else {
// Otherwise if it's a newly-published post, find it in the local store.
let request = WFAPost.createFetchRequest()
let matchBodyPredicate = NSPredicate(format: "body == %@", fetchedPost.body)
if let fetchedPostTitle = fetchedPost.title {
let matchTitlePredicate = NSPredicate(format: "title == %@", fetchedPostTitle)
request.predicate = NSCompoundPredicate(
andPredicateWithSubpredicates: [
matchTitlePredicate,
matchBodyPredicate
]
)
} else {
request.predicate = matchBodyPredicate
}
do {
let cachedPostsResults = try LocalStorageManager.standard.container.viewContext.fetch(request)
guard let cachedPost = cachedPostsResults.first else { return }
- cachedPost.appearance = fetchedPost.appearance
- cachedPost.body = fetchedPost.body
- cachedPost.createdDate = fetchedPost.createdDate
- cachedPost.language = fetchedPost.language
- cachedPost.postId = fetchedPost.postId
- cachedPost.rtl = fetchedPost.rtl ?? false
- cachedPost.slug = fetchedPost.slug
- cachedPost.status = PostStatus.published.rawValue
- cachedPost.title = fetchedPost.title ?? ""
- cachedPost.updatedDate = fetchedPost.updatedDate
+ importData(from: fetchedPost, into: cachedPost)
DispatchQueue.main.async {
LocalStorageManager.standard.saveContext()
}
} catch {
print("Error: Failed to fetch cached posts")
}
}
} catch {
print(error)
}
}
func updateFromServerHandler(result: Result<WFPost, Error>) {
// We're done with the network request.
DispatchQueue.main.async {
self.isProcessingRequest = false
}
// ⚠️ NOTE:
// The API does not return a collection alias, so we take care not to overwrite the
// cached post's collection alias with the 'nil' value from the fetched post.
// See: https://github.com/writeas/writefreely-swift/issues/20
do {
let fetchedPost = try result.get()
guard let cachedPost = self.selectedPost else { return }
- cachedPost.appearance = fetchedPost.appearance
- cachedPost.body = fetchedPost.body
- cachedPost.createdDate = fetchedPost.createdDate
- cachedPost.language = fetchedPost.language
- cachedPost.postId = fetchedPost.postId
- cachedPost.rtl = fetchedPost.rtl ?? false
- cachedPost.slug = fetchedPost.slug
- cachedPost.status = PostStatus.published.rawValue
- cachedPost.title = fetchedPost.title ?? ""
- cachedPost.updatedDate = fetchedPost.updatedDate
+ importData(from: fetchedPost, into: cachedPost)
cachedPost.hasNewerRemoteCopy = false
DispatchQueue.main.async {
LocalStorageManager.standard.saveContext()
}
} catch {
print(error)
}
}
func movePostHandler(result: Result<Bool, Error>) {
// We're done with the network request.
DispatchQueue.main.async {
self.isProcessingRequest = false
}
do {
let succeeded = try result.get()
if succeeded {
if let post = selectedPost {
updateFromServer(post: post)
} else {
return
}
}
} catch {
DispatchQueue.main.async {
LocalStorageManager.standard.container.viewContext.rollback()
}
print(error)
}
}
+
+ private func importData(from fetchedPost: WFPost, into cachedPost: WFAPost) {
+ cachedPost.appearance = fetchedPost.appearance
+ cachedPost.body = fetchedPost.body
+ cachedPost.createdDate = fetchedPost.createdDate
+ cachedPost.language = fetchedPost.language
+ cachedPost.postId = fetchedPost.postId
+ cachedPost.rtl = fetchedPost.rtl ?? false
+ cachedPost.slug = fetchedPost.slug
+ cachedPost.status = PostStatus.published.rawValue
+ cachedPost.title = fetchedPost.title ?? ""
+ cachedPost.updatedDate = fetchedPost.updatedDate
+ }
}
diff --git a/Shared/LocalStorageManager.swift b/Shared/LocalStorageManager.swift
index 63bdd88..b644faf 100644
--- a/Shared/LocalStorageManager.swift
+++ b/Shared/LocalStorageManager.swift
@@ -1,123 +1,123 @@
import CoreData
#if os(iOS)
import UIKit
#elseif os(macOS)
import AppKit
#endif
final class LocalStorageManager {
public static var standard = LocalStorageManager()
public let container: NSPersistentContainer
private let containerName = "LocalStorageModel"
private init() {
container = NSPersistentContainer(name: containerName)
setupStore(in: container)
registerObservers()
}
func saveContext() {
if container.viewContext.hasChanges {
do {
try container.viewContext.save()
} catch {
print("Error saving context: \(error)")
}
}
}
func purgeUserCollections() {
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "WFACollection")
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try container.viewContext.executeAndMergeChanges(using: deleteRequest)
} catch {
print("Error: Failed to purge cached collections.")
}
}
}
private extension LocalStorageManager {
var oldStoreURL: URL {
let appSupport = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
return appSupport.appendingPathComponent("LocalStorageModel.sqlite")
}
var sharedStoreURL: URL {
let id = "group.com.abunchtell.writefreely"
let groupContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: id)!
return groupContainer.appendingPathComponent("LocalStorageModel.sqlite")
}
func setupStore(in container: NSPersistentContainer) {
if !FileManager.default.fileExists(atPath: oldStoreURL.path) {
container.persistentStoreDescriptions.first!.url = sharedStoreURL
}
- container.loadPersistentStores { description, error in
+ container.loadPersistentStores { _, error in
if let error = error {
fatalError("Core Data store failed to load with error: \(error)")
}
}
migrateStore(for: container)
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
}
func migrateStore(for container: NSPersistentContainer) {
// Check if the shared store exists before attempting a migration — for example, in case we've already attempted
// and successfully completed a migration, but the deletion of the old store failed for some reason.
guard !FileManager.default.fileExists(atPath: sharedStoreURL.path) else { return }
let coordinator = container.persistentStoreCoordinator
// Get a reference to the old store.
guard let oldStore = coordinator.persistentStore(for: oldStoreURL) else {
return
}
// Attempt to migrate the old store over to the shared store URL.
do {
try coordinator.migratePersistentStore(oldStore,
to: sharedStoreURL,
options: nil,
withType: NSSQLiteStoreType)
} catch {
fatalError("Something went wrong migrating the store: \(error)")
}
// Attempt to delete the old store.
do {
try FileManager.default.removeItem(at: oldStoreURL)
} catch {
fatalError("Something went wrong while deleting the old store: \(error)")
}
}
func registerObservers() {
let center = NotificationCenter.default
#if os(iOS)
let notification = UIApplication.willResignActiveNotification
#elseif os(macOS)
let notification = NSApplication.willResignActiveNotification
#endif
// We don't need to worry about removing this observer because we're targeting iOS 9+ / macOS 10.11+; the
// system will clean this up the next time it would be posted to.
// See: https://developer.apple.com/documentation/foundation/notificationcenter/1413994-removeobserver
// And: https://developer.apple.com/documentation/foundation/notificationcenter/1407263-removeobserver
// swiftlint:disable:next discarded_notification_center_observer
center.addObserver(forName: notification, object: nil, queue: nil, using: self.saveContextOnResignActive)
}
func saveContextOnResignActive(_ notification: Notification) {
saveContext()
}
}
diff --git a/Shared/WriteFreely_MultiPlatformApp.swift b/Shared/WriteFreely_MultiPlatformApp.swift
index 0ea2760..4378ada 100644
--- a/Shared/WriteFreely_MultiPlatformApp.swift
+++ b/Shared/WriteFreely_MultiPlatformApp.swift
@@ -1,155 +1,146 @@
import SwiftUI
#if os(macOS)
import Sparkle
#endif
@main
struct CheckForDebugModifier {
static func main() {
#if os(macOS)
if NSEvent.modifierFlags.contains(.shift) {
// Clear the launch-to-last-draft values to load a new draft.
UserDefaults.shared.setValue(false, forKey: WFDefaults.showAllPostsFlag)
UserDefaults.shared.setValue(nil, forKey: WFDefaults.selectedCollectionURL)
UserDefaults.shared.setValue(nil, forKey: WFDefaults.lastDraftURL)
} else {
// No-op
}
#endif
WriteFreely_MultiPlatformApp.main()
}
}
struct WriteFreely_MultiPlatformApp: App {
@StateObject private var model = WriteFreelyModel.shared
#if os(macOS)
- // swiftlint:disable:next weak_delegate
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
+ @StateObject var updaterViewModel = MacUpdatesViewModel()
@State private var selectedTab = 0
#endif
var body: some Scene {
WindowGroup {
ContentView()
.onAppear(perform: {
if model.editor.showAllPostsFlag {
DispatchQueue.main.async {
self.model.selectedCollection = nil
self.model.showAllPosts = true
showLastDraftOrCreateNewLocalPost()
}
} else {
DispatchQueue.main.async {
self.model.selectedCollection = model.editor.fetchSelectedCollectionFromAppStorage()
self.model.showAllPosts = false
showLastDraftOrCreateNewLocalPost()
}
}
-// DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
-// if model.editor.lastDraftURL != nil {
-// self.model.selectedPost = model.editor.fetchLastDraftFromAppStorage()
-// } else {
-// createNewLocalPost()
-// }
-// }
})
.environmentObject(model)
.environment(\.managedObjectContext, LocalStorageManager.standard.container.viewContext)
// .preferredColorScheme(preferences.selectedColorScheme) // See PreferencesModel for info.
}
.commands {
#if os(macOS)
- CommandGroup(after: .appInfo, addition: {
- Button("Check For Updates") {
- SUUpdater.shared()?.checkForUpdates(self)
- }
- })
+ CommandGroup(after: .appInfo) {
+ CheckForUpdatesView(updaterViewModel: updaterViewModel)
+ }
#endif
CommandGroup(replacing: .newItem, addition: {
Button("New Post") {
createNewLocalPost()
}
.keyboardShortcut("n", modifiers: [.command])
})
CommandGroup(after: .newItem) {
Button("Refresh Posts") {
DispatchQueue.main.async {
model.fetchUserCollections()
model.fetchUserPosts()
}
}
.disabled(!model.account.isLoggedIn)
.keyboardShortcut("r", modifiers: [.command])
}
SidebarCommands()
#if os(macOS)
PostCommands(model: model)
#endif
CommandGroup(after: .help) {
Button("Visit Support Forum") {
#if os(macOS)
NSWorkspace().open(model.helpURL)
#else
UIApplication.shared.open(model.helpURL)
#endif
}
}
ToolbarCommands()
TextEditingCommands()
}
#if os(macOS)
Settings {
TabView(selection: $selectedTab) {
MacAccountView()
.environmentObject(model)
.tabItem {
Image(systemName: "person.crop.circle")
Text("Account")
}
.tag(0)
MacPreferencesView(preferences: model.preferences)
.tabItem {
Image(systemName: "gear")
Text("Preferences")
}
.tag(1)
- MacUpdatesView()
+ MacUpdatesView(updaterViewModel: updaterViewModel)
.tabItem {
Image(systemName: "arrow.down.circle")
Text("Updates")
}
.tag(2)
}
.frame(minWidth: 500, maxWidth: 500, minHeight: 200)
.padding()
// .preferredColorScheme(preferences.selectedColorScheme) // See PreferencesModel for info.
}
#endif
}
private func showLastDraftOrCreateNewLocalPost() {
if model.editor.lastDraftURL != nil {
self.model.selectedPost = model.editor.fetchLastDraftFromAppStorage()
} else {
createNewLocalPost()
}
}
private func createNewLocalPost() {
withAnimation {
// Un-set the currently selected post
self.model.selectedPost = nil
}
// Create the new-post managed object
let managedPost = model.editor.generateNewLocalPost(withFont: model.preferences.font)
withAnimation {
// Set it as the selectedPost
DispatchQueue.main.asyncAfter(deadline: .now()) {
self.model.selectedPost = managedPost
}
}
}
}
diff --git a/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj b/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj
index 5840740..cf176f7 100644
--- a/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj
+++ b/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj
@@ -1,1492 +1,1498 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objects = {
/* Begin PBXBuildFile section */
170A7EC126F5186A00F1CBD4 /* CollectionListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 170A7EC026F5186A00F1CBD4 /* CollectionListModel.swift */; };
170A7EC226F5186A00F1CBD4 /* CollectionListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 170A7EC026F5186A00F1CBD4 /* CollectionListModel.swift */; };
170DFA34251BBC44001D82A0 /* PostEditorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 170DFA33251BBC44001D82A0 /* PostEditorModel.swift */; };
170DFA35251BBC44001D82A0 /* PostEditorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 170DFA33251BBC44001D82A0 /* PostEditorModel.swift */; };
17120DA124E19839002B9F6C /* AccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A5388D24DDEC7400DEFF9A /* AccountView.swift */; };
17120DA224E1985C002B9F6C /* AccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A5388B24DDC83F00DEFF9A /* AccountModel.swift */; };
17120DA324E19A42002B9F6C /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A5389124DDED0000DEFF9A /* PreferencesView.swift */; };
17120DA724E19D11002B9F6C /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17120DA424E19CBF002B9F6C /* SettingsView.swift */; };
17120DA924E1B2F5002B9F6C /* AccountLogoutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17120DA824E1B2F5002B9F6C /* AccountLogoutView.swift */; };
17120DAA24E1B2F5002B9F6C /* AccountLogoutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17120DA824E1B2F5002B9F6C /* AccountLogoutView.swift */; };
17120DAC24E1B99F002B9F6C /* AccountLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17120DAB24E1B99F002B9F6C /* AccountLoginView.swift */; };
17120DAD24E1B99F002B9F6C /* AccountLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17120DAB24E1B99F002B9F6C /* AccountLoginView.swift */; };
17120DB224E1E19C002B9F6C /* SettingsHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17120DB124E1E19C002B9F6C /* SettingsHeaderView.swift */; };
- 1714DD65260BAC14000C0DFF /* WriteFreely in Frameworks */ = {isa = PBXBuildFile; productRef = 1714DD64260BAC14000C0DFF /* WriteFreely */; };
- 1714DD6B260BAC2C000C0DFF /* WriteFreely in Frameworks */ = {isa = PBXBuildFile; productRef = 1714DD6A260BAC2C000C0DFF /* WriteFreely */; };
171BFDFA24D4AF8300888236 /* CollectionListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171BFDF924D4AF8300888236 /* CollectionListView.swift */; };
171BFDFB24D4AF8300888236 /* CollectionListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171BFDF924D4AF8300888236 /* CollectionListView.swift */; };
171DC677272C7D0B002B9B8A /* UserDefaults+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171DC676272C7D0B002B9B8A /* UserDefaults+Extensions.swift */; };
171DC678272C7D0B002B9B8A /* UserDefaults+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171DC676272C7D0B002B9B8A /* UserDefaults+Extensions.swift */; };
172C492E2593981900E20ADF /* MacUpdatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172C492D2593981900E20ADF /* MacUpdatesView.swift */; };
172E10012735B83E00061372 /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 172E10002735B83E00061372 /* UniformTypeIdentifiers.framework */; platformFilter = maccatalyst; };
172E10042735B83E00061372 /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 172E10032735B83E00061372 /* Media.xcassets */; };
172E10062735B83E00061372 /* ActionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172E10052735B83E00061372 /* ActionViewController.swift */; };
172E100D2735B83E00061372 /* ActionExtension-iOS.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 172E0FFF2735B83E00061372 /* ActionExtension-iOS.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
172E10132735BB6200061372 /* Action.js in Resources */ = {isa = PBXBuildFile; fileRef = 172E10122735BB6200061372 /* Action.js */; };
172E10152735C2BD00061372 /* UIHostingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172E10142735C2BD00061372 /* UIHostingView.swift */; };
172E10172735C2DF00061372 /* EnvironmentValues+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172E10162735C2DF00061372 /* EnvironmentValues+Extensions.swift */; };
172E10192735C3DB00061372 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172E10182735C3DB00061372 /* ContentView.swift */; };
- 172E101B2735C54400061372 /* WriteFreely in Frameworks */ = {isa = PBXBuildFile; productRef = 172E101A2735C54400061372 /* WriteFreely */; };
172E101C2735C57400061372 /* LocalStorageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756DBB924FED45500207AB8 /* LocalStorageManager.swift */; };
172E101D2735C5AB00061372 /* LocalStorageModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 1756DBB524FED3A400207AB8 /* LocalStorageModel.xcdatamodeld */; };
172E101E2735C62F00061372 /* PostStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E612507D8E600072984 /* PostStatus.swift */; };
172E101F2735C64600061372 /* WFAPost+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B996D62502D23E0017B536 /* WFAPost+CoreDataClass.swift */; };
172E10202735C64600061372 /* WFACollection+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756DBFF24FEE18400207AB8 /* WFACollection+CoreDataClass.swift */; };
172E10212735C64600061372 /* WFACollection+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756DC0024FEE18400207AB8 /* WFACollection+CoreDataProperties.swift */; };
172E10222735C64600061372 /* WFAPost+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B996D72502D23E0017B536 /* WFAPost+CoreDataProperties.swift */; };
172E10232735C6FF00061372 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E6F250AA12200072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift */; };
172E10242735C72500061372 /* PreferencesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D435E724E3128F0036B539 /* PreferencesModel.swift */; };
173E19D1254318F600440F0F /* RemoteChangePromptView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173E19D0254318F600440F0F /* RemoteChangePromptView.swift */; };
173E19E3254329CC00440F0F /* PostTextEditingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173E19E2254329CC00440F0F /* PostTextEditingView.swift */; };
17466626256C0D0600629997 /* MacEditorTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17466625256C0D0600629997 /* MacEditorTextView.swift */; };
17479F152583D8E40072B7FB /* PostEditorSharingPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17479F142583D8E40072B7FB /* PostEditorSharingPicker.swift */; };
17480CA5251272EE00EB7765 /* Bundle+AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17480CA4251272EE00EB7765 /* Bundle+AppVersion.swift */; };
17480CA6251272EE00EB7765 /* Bundle+AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17480CA4251272EE00EB7765 /* Bundle+AppVersion.swift */; };
174D313224EC2831006CA9EE /* WriteFreelyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 174D313124EC2831006CA9EE /* WriteFreelyModel.swift */; };
174D313324EC2831006CA9EE /* WriteFreelyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 174D313124EC2831006CA9EE /* WriteFreelyModel.swift */; };
1753F6AC24E431CC00309365 /* MacPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1753F6AB24E431CC00309365 /* MacPreferencesView.swift */; };
1756AE6E24CB255B00FD7257 /* PostListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756AE6D24CB255B00FD7257 /* PostListModel.swift */; };
1756AE6F24CB255B00FD7257 /* PostListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756AE6D24CB255B00FD7257 /* PostListModel.swift */; };
1756AE7424CB26FA00FD7257 /* PostCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756AE7324CB26FA00FD7257 /* PostCellView.swift */; };
1756AE7524CB26FA00FD7257 /* PostCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756AE7324CB26FA00FD7257 /* PostCellView.swift */; };
1756AE7724CB2EDD00FD7257 /* PostEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756AE7624CB2EDD00FD7257 /* PostEditorView.swift */; };
1756AE7A24CB65DF00FD7257 /* PostListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756AE7924CB65DF00FD7257 /* PostListView.swift */; };
1756AE7B24CB65DF00FD7257 /* PostListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756AE7924CB65DF00FD7257 /* PostListView.swift */; };
1756AE8124CB844500FD7257 /* View+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756AE8024CB844500FD7257 /* View+Keyboard.swift */; };
1756DBB324FECDBB00207AB8 /* PostEditorStatusToolbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756DBB224FECDBB00207AB8 /* PostEditorStatusToolbarView.swift */; };
1756DBB424FECDBB00207AB8 /* PostEditorStatusToolbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756DBB224FECDBB00207AB8 /* PostEditorStatusToolbarView.swift */; };
1756DBB724FED3A400207AB8 /* LocalStorageModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 1756DBB524FED3A400207AB8 /* LocalStorageModel.xcdatamodeld */; };
1756DBB824FED3A400207AB8 /* LocalStorageModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 1756DBB524FED3A400207AB8 /* LocalStorageModel.xcdatamodeld */; };
1756DBBA24FED45500207AB8 /* LocalStorageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756DBB924FED45500207AB8 /* LocalStorageManager.swift */; };
1756DBBB24FED45500207AB8 /* LocalStorageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756DBB924FED45500207AB8 /* LocalStorageManager.swift */; };
1756DC0124FEE18400207AB8 /* WFACollection+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756DBFF24FEE18400207AB8 /* WFACollection+CoreDataClass.swift */; };
1756DC0224FEE18400207AB8 /* WFACollection+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756DBFF24FEE18400207AB8 /* WFACollection+CoreDataClass.swift */; };
1756DC0324FEE18400207AB8 /* WFACollection+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756DC0024FEE18400207AB8 /* WFACollection+CoreDataProperties.swift */; };
1756DC0424FEE18400207AB8 /* WFACollection+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756DC0024FEE18400207AB8 /* WFACollection+CoreDataProperties.swift */; };
1780F6EF25895EDB00FE45FF /* PostCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1780F6EE25895EDB00FE45FF /* PostCommands.swift */; };
17836C14273EFB870047AF61 /* UserDefaults+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171DC676272C7D0B002B9B8A /* UserDefaults+Extensions.swift */; };
17836C15273F0FBB0047AF61 /* Hack-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 17D4F3A42514F1E900517CE6 /* Hack-Regular.ttf */; };
17836C16273F0FBB0047AF61 /* LoraGX.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 17D4F36B2514EE2F00517CE6 /* LoraGX.ttf */; };
17836C17273F0FBB0047AF61 /* OpenSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 17D4F39D2514F0E500517CE6 /* OpenSans-Regular.ttf */; };
- 17A4FEDA25924AF70037E96B /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 17A4FED925924AF70037E96B /* Sparkle */; };
+ 1784D2ED27946D880033E72E /* WriteFreely in Frameworks */ = {isa = PBXBuildFile; productRef = 1784D2EC27946D880033E72E /* WriteFreely */; };
+ 1784D2EF27946D9A0033E72E /* WriteFreely in Frameworks */ = {isa = PBXBuildFile; productRef = 1784D2EE27946D9A0033E72E /* WriteFreely */; };
+ 1784D2F127946DA10033E72E /* WriteFreely in Frameworks */ = {isa = PBXBuildFile; productRef = 1784D2F027946DA10033E72E /* WriteFreely */; };
17A4FEED25927E730037E96B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A4FEEC25927E730037E96B /* AppDelegate.swift */; };
17A5388824DDA31F00DEFF9A /* MacAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A5388724DDA31F00DEFF9A /* MacAccountView.swift */; };
17A5388C24DDC83F00DEFF9A /* AccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A5388B24DDC83F00DEFF9A /* AccountModel.swift */; };
17A5388F24DDEC7400DEFF9A /* AccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A5388D24DDEC7400DEFF9A /* AccountView.swift */; };
17A5389324DDED0000DEFF9A /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A5389124DDED0000DEFF9A /* PreferencesView.swift */; };
17A67CAF251A5DD7002F163D /* PostEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A67CAE251A5DD7002F163D /* PostEditorView.swift */; };
17AD0A5E25489E810057D763 /* PostTitleTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17AD0A5D25489E810057D763 /* PostTitleTextView.swift */; };
17AD0A6425489E900057D763 /* PostBodyTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17AD0A6325489E900057D763 /* PostBodyTextView.swift */; };
17B37C4B25C8661300FE75E9 /* WriteFreelyModel+Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B37C4A25C8661300FE75E9 /* WriteFreelyModel+Keychain.swift */; };
17B37C4C25C8661300FE75E9 /* WriteFreelyModel+Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B37C4A25C8661300FE75E9 /* WriteFreelyModel+Keychain.swift */; };
17B37C5625C8679800FE75E9 /* WriteFreelyModel+API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B37C5525C8679800FE75E9 /* WriteFreelyModel+API.swift */; };
17B37C5725C8679800FE75E9 /* WriteFreelyModel+API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B37C5525C8679800FE75E9 /* WriteFreelyModel+API.swift */; };
17B37C5D25C8698900FE75E9 /* WriteFreelyModel+APIHandlers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B37C5C25C8698900FE75E9 /* WriteFreelyModel+APIHandlers.swift */; };
17B37C5E25C8698900FE75E9 /* WriteFreelyModel+APIHandlers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B37C5C25C8698900FE75E9 /* WriteFreelyModel+APIHandlers.swift */; };
17B3E965250FAA9000EE9748 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 17B3E964250FAA9000EE9748 /* LaunchScreen.storyboard */; };
17B5103B2515448D00E9631F /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 17B5103A2515448D00E9631F /* Credits.rtf */; };
17B996D82502D23E0017B536 /* WFAPost+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B996D62502D23E0017B536 /* WFAPost+CoreDataClass.swift */; };
17B996D92502D23E0017B536 /* WFAPost+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B996D62502D23E0017B536 /* WFAPost+CoreDataClass.swift */; };
17B996DA2502D23E0017B536 /* WFAPost+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B996D72502D23E0017B536 /* WFAPost+CoreDataProperties.swift */; };
17B996DB2502D23E0017B536 /* WFAPost+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B996D72502D23E0017B536 /* WFAPost+CoreDataProperties.swift */; };
17BC618A25715318003363CA /* ActivePostToolbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17BC617825715068003363CA /* ActivePostToolbarView.swift */; };
17C42E622507D8E600072984 /* PostStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E612507D8E600072984 /* PostStatus.swift */; };
17C42E632507D8E600072984 /* PostStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E612507D8E600072984 /* PostStatus.swift */; };
17C42E652509237800072984 /* PostListFilteredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E642509237800072984 /* PostListFilteredView.swift */; };
17C42E662509237800072984 /* PostListFilteredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E642509237800072984 /* PostListFilteredView.swift */; };
17C42E70250AA12300072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E6F250AA12200072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift */; };
17C42E71250AAFD500072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E6F250AA12200072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift */; };
17D435E824E3128F0036B539 /* PreferencesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D435E724E3128F0036B539 /* PreferencesModel.swift */; };
17D435E924E3128F0036B539 /* PreferencesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D435E724E3128F0036B539 /* PreferencesModel.swift */; };
+ 17D4926527947B4D0035BD7E /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 17D4926427947B4D0035BD7E /* Sparkle */; };
+ 17D4926727947D780035BD7E /* MacUpdatesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D4926627947D780035BD7E /* MacUpdatesViewModel.swift */; };
17D4F36C2514EE2F00517CE6 /* LoraGX.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 17D4F36B2514EE2F00517CE6 /* LoraGX.ttf */; };
17D4F36D2514EE2F00517CE6 /* LoraGX.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 17D4F36B2514EE2F00517CE6 /* LoraGX.ttf */; };
17D4F39E2514F0E500517CE6 /* OpenSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 17D4F39D2514F0E500517CE6 /* OpenSans-Regular.ttf */; };
17D4F39F2514F0E500517CE6 /* OpenSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 17D4F39D2514F0E500517CE6 /* OpenSans-Regular.ttf */; };
17D4F3A52514F1E900517CE6 /* Hack-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 17D4F3A42514F1E900517CE6 /* Hack-Regular.ttf */; };
17D4F3A62514F1E900517CE6 /* Hack-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 17D4F3A42514F1E900517CE6 /* Hack-Regular.ttf */; };
17DF329D24C87D3500BCE2E3 /* Tests_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DF329C24C87D3500BCE2E3 /* Tests_iOS.swift */; };
17DF32A824C87D3500BCE2E3 /* Tests_macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DF32A724C87D3500BCE2E3 /* Tests_macOS.swift */; };
17DF32AA24C87D3500BCE2E3 /* WriteFreely_MultiPlatformApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DF328124C87D3300BCE2E3 /* WriteFreely_MultiPlatformApp.swift */; };
17DF32AB24C87D3500BCE2E3 /* WriteFreely_MultiPlatformApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DF328124C87D3300BCE2E3 /* WriteFreely_MultiPlatformApp.swift */; };
17DF32AC24C87D3500BCE2E3 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DF328224C87D3300BCE2E3 /* ContentView.swift */; };
17DF32AD24C87D3500BCE2E3 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DF328224C87D3300BCE2E3 /* ContentView.swift */; };
17DF32AE24C87D3500BCE2E3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 17DF328324C87D3500BCE2E3 /* Assets.xcassets */; };
17DF32AF24C87D3500BCE2E3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 17DF328324C87D3500BCE2E3 /* Assets.xcassets */; };
17DF32D524C8CA3400BCE2E3 /* PostStatusBadgeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DF32D424C8CA3400BCE2E3 /* PostStatusBadgeView.swift */; };
17DF32D624C8CA3400BCE2E3 /* PostStatusBadgeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DF32D424C8CA3400BCE2E3 /* PostStatusBadgeView.swift */; };
17DFDE87251D309400A25F31 /* Hack-License.txt in Resources */ = {isa = PBXBuildFile; fileRef = 17DFDE84251D309400A25F31 /* Hack-License.txt */; };
17DFDE88251D309400A25F31 /* Hack-License.txt in Resources */ = {isa = PBXBuildFile; fileRef = 17DFDE84251D309400A25F31 /* Hack-License.txt */; };
17DFDE89251D309400A25F31 /* Lora-Cyrillic-OFL.txt in Resources */ = {isa = PBXBuildFile; fileRef = 17DFDE85251D309400A25F31 /* Lora-Cyrillic-OFL.txt */; };
17DFDE8A251D309400A25F31 /* Lora-Cyrillic-OFL.txt in Resources */ = {isa = PBXBuildFile; fileRef = 17DFDE85251D309400A25F31 /* Lora-Cyrillic-OFL.txt */; };
17DFDE8B251D309400A25F31 /* OpenSans-License.txt in Resources */ = {isa = PBXBuildFile; fileRef = 17DFDE86251D309400A25F31 /* OpenSans-License.txt */; };
17DFDE8C251D309400A25F31 /* OpenSans-License.txt in Resources */ = {isa = PBXBuildFile; fileRef = 17DFDE86251D309400A25F31 /* OpenSans-License.txt */; };
17E5DF8A2543610700DCDC9B /* PostTextEditingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17E5DF892543610700DCDC9B /* PostTextEditingView.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
172E100B2735B83E00061372 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 17DF327C24C87D3300BCE2E3 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 172E0FFE2735B83E00061372;
remoteInfo = "ActionExtension-iOS";
};
17DF329924C87D3500BCE2E3 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 17DF327C24C87D3300BCE2E3 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 17DF328724C87D3500BCE2E3;
remoteInfo = "WriteFreely-MultiPlatform (iOS)";
};
17DF32A424C87D3500BCE2E3 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 17DF327C24C87D3300BCE2E3 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 17DF328F24C87D3500BCE2E3;
remoteInfo = "WriteFreely-MultiPlatform (macOS)";
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
172E100E2735B83E00061372 /* Embed App Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
172E100D2735B83E00061372 /* ActionExtension-iOS.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1709ADDF251B9A110053AF79 /* EditorLaunchingPolicy.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = EditorLaunchingPolicy.md; sourceTree = "<group>"; };
170A7EC026F5186A00F1CBD4 /* CollectionListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionListModel.swift; sourceTree = "<group>"; };
170DFA33251BBC44001D82A0 /* PostEditorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostEditorModel.swift; sourceTree = "<group>"; };
17120DA424E19CBF002B9F6C /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
17120DA824E1B2F5002B9F6C /* AccountLogoutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountLogoutView.swift; sourceTree = "<group>"; };
17120DAB24E1B99F002B9F6C /* AccountLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountLoginView.swift; sourceTree = "<group>"; };
17120DB124E1E19C002B9F6C /* SettingsHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsHeaderView.swift; sourceTree = "<group>"; };
171BFDF924D4AF8300888236 /* CollectionListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionListView.swift; sourceTree = "<group>"; };
171DC676272C7D0B002B9B8A /* UserDefaults+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Extensions.swift"; sourceTree = "<group>"; };
172C492D2593981900E20ADF /* MacUpdatesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacUpdatesView.swift; sourceTree = "<group>"; };
172E0FFF2735B83E00061372 /* ActionExtension-iOS.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "ActionExtension-iOS.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
172E10002735B83E00061372 /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; };
172E10032735B83E00061372 /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Media.xcassets; sourceTree = "<group>"; };
172E10052735B83E00061372 /* ActionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionViewController.swift; sourceTree = "<group>"; };
172E100A2735B83E00061372 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; usesTabs = 1; };
172E10122735BB6200061372 /* Action.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = Action.js; sourceTree = "<group>"; };
172E10142735C2BD00061372 /* UIHostingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIHostingView.swift; sourceTree = "<group>"; };
172E10162735C2DF00061372 /* EnvironmentValues+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EnvironmentValues+Extensions.swift"; sourceTree = "<group>"; };
172E10182735C3DB00061372 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
173E19D0254318F600440F0F /* RemoteChangePromptView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteChangePromptView.swift; sourceTree = "<group>"; };
173E19E2254329CC00440F0F /* PostTextEditingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostTextEditingView.swift; sourceTree = "<group>"; };
17466625256C0D0600629997 /* MacEditorTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacEditorTextView.swift; sourceTree = "<group>"; };
17479F142583D8E40072B7FB /* PostEditorSharingPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostEditorSharingPicker.swift; sourceTree = "<group>"; };
17480CA4251272EE00EB7765 /* Bundle+AppVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+AppVersion.swift"; sourceTree = "<group>"; };
174D313124EC2831006CA9EE /* WriteFreelyModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WriteFreelyModel.swift; sourceTree = "<group>"; };
1753F6AB24E431CC00309365 /* MacPreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacPreferencesView.swift; sourceTree = "<group>"; };
1756AE6D24CB255B00FD7257 /* PostListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostListModel.swift; sourceTree = "<group>"; };
1756AE7324CB26FA00FD7257 /* PostCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostCellView.swift; sourceTree = "<group>"; };
1756AE7624CB2EDD00FD7257 /* PostEditorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostEditorView.swift; sourceTree = "<group>"; };
1756AE7924CB65DF00FD7257 /* PostListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostListView.swift; sourceTree = "<group>"; };
1756AE8024CB844500FD7257 /* View+Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Keyboard.swift"; sourceTree = "<group>"; };
1756DBB224FECDBB00207AB8 /* PostEditorStatusToolbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostEditorStatusToolbarView.swift; sourceTree = "<group>"; };
1756DBB624FED3A400207AB8 /* LocalStorageModel.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = LocalStorageModel.xcdatamodel; sourceTree = "<group>"; };
1756DBB924FED45500207AB8 /* LocalStorageManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalStorageManager.swift; sourceTree = "<group>"; };
1756DBFF24FEE18400207AB8 /* WFACollection+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WFACollection+CoreDataClass.swift"; sourceTree = SOURCE_ROOT; };
1756DC0024FEE18400207AB8 /* WFACollection+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WFACollection+CoreDataProperties.swift"; sourceTree = SOURCE_ROOT; };
1780F6EE25895EDB00FE45FF /* PostCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostCommands.swift; sourceTree = "<group>"; };
17836C18273F10C40047AF61 /* ActionExtension-iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "ActionExtension-iOS.entitlements"; sourceTree = "<group>"; };
17A355D3271A052C007C7A47 /* WriteFreely-MultiPlatform (iOS).entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "WriteFreely-MultiPlatform (iOS).entitlements"; sourceTree = "<group>"; };
17A4FEDF25924E810037E96B /* MacSoftwareUpdater.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = MacSoftwareUpdater.md; sourceTree = "<group>"; };
17A4FEEC25927E730037E96B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
17A5388724DDA31F00DEFF9A /* MacAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacAccountView.swift; sourceTree = "<group>"; };
17A5388B24DDC83F00DEFF9A /* AccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountModel.swift; sourceTree = "<group>"; };
17A5388D24DDEC7400DEFF9A /* AccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountView.swift; sourceTree = "<group>"; };
17A5389124DDED0000DEFF9A /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
17A67CAE251A5DD7002F163D /* PostEditorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostEditorView.swift; sourceTree = "<group>"; };
17AD0A5D25489E810057D763 /* PostTitleTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostTitleTextView.swift; sourceTree = "<group>"; };
17AD0A6325489E900057D763 /* PostBodyTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostBodyTextView.swift; sourceTree = "<group>"; };
17B37C4A25C8661300FE75E9 /* WriteFreelyModel+Keychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WriteFreelyModel+Keychain.swift"; sourceTree = "<group>"; };
17B37C5525C8679800FE75E9 /* WriteFreelyModel+API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WriteFreelyModel+API.swift"; sourceTree = "<group>"; };
17B37C5C25C8698900FE75E9 /* WriteFreelyModel+APIHandlers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WriteFreelyModel+APIHandlers.swift"; sourceTree = "<group>"; };
17B3E964250FAA9000EE9748 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
17B5103A2515448D00E9631F /* Credits.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = "<group>"; };
17B68D4F25A4FED2005ED37C /* Sparkle-License.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Sparkle-License.txt"; sourceTree = "<group>"; };
17B996D62502D23E0017B536 /* WFAPost+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WFAPost+CoreDataClass.swift"; sourceTree = SOURCE_ROOT; };
17B996D72502D23E0017B536 /* WFAPost+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WFAPost+CoreDataProperties.swift"; sourceTree = SOURCE_ROOT; };
17BC617825715068003363CA /* ActivePostToolbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivePostToolbarView.swift; sourceTree = "<group>"; };
17C42E612507D8E600072984 /* PostStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostStatus.swift; sourceTree = "<group>"; };
17C42E642509237800072984 /* PostListFilteredView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostListFilteredView.swift; sourceTree = "<group>"; };
17C42E6F250AA12200072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+ExecuteAndMergeChanges.swift"; sourceTree = "<group>"; };
17D435E724E3128F0036B539 /* PreferencesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesModel.swift; sourceTree = "<group>"; };
+ 17D4926627947D780035BD7E /* MacUpdatesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacUpdatesViewModel.swift; sourceTree = "<group>"; };
17D4F36B2514EE2F00517CE6 /* LoraGX.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = LoraGX.ttf; sourceTree = "<group>"; };
17D4F39D2514F0E500517CE6 /* OpenSans-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "OpenSans-Regular.ttf"; sourceTree = "<group>"; };
17D4F3A42514F1E900517CE6 /* Hack-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Hack-Regular.ttf"; sourceTree = "<group>"; };
17DF328124C87D3300BCE2E3 /* WriteFreely_MultiPlatformApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WriteFreely_MultiPlatformApp.swift; sourceTree = "<group>"; };
17DF328224C87D3300BCE2E3 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
17DF328324C87D3500BCE2E3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
17DF328824C87D3500BCE2E3 /* WriteFreely-MultiPlatform.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "WriteFreely-MultiPlatform.app"; sourceTree = BUILT_PRODUCTS_DIR; };
17DF328B24C87D3500BCE2E3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
17DF329024C87D3500BCE2E3 /* WriteFreely for Mac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "WriteFreely for Mac.app"; sourceTree = BUILT_PRODUCTS_DIR; };
17DF329224C87D3500BCE2E3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
17DF329324C87D3500BCE2E3 /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = "<group>"; };
17DF329824C87D3500BCE2E3 /* Tests iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
17DF329C24C87D3500BCE2E3 /* Tests_iOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests_iOS.swift; sourceTree = "<group>"; };
17DF329E24C87D3500BCE2E3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
17DF32A324C87D3500BCE2E3 /* Tests macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests macOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
17DF32A724C87D3500BCE2E3 /* Tests_macOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests_macOS.swift; sourceTree = "<group>"; };
17DF32A924C87D3500BCE2E3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
17DF32C624C884FF00BCE2E3 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
17DF32C724C8853700BCE2E3 /* CODE_OF_CONDUCT.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CODE_OF_CONDUCT.md; sourceTree = "<group>"; };
17DF32C824C8854B00BCE2E3 /* CONTRIBUTING.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CONTRIBUTING.md; sourceTree = "<group>"; };
17DF32C924C8855E00BCE2E3 /* LICENSE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = "<group>"; };
17DF32CA24C8856C00BCE2E3 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = "<group>"; };
17DF32D424C8CA3400BCE2E3 /* PostStatusBadgeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostStatusBadgeView.swift; sourceTree = "<group>"; };
17DFDE84251D309400A25F31 /* Hack-License.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Hack-License.txt"; sourceTree = "<group>"; };
17DFDE85251D309400A25F31 /* Lora-Cyrillic-OFL.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Lora-Cyrillic-OFL.txt"; sourceTree = "<group>"; };
17DFDE86251D309400A25F31 /* OpenSans-License.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "OpenSans-License.txt"; sourceTree = "<group>"; };
17E5DF892543610700DCDC9B /* PostTextEditingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostTextEditingView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
172E0FFC2735B83E00061372 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
172E10012735B83E00061372 /* UniformTypeIdentifiers.framework in Frameworks */,
- 172E101B2735C54400061372 /* WriteFreely in Frameworks */,
+ 1784D2F127946DA10033E72E /* WriteFreely in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
17DF328524C87D3500BCE2E3 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 1714DD65260BAC14000C0DFF /* WriteFreely in Frameworks */,
+ 1784D2ED27946D880033E72E /* WriteFreely in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
17DF328D24C87D3500BCE2E3 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 17A4FEDA25924AF70037E96B /* Sparkle in Frameworks */,
- 1714DD6B260BAC2C000C0DFF /* WriteFreely in Frameworks */,
+ 1784D2EF27946D9A0033E72E /* WriteFreely in Frameworks */,
+ 17D4926527947B4D0035BD7E /* Sparkle in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
17DF329524C87D3500BCE2E3 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
17DF32A024C87D3500BCE2E3 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
1709ADDE251B99D40053AF79 /* Technotes */ = {
isa = PBXGroup;
children = (
1709ADDF251B9A110053AF79 /* EditorLaunchingPolicy.md */,
17A4FEDF25924E810037E96B /* MacSoftwareUpdater.md */,
);
path = Technotes;
sourceTree = "<group>";
};
17120DA624E19CE2002B9F6C /* Settings */ = {
isa = PBXGroup;
children = (
17120DB124E1E19C002B9F6C /* SettingsHeaderView.swift */,
17120DA424E19CBF002B9F6C /* SettingsView.swift */,
);
path = Settings;
sourceTree = "<group>";
};
172E10022735B83E00061372 /* ActionExtension-iOS */ = {
isa = PBXGroup;
children = (
17836C18273F10C40047AF61 /* ActionExtension-iOS.entitlements */,
172E10032735B83E00061372 /* Media.xcassets */,
172E10182735C3DB00061372 /* ContentView.swift */,
172E10052735B83E00061372 /* ActionViewController.swift */,
172E100A2735B83E00061372 /* Info.plist */,
172E10122735BB6200061372 /* Action.js */,
);
path = "ActionExtension-iOS";
sourceTree = "<group>";
};
1739B8D324EAFAB700DA7421 /* PostEditor */ = {
isa = PBXGroup;
children = (
170DFA33251BBC44001D82A0 /* PostEditorModel.swift */,
1756DBB224FECDBB00207AB8 /* PostEditorStatusToolbarView.swift */,
);
path = PostEditor;
sourceTree = "<group>";
};
1756AE7F24CB841200FD7257 /* Extensions */ = {
isa = PBXGroup;
children = (
17480CA4251272EE00EB7765 /* Bundle+AppVersion.swift */,
17C42E6F250AA12200072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift */,
17B37C5525C8679800FE75E9 /* WriteFreelyModel+API.swift */,
17B37C5C25C8698900FE75E9 /* WriteFreelyModel+APIHandlers.swift */,
17B37C4A25C8661300FE75E9 /* WriteFreelyModel+Keychain.swift */,
171DC676272C7D0B002B9B8A /* UserDefaults+Extensions.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
1762DCB124EB07680019C4EB /* Models */ = {
isa = PBXGroup;
children = (
1756DBFF24FEE18400207AB8 /* WFACollection+CoreDataClass.swift */,
1756DC0024FEE18400207AB8 /* WFACollection+CoreDataProperties.swift */,
17B996D62502D23E0017B536 /* WFAPost+CoreDataClass.swift */,
17B996D72502D23E0017B536 /* WFAPost+CoreDataProperties.swift */,
17C42E612507D8E600072984 /* PostStatus.swift */,
174D313124EC2831006CA9EE /* WriteFreelyModel.swift */,
1756DBB524FED3A400207AB8 /* LocalStorageModel.xcdatamodeld */,
);
path = Models;
sourceTree = "<group>";
};
1765F62C24E1924800C9EBF0 /* Preferences */ = {
isa = PBXGroup;
children = (
17D435E724E3128F0036B539 /* PreferencesModel.swift */,
17A5389124DDED0000DEFF9A /* PreferencesView.swift */,
);
path = Preferences;
sourceTree = "<group>";
};
17681E3F251940F200D394AE /* Extensions */ = {
isa = PBXGroup;
children = (
1756AE8024CB844500FD7257 /* View+Keyboard.swift */,
172E10142735C2BD00061372 /* UIHostingView.swift */,
172E10162735C2DF00061372 /* EnvironmentValues+Extensions.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
17A5388924DDA50500DEFF9A /* Settings */ = {
isa = PBXGroup;
children = (
17A5388724DDA31F00DEFF9A /* MacAccountView.swift */,
1753F6AB24E431CC00309365 /* MacPreferencesView.swift */,
172C492D2593981900E20ADF /* MacUpdatesView.swift */,
+ 17D4926627947D780035BD7E /* MacUpdatesViewModel.swift */,
);
path = Settings;
sourceTree = "<group>";
};
17A67CAB251A5D7E002F163D /* PostEditor */ = {
isa = PBXGroup;
children = (
1756AE7624CB2EDD00FD7257 /* PostEditorView.swift */,
173E19D0254318F600440F0F /* RemoteChangePromptView.swift */,
173E19E2254329CC00440F0F /* PostTextEditingView.swift */,
17AD0A5D25489E810057D763 /* PostTitleTextView.swift */,
17AD0A6325489E900057D763 /* PostBodyTextView.swift */,
);
path = PostEditor;
sourceTree = "<group>";
};
17A67CAC251A5D8D002F163D /* PostEditor */ = {
isa = PBXGroup;
children = (
17479F142583D8E40072B7FB /* PostEditorSharingPicker.swift */,
17A67CAE251A5DD7002F163D /* PostEditorView.swift */,
17E5DF892543610700DCDC9B /* PostTextEditingView.swift */,
17466625256C0D0600629997 /* MacEditorTextView.swift */,
);
path = PostEditor;
sourceTree = "<group>";
};
17BC617725715042003363CA /* Navigation */ = {
isa = PBXGroup;
children = (
17BC617825715068003363CA /* ActivePostToolbarView.swift */,
1780F6EE25895EDB00FE45FF /* PostCommands.swift */,
);
path = Navigation;
sourceTree = "<group>";
};
17D4F3722514EE4400517CE6 /* Resources */ = {
isa = PBXGroup;
children = (
17DFDE83251D309400A25F31 /* Licenses */,
17D4F3A42514F1E900517CE6 /* Hack-Regular.ttf */,
17D4F39D2514F0E500517CE6 /* OpenSans-Regular.ttf */,
17D4F36B2514EE2F00517CE6 /* LoraGX.ttf */,
);
path = Resources;
sourceTree = "<group>";
};
17DF327B24C87D3300BCE2E3 = {
isa = PBXGroup;
children = (
17A355D3271A052C007C7A47 /* WriteFreely-MultiPlatform (iOS).entitlements */,
17DF32C624C884FF00BCE2E3 /* README.md */,
17DF32C924C8855E00BCE2E3 /* LICENSE.md */,
17DF32CA24C8856C00BCE2E3 /* CHANGELOG.md */,
17DF32C724C8853700BCE2E3 /* CODE_OF_CONDUCT.md */,
17DF32C824C8854B00BCE2E3 /* CONTRIBUTING.md */,
1709ADDE251B99D40053AF79 /* Technotes */,
17DF328024C87D3300BCE2E3 /* Shared */,
17DF328A24C87D3500BCE2E3 /* iOS */,
17DF329124C87D3500BCE2E3 /* macOS */,
17DF329B24C87D3500BCE2E3 /* Tests iOS */,
17DF32A624C87D3500BCE2E3 /* Tests macOS */,
172E10022735B83E00061372 /* ActionExtension-iOS */,
17DF328924C87D3500BCE2E3 /* Products */,
17DF32C124C87D8D00BCE2E3 /* Frameworks */,
);
sourceTree = "<group>";
};
17DF328024C87D3300BCE2E3 /* Shared */ = {
isa = PBXGroup;
children = (
17DF328124C87D3300BCE2E3 /* WriteFreely_MultiPlatformApp.swift */,
1756DBB924FED45500207AB8 /* LocalStorageManager.swift */,
17DF328324C87D3500BCE2E3 /* Assets.xcassets */,
17DF32D024C8B75C00BCE2E3 /* Account */,
1756AE7F24CB841200FD7257 /* Extensions */,
1762DCB124EB07680019C4EB /* Models */,
17DF32CC24C8B72300BCE2E3 /* Navigation */,
1739B8D324EAFAB700DA7421 /* PostEditor */,
17DF32D124C8B78500BCE2E3 /* PostList */,
17DF32D224C8B78D00BCE2E3 /* PostCollection */,
1765F62C24E1924800C9EBF0 /* Preferences */,
17D4F3722514EE4400517CE6 /* Resources */,
);
path = Shared;
sourceTree = "<group>";
};
17DF328924C87D3500BCE2E3 /* Products */ = {
isa = PBXGroup;
children = (
17DF328824C87D3500BCE2E3 /* WriteFreely-MultiPlatform.app */,
17DF329024C87D3500BCE2E3 /* WriteFreely for Mac.app */,
17DF329824C87D3500BCE2E3 /* Tests iOS.xctest */,
17DF32A324C87D3500BCE2E3 /* Tests macOS.xctest */,
172E0FFF2735B83E00061372 /* ActionExtension-iOS.appex */,
);
name = Products;
sourceTree = "<group>";
};
17DF328A24C87D3500BCE2E3 /* iOS */ = {
isa = PBXGroup;
children = (
17DF328B24C87D3500BCE2E3 /* Info.plist */,
17B3E964250FAA9000EE9748 /* LaunchScreen.storyboard */,
17681E3F251940F200D394AE /* Extensions */,
17A67CAB251A5D7E002F163D /* PostEditor */,
17120DA624E19CE2002B9F6C /* Settings */,
);
path = iOS;
sourceTree = "<group>";
};
17DF329124C87D3500BCE2E3 /* macOS */ = {
isa = PBXGroup;
children = (
17DF329224C87D3500BCE2E3 /* Info.plist */,
17DF329324C87D3500BCE2E3 /* macOS.entitlements */,
17A4FEEC25927E730037E96B /* AppDelegate.swift */,
17BC617725715042003363CA /* Navigation */,
17A67CAC251A5D8D002F163D /* PostEditor */,
17A5388924DDA50500DEFF9A /* Settings */,
17B5103A2515448D00E9631F /* Credits.rtf */,
);
path = macOS;
sourceTree = "<group>";
};
17DF329B24C87D3500BCE2E3 /* Tests iOS */ = {
isa = PBXGroup;
children = (
17DF329C24C87D3500BCE2E3 /* Tests_iOS.swift */,
17DF329E24C87D3500BCE2E3 /* Info.plist */,
);
path = "Tests iOS";
sourceTree = "<group>";
};
17DF32A624C87D3500BCE2E3 /* Tests macOS */ = {
isa = PBXGroup;
children = (
17DF32A724C87D3500BCE2E3 /* Tests_macOS.swift */,
17DF32A924C87D3500BCE2E3 /* Info.plist */,
);
path = "Tests macOS";
sourceTree = "<group>";
};
17DF32C124C87D8D00BCE2E3 /* Frameworks */ = {
isa = PBXGroup;
children = (
172E10002735B83E00061372 /* UniformTypeIdentifiers.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
17DF32CC24C8B72300BCE2E3 /* Navigation */ = {
isa = PBXGroup;
children = (
17DF328224C87D3300BCE2E3 /* ContentView.swift */,
);
path = Navigation;
sourceTree = "<group>";
};
17DF32D024C8B75C00BCE2E3 /* Account */ = {
isa = PBXGroup;
children = (
17A5388B24DDC83F00DEFF9A /* AccountModel.swift */,
17120DAB24E1B99F002B9F6C /* AccountLoginView.swift */,
17120DA824E1B2F5002B9F6C /* AccountLogoutView.swift */,
17A5388D24DDEC7400DEFF9A /* AccountView.swift */,
);
path = Account;
sourceTree = "<group>";
};
17DF32D124C8B78500BCE2E3 /* PostList */ = {
isa = PBXGroup;
children = (
1756AE7324CB26FA00FD7257 /* PostCellView.swift */,
1756AE6D24CB255B00FD7257 /* PostListModel.swift */,
1756AE7924CB65DF00FD7257 /* PostListView.swift */,
17DF32D424C8CA3400BCE2E3 /* PostStatusBadgeView.swift */,
17C42E642509237800072984 /* PostListFilteredView.swift */,
);
path = PostList;
sourceTree = "<group>";
};
17DF32D224C8B78D00BCE2E3 /* PostCollection */ = {
isa = PBXGroup;
children = (
170A7EC026F5186A00F1CBD4 /* CollectionListModel.swift */,
171BFDF924D4AF8300888236 /* CollectionListView.swift */,
);
path = PostCollection;
sourceTree = "<group>";
};
17DFDE83251D309400A25F31 /* Licenses */ = {
isa = PBXGroup;
children = (
17B68D4F25A4FED2005ED37C /* Sparkle-License.txt */,
17DFDE84251D309400A25F31 /* Hack-License.txt */,
17DFDE85251D309400A25F31 /* Lora-Cyrillic-OFL.txt */,
17DFDE86251D309400A25F31 /* OpenSans-License.txt */,
);
path = Licenses;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
172E0FFE2735B83E00061372 /* ActionExtension-iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 172E10112735B83E00061372 /* Build configuration list for PBXNativeTarget "ActionExtension-iOS" */;
buildPhases = (
172E0FFB2735B83E00061372 /* Sources */,
172E0FFC2735B83E00061372 /* Frameworks */,
172E0FFD2735B83E00061372 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "ActionExtension-iOS";
packageProductDependencies = (
- 172E101A2735C54400061372 /* WriteFreely */,
+ 1784D2F027946DA10033E72E /* WriteFreely */,
);
productName = "ActionExtension-iOS";
productReference = 172E0FFF2735B83E00061372 /* ActionExtension-iOS.appex */;
productType = "com.apple.product-type.app-extension";
};
17DF328724C87D3500BCE2E3 /* WriteFreely-MultiPlatform (iOS) */ = {
isa = PBXNativeTarget;
buildConfigurationList = 17DF32B224C87D3500BCE2E3 /* Build configuration list for PBXNativeTarget "WriteFreely-MultiPlatform (iOS)" */;
buildPhases = (
17DF328424C87D3500BCE2E3 /* Sources */,
17DF328524C87D3500BCE2E3 /* Frameworks */,
17DF328624C87D3500BCE2E3 /* Resources */,
17DF32C424C87E6700BCE2E3 /* ShellScript */,
172E100E2735B83E00061372 /* Embed App Extensions */,
);
buildRules = (
);
dependencies = (
172E100C2735B83E00061372 /* PBXTargetDependency */,
);
name = "WriteFreely-MultiPlatform (iOS)";
packageProductDependencies = (
- 1714DD64260BAC14000C0DFF /* WriteFreely */,
+ 1784D2EC27946D880033E72E /* WriteFreely */,
);
productName = "WriteFreely-MultiPlatform (iOS)";
productReference = 17DF328824C87D3500BCE2E3 /* WriteFreely-MultiPlatform.app */;
productType = "com.apple.product-type.application";
};
17DF328F24C87D3500BCE2E3 /* WriteFreely-MultiPlatform (macOS) */ = {
isa = PBXNativeTarget;
buildConfigurationList = 17DF32B524C87D3500BCE2E3 /* Build configuration list for PBXNativeTarget "WriteFreely-MultiPlatform (macOS)" */;
buildPhases = (
17DF328C24C87D3500BCE2E3 /* Sources */,
17DF328D24C87D3500BCE2E3 /* Frameworks */,
17DF328E24C87D3500BCE2E3 /* Resources */,
17DF32C524C87FDB00BCE2E3 /* ShellScript */,
);
buildRules = (
);
dependencies = (
);
name = "WriteFreely-MultiPlatform (macOS)";
packageProductDependencies = (
- 17A4FED925924AF70037E96B /* Sparkle */,
- 1714DD6A260BAC2C000C0DFF /* WriteFreely */,
+ 1784D2EE27946D9A0033E72E /* WriteFreely */,
+ 17D4926427947B4D0035BD7E /* Sparkle */,
);
productName = "WriteFreely-MultiPlatform (macOS)";
productReference = 17DF329024C87D3500BCE2E3 /* WriteFreely for Mac.app */;
productType = "com.apple.product-type.application";
};
17DF329724C87D3500BCE2E3 /* Tests iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 17DF32B824C87D3500BCE2E3 /* Build configuration list for PBXNativeTarget "Tests iOS" */;
buildPhases = (
17DF329424C87D3500BCE2E3 /* Sources */,
17DF329524C87D3500BCE2E3 /* Frameworks */,
17DF329624C87D3500BCE2E3 /* Resources */,
);
buildRules = (
);
dependencies = (
17DF329A24C87D3500BCE2E3 /* PBXTargetDependency */,
);
name = "Tests iOS";
productName = "Tests iOS";
productReference = 17DF329824C87D3500BCE2E3 /* Tests iOS.xctest */;
productType = "com.apple.product-type.bundle.ui-testing";
};
17DF32A224C87D3500BCE2E3 /* Tests macOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 17DF32BB24C87D3500BCE2E3 /* Build configuration list for PBXNativeTarget "Tests macOS" */;
buildPhases = (
17DF329F24C87D3500BCE2E3 /* Sources */,
17DF32A024C87D3500BCE2E3 /* Frameworks */,
17DF32A124C87D3500BCE2E3 /* Resources */,
);
buildRules = (
);
dependencies = (
17DF32A524C87D3500BCE2E3 /* PBXTargetDependency */,
);
name = "Tests macOS";
productName = "Tests macOS";
productReference = 17DF32A324C87D3500BCE2E3 /* Tests macOS.xctest */;
productType = "com.apple.product-type.bundle.ui-testing";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
17DF327C24C87D3300BCE2E3 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1310;
- LastUpgradeCheck = 1200;
+ LastUpgradeCheck = 1320;
TargetAttributes = {
172E0FFE2735B83E00061372 = {
CreatedOnToolsVersion = 13.1;
};
17DF328724C87D3500BCE2E3 = {
CreatedOnToolsVersion = 12.0;
};
17DF328F24C87D3500BCE2E3 = {
CreatedOnToolsVersion = 12.0;
};
17DF329724C87D3500BCE2E3 = {
CreatedOnToolsVersion = 12.0;
TestTargetID = 17DF328724C87D3500BCE2E3;
};
17DF32A224C87D3500BCE2E3 = {
CreatedOnToolsVersion = 12.0;
TestTargetID = 17DF328F24C87D3500BCE2E3;
};
};
};
buildConfigurationList = 17DF327F24C87D3300BCE2E3 /* Build configuration list for PBXProject "WriteFreely-MultiPlatform" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 17DF327B24C87D3300BCE2E3;
packageReferences = (
- 17A4FED825924AF70037E96B /* XCRemoteSwiftPackageReference "Sparkle" */,
- 1714DD63260BAC14000C0DFF /* XCRemoteSwiftPackageReference "writefreely-swift" */,
+ 1784D2EB27946D880033E72E /* XCRemoteSwiftPackageReference "writefreely-swift" */,
+ 17D4926327947B4D0035BD7E /* XCRemoteSwiftPackageReference "Sparkle" */,
);
productRefGroup = 17DF328924C87D3500BCE2E3 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
17DF328724C87D3500BCE2E3 /* WriteFreely-MultiPlatform (iOS) */,
17DF328F24C87D3500BCE2E3 /* WriteFreely-MultiPlatform (macOS) */,
17DF329724C87D3500BCE2E3 /* Tests iOS */,
17DF32A224C87D3500BCE2E3 /* Tests macOS */,
172E0FFE2735B83E00061372 /* ActionExtension-iOS */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
172E0FFD2735B83E00061372 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
17836C17273F0FBB0047AF61 /* OpenSans-Regular.ttf in Resources */,
172E10132735BB6200061372 /* Action.js in Resources */,
172E10042735B83E00061372 /* Media.xcassets in Resources */,
17836C15273F0FBB0047AF61 /* Hack-Regular.ttf in Resources */,
17836C16273F0FBB0047AF61 /* LoraGX.ttf in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
17DF328624C87D3500BCE2E3 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
17B3E965250FAA9000EE9748 /* LaunchScreen.storyboard in Resources */,
17DFDE8B251D309400A25F31 /* OpenSans-License.txt in Resources */,
17DF32AE24C87D3500BCE2E3 /* Assets.xcassets in Resources */,
17D4F39E2514F0E500517CE6 /* OpenSans-Regular.ttf in Resources */,
17D4F36C2514EE2F00517CE6 /* LoraGX.ttf in Resources */,
17D4F3A52514F1E900517CE6 /* Hack-Regular.ttf in Resources */,
17DFDE89251D309400A25F31 /* Lora-Cyrillic-OFL.txt in Resources */,
17DFDE87251D309400A25F31 /* Hack-License.txt in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
17DF328E24C87D3500BCE2E3 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
17DF32AF24C87D3500BCE2E3 /* Assets.xcassets in Resources */,
17DFDE8C251D309400A25F31 /* OpenSans-License.txt in Resources */,
17B5103B2515448D00E9631F /* Credits.rtf in Resources */,
17D4F39F2514F0E500517CE6 /* OpenSans-Regular.ttf in Resources */,
17D4F3A62514F1E900517CE6 /* Hack-Regular.ttf in Resources */,
17D4F36D2514EE2F00517CE6 /* LoraGX.ttf in Resources */,
17DFDE8A251D309400A25F31 /* Lora-Cyrillic-OFL.txt in Resources */,
17DFDE88251D309400A25F31 /* Hack-License.txt in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
17DF329624C87D3500BCE2E3 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
17DF32A124C87D3500BCE2E3 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
17DF32C424C87E6700BCE2E3 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Run SwiftLint on builds\nif which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
};
17DF32C524C87FDB00BCE2E3 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Run SwiftLint on builds\nif which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
172E0FFB2735B83E00061372 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
172E10062735B83E00061372 /* ActionViewController.swift in Sources */,
172E10202735C64600061372 /* WFACollection+CoreDataClass.swift in Sources */,
172E10222735C64600061372 /* WFAPost+CoreDataProperties.swift in Sources */,
172E101D2735C5AB00061372 /* LocalStorageModel.xcdatamodeld in Sources */,
17836C14273EFB870047AF61 /* UserDefaults+Extensions.swift in Sources */,
172E10242735C72500061372 /* PreferencesModel.swift in Sources */,
172E10172735C2DF00061372 /* EnvironmentValues+Extensions.swift in Sources */,
172E10212735C64600061372 /* WFACollection+CoreDataProperties.swift in Sources */,
172E101C2735C57400061372 /* LocalStorageManager.swift in Sources */,
172E10192735C3DB00061372 /* ContentView.swift in Sources */,
172E10152735C2BD00061372 /* UIHostingView.swift in Sources */,
172E101F2735C64600061372 /* WFAPost+CoreDataClass.swift in Sources */,
172E10232735C6FF00061372 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift in Sources */,
172E101E2735C62F00061372 /* PostStatus.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
17DF328424C87D3500BCE2E3 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
17DF32AC24C87D3500BCE2E3 /* ContentView.swift in Sources */,
173E19D1254318F600440F0F /* RemoteChangePromptView.swift in Sources */,
17B37C5625C8679800FE75E9 /* WriteFreelyModel+API.swift in Sources */,
17C42E622507D8E600072984 /* PostStatus.swift in Sources */,
1756DBBA24FED45500207AB8 /* LocalStorageManager.swift in Sources */,
1756AE8124CB844500FD7257 /* View+Keyboard.swift in Sources */,
17C42E652509237800072984 /* PostListFilteredView.swift in Sources */,
170DFA34251BBC44001D82A0 /* PostEditorModel.swift in Sources */,
17120DAC24E1B99F002B9F6C /* AccountLoginView.swift in Sources */,
17B37C4B25C8661300FE75E9 /* WriteFreelyModel+Keychain.swift in Sources */,
17480CA5251272EE00EB7765 /* Bundle+AppVersion.swift in Sources */,
17AD0A6425489E900057D763 /* PostBodyTextView.swift in Sources */,
17B37C5D25C8698900FE75E9 /* WriteFreelyModel+APIHandlers.swift in Sources */,
17AD0A5E25489E810057D763 /* PostTitleTextView.swift in Sources */,
17120DA924E1B2F5002B9F6C /* AccountLogoutView.swift in Sources */,
171BFDFA24D4AF8300888236 /* CollectionListView.swift in Sources */,
1756DBB324FECDBB00207AB8 /* PostEditorStatusToolbarView.swift in Sources */,
17120DB224E1E19C002B9F6C /* SettingsHeaderView.swift in Sources */,
171DC677272C7D0B002B9B8A /* UserDefaults+Extensions.swift in Sources */,
1756DBB724FED3A400207AB8 /* LocalStorageModel.xcdatamodeld in Sources */,
17B996DA2502D23E0017B536 /* WFAPost+CoreDataProperties.swift in Sources */,
1756AE7724CB2EDD00FD7257 /* PostEditorView.swift in Sources */,
17DF32D524C8CA3400BCE2E3 /* PostStatusBadgeView.swift in Sources */,
170A7EC126F5186A00F1CBD4 /* CollectionListModel.swift in Sources */,
17D435E824E3128F0036B539 /* PreferencesModel.swift in Sources */,
1756AE7A24CB65DF00FD7257 /* PostListView.swift in Sources */,
17B996D82502D23E0017B536 /* WFAPost+CoreDataClass.swift in Sources */,
1756DC0124FEE18400207AB8 /* WFACollection+CoreDataClass.swift in Sources */,
17DF32AA24C87D3500BCE2E3 /* WriteFreely_MultiPlatformApp.swift in Sources */,
17120DA724E19D11002B9F6C /* SettingsView.swift in Sources */,
1756DC0324FEE18400207AB8 /* WFACollection+CoreDataProperties.swift in Sources */,
17120DA224E1985C002B9F6C /* AccountModel.swift in Sources */,
17120DA324E19A42002B9F6C /* PreferencesView.swift in Sources */,
1756AE6E24CB255B00FD7257 /* PostListModel.swift in Sources */,
173E19E3254329CC00440F0F /* PostTextEditingView.swift in Sources */,
174D313224EC2831006CA9EE /* WriteFreelyModel.swift in Sources */,
17C42E70250AA12300072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift in Sources */,
17120DA124E19839002B9F6C /* AccountView.swift in Sources */,
1756AE7424CB26FA00FD7257 /* PostCellView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
17DF328C24C87D3500BCE2E3 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
171DC678272C7D0B002B9B8A /* UserDefaults+Extensions.swift in Sources */,
17DF32AD24C87D3500BCE2E3 /* ContentView.swift in Sources */,
1756DBBB24FED45500207AB8 /* LocalStorageManager.swift in Sources */,
17A4FEED25927E730037E96B /* AppDelegate.swift in Sources */,
174D313324EC2831006CA9EE /* WriteFreelyModel.swift in Sources */,
17D435E924E3128F0036B539 /* PreferencesModel.swift in Sources */,
17120DAA24E1B2F5002B9F6C /* AccountLogoutView.swift in Sources */,
17DF32D624C8CA3400BCE2E3 /* PostStatusBadgeView.swift in Sources */,
172C492E2593981900E20ADF /* MacUpdatesView.swift in Sources */,
17479F152583D8E40072B7FB /* PostEditorSharingPicker.swift in Sources */,
17480CA6251272EE00EB7765 /* Bundle+AppVersion.swift in Sources */,
17C42E662509237800072984 /* PostListFilteredView.swift in Sources */,
17120DAD24E1B99F002B9F6C /* AccountLoginView.swift in Sources */,
+ 17D4926727947D780035BD7E /* MacUpdatesViewModel.swift in Sources */,
17466626256C0D0600629997 /* MacEditorTextView.swift in Sources */,
170A7EC226F5186A00F1CBD4 /* CollectionListModel.swift in Sources */,
17E5DF8A2543610700DCDC9B /* PostTextEditingView.swift in Sources */,
17C42E71250AAFD500072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift in Sources */,
1756AE7B24CB65DF00FD7257 /* PostListView.swift in Sources */,
1753F6AC24E431CC00309365 /* MacPreferencesView.swift in Sources */,
1756DC0424FEE18400207AB8 /* WFACollection+CoreDataProperties.swift in Sources */,
17B996DB2502D23E0017B536 /* WFAPost+CoreDataProperties.swift in Sources */,
17BC618A25715318003363CA /* ActivePostToolbarView.swift in Sources */,
171BFDFB24D4AF8300888236 /* CollectionListView.swift in Sources */,
17A67CAF251A5DD7002F163D /* PostEditorView.swift in Sources */,
17DF32AB24C87D3500BCE2E3 /* WriteFreely_MultiPlatformApp.swift in Sources */,
17B37C5725C8679800FE75E9 /* WriteFreelyModel+API.swift in Sources */,
17A5388C24DDC83F00DEFF9A /* AccountModel.swift in Sources */,
17B996D92502D23E0017B536 /* WFAPost+CoreDataClass.swift in Sources */,
1756DBB824FED3A400207AB8 /* LocalStorageModel.xcdatamodeld in Sources */,
17B37C4C25C8661300FE75E9 /* WriteFreelyModel+Keychain.swift in Sources */,
17A5389324DDED0000DEFF9A /* PreferencesView.swift in Sources */,
1756AE6F24CB255B00FD7257 /* PostListModel.swift in Sources */,
1756DC0224FEE18400207AB8 /* WFACollection+CoreDataClass.swift in Sources */,
1756DBB424FECDBB00207AB8 /* PostEditorStatusToolbarView.swift in Sources */,
17A5388F24DDEC7400DEFF9A /* AccountView.swift in Sources */,
1780F6EF25895EDB00FE45FF /* PostCommands.swift in Sources */,
17B37C5E25C8698900FE75E9 /* WriteFreelyModel+APIHandlers.swift in Sources */,
170DFA35251BBC44001D82A0 /* PostEditorModel.swift in Sources */,
1756AE7524CB26FA00FD7257 /* PostCellView.swift in Sources */,
17A5388824DDA31F00DEFF9A /* MacAccountView.swift in Sources */,
17C42E632507D8E600072984 /* PostStatus.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
17DF329424C87D3500BCE2E3 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
17DF329D24C87D3500BCE2E3 /* Tests_iOS.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
17DF329F24C87D3500BCE2E3 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
17DF32A824C87D3500BCE2E3 /* Tests_macOS.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
172E100C2735B83E00061372 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 172E0FFE2735B83E00061372 /* ActionExtension-iOS */;
targetProxy = 172E100B2735B83E00061372 /* PBXContainerItemProxy */;
};
17DF329A24C87D3500BCE2E3 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 17DF328724C87D3500BCE2E3 /* WriteFreely-MultiPlatform (iOS) */;
targetProxy = 17DF329924C87D3500BCE2E3 /* PBXContainerItemProxy */;
};
17DF32A524C87D3500BCE2E3 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 17DF328F24C87D3500BCE2E3 /* WriteFreely-MultiPlatform (macOS) */;
targetProxy = 17DF32A424C87D3500BCE2E3 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
172E100F2735B83E00061372 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconExtension;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_ENTITLEMENTS = "ActionExtension-iOS/ActionExtension-iOS.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 646;
DEVELOPMENT_TEAM = TPPAB4YBA6;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "ActionExtension-iOS/Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = "Create WriteFreely draft";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0.8;
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform.ActionExtension-iOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
172E10102735B83E00061372 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconExtension;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_ENTITLEMENTS = "ActionExtension-iOS/ActionExtension-iOS.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 646;
DEVELOPMENT_TEAM = TPPAB4YBA6;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "ActionExtension-iOS/Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = "Create WriteFreely draft";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0.8;
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform.ActionExtension-iOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
17DF32B024C87D3500BCE2E3 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
17DF32B124C87D3500BCE2E3 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
17DF32B324C87D3500BCE2E3 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = "WriteFreely-MultiPlatform (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 646;
DEVELOPMENT_TEAM = TPPAB4YBA6;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = iOS/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.8;
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform";
PRODUCT_NAME = "WriteFreely-MultiPlatform";
SDKROOT = iphoneos;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
17DF32B424C87D3500BCE2E3 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = "WriteFreely-MultiPlatform (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 646;
DEVELOPMENT_TEAM = TPPAB4YBA6;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = iOS/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.8;
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform";
PRODUCT_NAME = "WriteFreely-MultiPlatform";
SDKROOT = iphoneos;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
17DF32B624C87D3500BCE2E3 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 620;
DEVELOPMENT_TEAM = TPPAB4YBA6;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = macOS/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 0.6.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform";
PRODUCT_NAME = "WriteFreely for Mac";
SDKROOT = macosx;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
17DF32B724C87D3500BCE2E3 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 620;
DEVELOPMENT_TEAM = TPPAB4YBA6;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = macOS/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 0.6.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform";
PRODUCT_NAME = "WriteFreely for Mac";
SDKROOT = macosx;
SWIFT_VERSION = 5.0;
};
name = Release;
};
17DF32B924C87D3500BCE2E3 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = TPPAB4YBA6;
INFOPLIST_FILE = "Tests iOS/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.Tests-iOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = "WriteFreely-MultiPlatform (iOS)";
};
name = Debug;
};
17DF32BA24C87D3500BCE2E3 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = TPPAB4YBA6;
INFOPLIST_FILE = "Tests iOS/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.Tests-iOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = "WriteFreely-MultiPlatform (iOS)";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
17DF32BC24C87D3500BCE2E3 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = TPPAB4YBA6;
INFOPLIST_FILE = "Tests macOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.Tests-macOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_VERSION = 5.0;
TEST_TARGET_NAME = "WriteFreely-MultiPlatform (macOS)";
};
name = Debug;
};
17DF32BD24C87D3500BCE2E3 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = TPPAB4YBA6;
INFOPLIST_FILE = "Tests macOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.Tests-macOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_VERSION = 5.0;
TEST_TARGET_NAME = "WriteFreely-MultiPlatform (macOS)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
172E10112735B83E00061372 /* Build configuration list for PBXNativeTarget "ActionExtension-iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
172E100F2735B83E00061372 /* Debug */,
172E10102735B83E00061372 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
17DF327F24C87D3300BCE2E3 /* Build configuration list for PBXProject "WriteFreely-MultiPlatform" */ = {
isa = XCConfigurationList;
buildConfigurations = (
17DF32B024C87D3500BCE2E3 /* Debug */,
17DF32B124C87D3500BCE2E3 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
17DF32B224C87D3500BCE2E3 /* Build configuration list for PBXNativeTarget "WriteFreely-MultiPlatform (iOS)" */ = {
isa = XCConfigurationList;
buildConfigurations = (
17DF32B324C87D3500BCE2E3 /* Debug */,
17DF32B424C87D3500BCE2E3 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
17DF32B524C87D3500BCE2E3 /* Build configuration list for PBXNativeTarget "WriteFreely-MultiPlatform (macOS)" */ = {
isa = XCConfigurationList;
buildConfigurations = (
17DF32B624C87D3500BCE2E3 /* Debug */,
17DF32B724C87D3500BCE2E3 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
17DF32B824C87D3500BCE2E3 /* Build configuration list for PBXNativeTarget "Tests iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
17DF32B924C87D3500BCE2E3 /* Debug */,
17DF32BA24C87D3500BCE2E3 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
17DF32BB24C87D3500BCE2E3 /* Build configuration list for PBXNativeTarget "Tests macOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
17DF32BC24C87D3500BCE2E3 /* Debug */,
17DF32BD24C87D3500BCE2E3 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
- 1714DD63260BAC14000C0DFF /* XCRemoteSwiftPackageReference "writefreely-swift" */ = {
+ 1784D2EB27946D880033E72E /* XCRemoteSwiftPackageReference "writefreely-swift" */ = {
isa = XCRemoteSwiftPackageReference;
- repositoryURL = "git@github.com:writefreely/writefreely-swift.git";
+ repositoryURL = "https://github.com/writefreely/writefreely-swift";
requirement = {
kind = upToNextMajorVersion;
- minimumVersion = 0.3.2;
+ minimumVersion = 0.3.4;
};
};
- 17A4FED825924AF70037E96B /* XCRemoteSwiftPackageReference "Sparkle" */ = {
+ 17D4926327947B4D0035BD7E /* XCRemoteSwiftPackageReference "Sparkle" */ = {
isa = XCRemoteSwiftPackageReference;
- repositoryURL = "https://github.com/writefreely/Sparkle";
+ repositoryURL = "https://github.com/sparkle-project/Sparkle";
requirement = {
- branch = master;
- kind = branch;
+ kind = upToNextMinorVersion;
+ minimumVersion = 2.0.0;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
- 1714DD64260BAC14000C0DFF /* WriteFreely */ = {
+ 1784D2EC27946D880033E72E /* WriteFreely */ = {
isa = XCSwiftPackageProductDependency;
- package = 1714DD63260BAC14000C0DFF /* XCRemoteSwiftPackageReference "writefreely-swift" */;
+ package = 1784D2EB27946D880033E72E /* XCRemoteSwiftPackageReference "writefreely-swift" */;
productName = WriteFreely;
};
- 1714DD6A260BAC2C000C0DFF /* WriteFreely */ = {
+ 1784D2EE27946D9A0033E72E /* WriteFreely */ = {
isa = XCSwiftPackageProductDependency;
- package = 1714DD63260BAC14000C0DFF /* XCRemoteSwiftPackageReference "writefreely-swift" */;
+ package = 1784D2EB27946D880033E72E /* XCRemoteSwiftPackageReference "writefreely-swift" */;
productName = WriteFreely;
};
- 172E101A2735C54400061372 /* WriteFreely */ = {
+ 1784D2F027946DA10033E72E /* WriteFreely */ = {
isa = XCSwiftPackageProductDependency;
- package = 1714DD63260BAC14000C0DFF /* XCRemoteSwiftPackageReference "writefreely-swift" */;
+ package = 1784D2EB27946D880033E72E /* XCRemoteSwiftPackageReference "writefreely-swift" */;
productName = WriteFreely;
};
- 17A4FED925924AF70037E96B /* Sparkle */ = {
+ 17D4926427947B4D0035BD7E /* Sparkle */ = {
isa = XCSwiftPackageProductDependency;
- package = 17A4FED825924AF70037E96B /* XCRemoteSwiftPackageReference "Sparkle" */;
+ package = 17D4926327947B4D0035BD7E /* XCRemoteSwiftPackageReference "Sparkle" */;
productName = Sparkle;
};
/* End XCSwiftPackageProductDependency section */
/* Begin XCVersionGroup section */
1756DBB524FED3A400207AB8 /* LocalStorageModel.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
1756DBB624FED3A400207AB8 /* LocalStorageModel.xcdatamodel */,
);
currentVersion = 1756DBB624FED3A400207AB8 /* LocalStorageModel.xcdatamodel */;
path = LocalStorageModel.xcdatamodeld;
sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel;
};
/* End XCVersionGroup section */
};
rootObject = 17DF327C24C87D3300BCE2E3 /* Project object */;
}
diff --git a/WriteFreely-MultiPlatform.xcodeproj/xcuserdata/angelo.xcuserdatad/xcschemes/xcschememanagement.plist b/WriteFreely-MultiPlatform.xcodeproj/xcuserdata/angelo.xcuserdatad/xcschemes/xcschememanagement.plist
index e5b216c..33a3444 100644
--- a/WriteFreely-MultiPlatform.xcodeproj/xcuserdata/angelo.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/WriteFreely-MultiPlatform.xcodeproj/xcuserdata/angelo.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -1,24 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>ActionExtension-iOS.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
- <integer>2</integer>
+ <integer>1</integer>
</dict>
<key>WriteFreely-MultiPlatform (iOS).xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
- <integer>1</integer>
+ <integer>2</integer>
</dict>
<key>WriteFreely-MultiPlatform (macOS).xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
</dict>
</plist>
diff --git a/macOS/AppDelegate.swift b/macOS/AppDelegate.swift
index e002e64..410ffe9 100644
--- a/macOS/AppDelegate.swift
+++ b/macOS/AppDelegate.swift
@@ -1,61 +1,38 @@
import Cocoa
import Sparkle
class AppDelegate: NSObject, NSApplicationDelegate {
- func applicationWillFinishLaunching(_ notification: Notification) {
- // Check UserDefaults for values; if the key doesn't exist (e.g., if MacUpdatesView hasn't ever been shown),
- // bool(forKey:) returns false, so set SUUpdater.shared() appropriately.
- let automaticallyChecksForUpdates = UserDefaults.shared.bool(forKey: WFDefaults.automaticallyChecksForUpdates)
- let subscribeToBetaUpdates = UserDefaults.shared.bool(forKey: WFDefaults.subscribeToBetaUpdates)
-
- // Set Sparkle properties.
- SUUpdater.shared()?.automaticallyChecksForUpdates = automaticallyChecksForUpdates
- if subscribeToBetaUpdates {
- SUUpdater.shared()?.feedURL = URL(string: AppcastFeedUrl.beta.rawValue)
- } else {
- SUUpdater.shared()?.feedURL = URL(string: AppcastFeedUrl.release.rawValue)
- }
-
- // If enabled, check for updates.
- if automaticallyChecksForUpdates {
- SUUpdater.shared()?.checkForUpdatesInBackground()
- }
- }
-
// MARK: - Window handling when miniaturized into app icon on the Dock
// Credit to Henry Cooper (pillboxer) on GitHub:
// https://github.com/tact/beta-bugs/issues/31#issuecomment-855914705
// If the window is currently minimized into the Dock, de-miniaturize it (note that if it's minimized
// and the user uses OPT+TAB to switch to it, it will be de-miniaturized and brought to the foreground).
func applicationDidBecomeActive(_ notification: Notification) {
- print("💬 Fired:", #function)
if let window = NSApp.windows.first {
window.deminiaturize(nil)
}
}
// If we're miniaturizing the window, deactivate it as well by activating Finder.app (note that
// this will bring any Finder windows that are behind other apps to the foreground).
func applicationDidChangeOcclusionState(_ notification: Notification) {
- print("💬 Fired:", #function)
if let window = NSApp.windows.first, window.isMiniaturized {
NSWorkspace.shared.runningApplications.first(where: {
$0.activationPolicy == .regular
})?.activate(options: .activateAllWindows)
}
}
lazy var windows = NSWindow()
func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
- print("💬 Fired:", #function)
if !flag {
for window in sender.windows {
window.makeKeyAndOrderFront(self)
}
}
return true
}
}
diff --git a/macOS/PostEditor/MacEditorTextView.swift b/macOS/PostEditor/MacEditorTextView.swift
index 601052a..9c11d8a 100644
--- a/macOS/PostEditor/MacEditorTextView.swift
+++ b/macOS/PostEditor/MacEditorTextView.swift
@@ -1,217 +1,217 @@
// Based on:
//
// MacEditorTextView
// Copyright (c) Thiago Holanda 2020
// https://twitter.com/tholanda
//
// MIT license
//
// See: https://gist.github.com/unnamedd/6e8c3fbc806b8deb60fa65d6b9affab0
import Combine
import SwiftUI
struct MacEditorTextView: NSViewRepresentable {
@Binding var text: String
var isFirstResponder: Bool = false
var isEditable: Bool = true
var font: NSFont? = NSFont(name: PostAppearance.serif.rawValue, size: 17)
var onEditingChanged: () -> Void = {}
var onCommit: () -> Void = {}
var onTextChange: (String) -> Void = { _ in }
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeNSView(context: Context) -> CustomTextView {
let textView = CustomTextView(
text: text,
isEditable: isEditable,
isFirstResponder: isFirstResponder,
font: font
)
textView.delegate = context.coordinator
return textView
}
func updateNSView(_ view: CustomTextView, context: Context) {
view.text = text
view.selectedRanges = context.coordinator.selectedRanges
}
}
// MARK: - Coordinator
extension MacEditorTextView {
class Coordinator: NSObject, NSTextViewDelegate {
var parent: MacEditorTextView
var selectedRanges: [NSValue] = []
var didBecomeFirstResponder: Bool = false
init(_ parent: MacEditorTextView) {
self.parent = parent
}
func textDidBeginEditing(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else {
return
}
self.parent.text = textView.string
self.parent.onEditingChanged()
}
func textDidChange(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else {
return
}
self.parent.text = textView.string
self.selectedRanges = textView.selectedRanges
self.parent.onTextChange(textView.string)
}
func textDidEndEditing(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else {
return
}
self.parent.text = textView.string
self.parent.onCommit()
}
}
}
// MARK: - CustomTextView
final class CustomTextView: NSView {
private var isFirstResponder: Bool
private var isEditable: Bool
private var font: NSFont?
weak var delegate: NSTextViewDelegate?
var text: String {
didSet {
textView.string = text
}
}
var selectedRanges: [NSValue] = [] {
didSet {
guard selectedRanges.count > 0 else {
return
}
textView.selectedRanges = selectedRanges
}
}
private lazy var scrollView: NSScrollView = {
let scrollView = NSScrollView()
scrollView.drawsBackground = false
scrollView.borderType = .noBorder
scrollView.hasVerticalScroller = true
scrollView.hasHorizontalRuler = false
scrollView.autoresizingMask = [.width, .height]
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
}()
private lazy var textView: NSTextView = {
let contentSize = scrollView.contentSize
let textStorage = NSTextStorage()
let layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer(containerSize: scrollView.frame.size)
textContainer.widthTracksTextView = true
textContainer.containerSize = NSSize(
width: contentSize.width,
height: CGFloat.greatestFiniteMagnitude
)
layoutManager.addTextContainer(textContainer)
let paragraphStyle = NSMutableParagraphStyle()
let lineSpacing: CGFloat = 8.5
paragraphStyle.lineSpacing = lineSpacing
let textView = NSTextView(frame: .zero, textContainer: textContainer)
textView.autoresizingMask = .width
textView.delegate = self.delegate
textView.drawsBackground = false
textView.font = self.font
textView.defaultParagraphStyle = paragraphStyle
textView.isEditable = self.isEditable
textView.isHorizontallyResizable = false
textView.isVerticallyResizable = true
textView.maxSize = NSSize(
width: CGFloat.greatestFiniteMagnitude,
height: CGFloat.greatestFiniteMagnitude
)
textView.minSize = NSSize(width: 0, height: contentSize.height)
textView.textColor = NSColor.labelColor
textView.allowsUndo = true
textView.usesFindPanel = true
textView.isAutomaticDashSubstitutionEnabled = false
textView.isRichText = false
textView.typingAttributes = [
- .paragraphStyle: paragraphStyle, // H/T Daniel Jalkut
- .font: font,
+ .paragraphStyle: paragraphStyle, // H/T Daniel Jalkut
+ .font: font ?? NSFont.systemFont(ofSize: 17), // Fall back to system font if we can't unwrap font argument
.foregroundColor: NSColor.labelColor
]
return textView
}()
// MARK: - Init
init(text: String, isEditable: Bool, isFirstResponder: Bool, font: NSFont?) {
self.font = font
self.isFirstResponder = isFirstResponder
self.isEditable = isEditable
self.text = text
super.init(frame: .zero)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Life cycle
override func viewWillDraw() {
super.viewWillDraw()
setupScrollViewConstraints()
setupTextView()
if isFirstResponder {
self.window?.makeFirstResponder(self.textView)
}
}
func setupScrollViewConstraints() {
scrollView.translatesAutoresizingMaskIntoConstraints = false
addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: topAnchor),
scrollView.trailingAnchor.constraint(equalTo: trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: bottomAnchor),
scrollView.leadingAnchor.constraint(equalTo: leadingAnchor)
])
}
func setupTextView() {
scrollView.documentView = textView
}
}
diff --git a/macOS/Settings/MacUpdatesView.swift b/macOS/Settings/MacUpdatesView.swift
index 53b4f0e..afb6c48 100644
--- a/macOS/Settings/MacUpdatesView.swift
+++ b/macOS/Settings/MacUpdatesView.swift
@@ -1,95 +1,91 @@
import SwiftUI
import Sparkle
-enum AppcastFeedUrl: String {
- case release = "https://writefreely-files.s3.amazonaws.com/apps/mac/appcast.xml"
- case beta = "https://writefreely-files.s3.amazonaws.com/apps/mac/appcast-beta.xml"
-}
-
struct MacUpdatesView: View {
+ @ObservedObject var updaterViewModel: MacUpdatesViewModel
+
@AppStorage(WFDefaults.automaticallyChecksForUpdates, store: UserDefaults.shared)
var automaticallyChecksForUpdates: Bool = false
@AppStorage(WFDefaults.subscribeToBetaUpdates, store: UserDefaults.shared)
var subscribeToBetaUpdates: Bool = false
+
@State private var lastUpdateCheck: Date?
private let betaWarningString = """
To get brand new features before each official release, choose "Test versions." Note that test versions may have bugs \
that can cause crashes and data loss.
"""
static let lastUpdateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .short
formatter.doesRelativeDateFormatting = true
return formatter
}()
var body: some View {
VStack(spacing: 24) {
Toggle(isOn: $automaticallyChecksForUpdates, label: {
Text("Check for updates automatically")
})
VStack {
Button(action: {
- SUUpdater.shared()?.checkForUpdates(self)
- DispatchQueue.main.async {
- lastUpdateCheck = SUUpdater.shared()?.lastUpdateCheckDate
+ updaterViewModel.checkForUpdates()
+ // There's a delay between requesting an update, and the timestamp for that update request being
+ // written to user defaults; we therefore delay updating the "Last checked" UI for one second.
+ DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
+ lastUpdateCheck = updaterViewModel.getLastUpdateCheckDate()
}
}, label: {
Text("Check For Updates")
})
HStack {
Text("Last checked:")
.font(.caption)
if let lastUpdateCheck = lastUpdateCheck {
Text(lastUpdateCheck, formatter: Self.lastUpdateFormatter)
.font(.caption)
} else {
Text("Never")
.font(.caption)
}
}
}
VStack(spacing: 16) {
HStack(alignment: .top) {
Text("Download:")
Picker(selection: $subscribeToBetaUpdates, label: Text("Download:"), content: {
Text("Release versions").tag(false)
Text("Test versions").tag(true)
})
.pickerStyle(RadioGroupPickerStyle())
.labelsHidden()
}
Text(betaWarningString)
.frame(width: 350)
.foregroundColor(.secondary)
}
}
.padding()
.onAppear {
- lastUpdateCheck = SUUpdater.shared()?.lastUpdateCheckDate
+ lastUpdateCheck = updaterViewModel.getLastUpdateCheckDate()
}
.onChange(of: automaticallyChecksForUpdates) { value in
- SUUpdater.shared()?.automaticallyChecksForUpdates = value
+ updaterViewModel.automaticallyCheckForUpdates = value
}
- .onChange(of: subscribeToBetaUpdates) { value in
- if value {
- SUUpdater.shared()?.feedURL = URL(string: AppcastFeedUrl.beta.rawValue)
- } else {
- SUUpdater.shared()?.feedURL = URL(string: AppcastFeedUrl.release.rawValue)
- }
+ .onChange(of: subscribeToBetaUpdates) { _ in
+ updaterViewModel.toggleAllowedChannels()
}
}
}
struct MacUpdatesView_Previews: PreviewProvider {
static var previews: some View {
- MacUpdatesView()
+ MacUpdatesView(updaterViewModel: MacUpdatesViewModel())
}
}
diff --git a/macOS/Settings/MacUpdatesViewModel.swift b/macOS/Settings/MacUpdatesViewModel.swift
new file mode 100644
index 0000000..b960524
--- /dev/null
+++ b/macOS/Settings/MacUpdatesViewModel.swift
@@ -0,0 +1,73 @@
+/// See https://sparkle-project.org/documentation/programmatic-setup#create-an-updater-in-swiftui
+
+import SwiftUI
+import Sparkle
+
+/// This view model class manages Sparkle's updater and publishes when new updates are allowed to be checked.
+final class MacUpdatesViewModel: ObservableObject {
+
+ @Published var canCheckForUpdates = false
+ private let updaterController: SPUStandardUpdaterController
+ private let updaterDelegate = MacUpdatesViewModelDelegate()
+
+ var automaticallyCheckForUpdates: Bool {
+ get {
+ return updaterController.updater.automaticallyChecksForUpdates
+ }
+ set(newValue) {
+ updaterController.updater.automaticallyChecksForUpdates = newValue
+ }
+ }
+
+ init() {
+ updaterController = SPUStandardUpdaterController(startingUpdater: true,
+ updaterDelegate: updaterDelegate,
+ userDriverDelegate: nil)
+
+ updaterController.updater.publisher(for: \.canCheckForUpdates)
+ .assign(to: &$canCheckForUpdates)
+
+ if automaticallyCheckForUpdates {
+ updaterController.updater.checkForUpdatesInBackground()
+ }
+ }
+
+ func checkForUpdates() {
+ updaterController.checkForUpdates(nil)
+ }
+
+ func getLastUpdateCheckDate() -> Date? {
+ return updaterController.updater.lastUpdateCheckDate
+ }
+
+ @discardableResult
+ func toggleAllowedChannels() -> Set<String> {
+ return updaterDelegate.allowedChannels(for: updaterController.updater)
+ }
+
+}
+
+final class MacUpdatesViewModelDelegate: NSObject, SPUUpdaterDelegate {
+
+ @AppStorage(WFDefaults.subscribeToBetaUpdates, store: UserDefaults.shared)
+ var subscribeToBetaUpdates: Bool = false
+
+ func allowedChannels(for updater: SPUUpdater) -> Set<String> {
+ let allowedChannels = Set(subscribeToBetaUpdates ? ["beta"] : [])
+ return allowedChannels
+ }
+
+}
+
+// This additional view is needed for the disabled state on the menu item to work properly before Monterey.
+// See https://stackoverflow.com/questions/68553092/menu-not-updating-swiftui-bug for more information
+struct CheckForUpdatesView: View {
+
+ @ObservedObject var updaterViewModel: MacUpdatesViewModel
+
+ var body: some View {
+ Button("Check for Updates…", action: updaterViewModel.checkForUpdates)
+ .disabled(!updaterViewModel.canCheckForUpdates)
+ }
+
+}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Jan 31, 9:46 AM (4 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3145684

Event Timeline