diff --git a/ClientKit/.gitignore b/ClientKit/.gitignore new file mode 100644 index 0000000..3b29812 --- /dev/null +++ b/ClientKit/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/ClientKit/Package.swift b/ClientKit/Package.swift new file mode 100644 index 0000000..6e7a9d5 --- /dev/null +++ b/ClientKit/Package.swift @@ -0,0 +1,36 @@ +// swift-tools-version: 5.8 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "ClientKit", + platforms: [ + .iOS(.v16), + .macOS(.v12), + .watchOS(.v8) + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "ClientKit", + targets: ["ClientKit"]) + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + .package(name: "PixelfedKit", path: "../PixelfedKit") + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "ClientKit", + dependencies: [ + .product(name: "PixelfedKit", package: "PixelfedKit") + ] + ), + .testTarget( + name: "ClientKitTests", + dependencies: ["ClientKit"]) + ] +) diff --git a/Vernissage/EnvironmentObjects/Client+Account.swift b/ClientKit/Sources/ClientKit/Client+Account.swift similarity index 95% rename from Vernissage/EnvironmentObjects/Client+Account.swift rename to ClientKit/Sources/ClientKit/Client+Account.swift index 0125dcd..4b03c03 100644 --- a/Vernissage/EnvironmentObjects/Client+Account.swift +++ b/ClientKit/Sources/ClientKit/Client+Account.swift @@ -82,7 +82,7 @@ extension Client { return try await pixelfedClient.bookmarks(limit: limit, page: page) } - func update(displayName: String, bio: String, website: String, locked: Bool, image: Data?) async throws -> Account { + public func update(displayName: String, bio: String, website: String, locked: Bool, image: Data?) async throws -> Account { return try await pixelfedClient.update(displayName: displayName, bio: bio, website: website, @@ -90,7 +90,7 @@ extension Client { image: image) } - func avatar(image: Data?) async throws -> Account { + public func avatar(image: Data?) async throws -> Account { return try await pixelfedClient.avatar(image: image) } } diff --git a/Vernissage/EnvironmentObjects/Client+Blocks.swift b/ClientKit/Sources/ClientKit/Client+Blocks.swift similarity index 100% rename from Vernissage/EnvironmentObjects/Client+Blocks.swift rename to ClientKit/Sources/ClientKit/Client+Blocks.swift diff --git a/Vernissage/EnvironmentObjects/Client+Instance.swift b/ClientKit/Sources/ClientKit/Client+Instance.swift similarity index 83% rename from Vernissage/EnvironmentObjects/Client+Instance.swift rename to ClientKit/Sources/ClientKit/Client+Instance.swift index 3f56f98..47060f2 100644 --- a/Vernissage/EnvironmentObjects/Client+Instance.swift +++ b/ClientKit/Sources/ClientKit/Client+Instance.swift @@ -9,7 +9,7 @@ import PixelfedKit extension Client { public class Instances { - func instances(instanceUrls: [String]) async -> [Instance] { + public func instances(instanceUrls: [String]) async -> [Instance] { var instances: [Instance] = [] // Now we have to download information about each instance. @@ -24,7 +24,7 @@ extension Client { return nil } catch { - ErrorService.shared.handle(error, message: "Cannot download instance information: \(url.string)") + print("Error [Cannot download instance information: \(url.string)]: \(error.localizedDescription)") return nil } } @@ -40,7 +40,7 @@ extension Client { return instances } - func instance(url: URL) async throws -> Instance { + public func instance(url: URL) async throws -> Instance { let client = PixelfedClient(baseURL: url) return try await client.readInstanceInformation() } diff --git a/Vernissage/EnvironmentObjects/Client+Media.swift b/ClientKit/Sources/ClientKit/Client+Media.swift similarity index 67% rename from Vernissage/EnvironmentObjects/Client+Media.swift rename to ClientKit/Sources/ClientKit/Client+Media.swift index b6ed444..4e0029f 100644 --- a/Vernissage/EnvironmentObjects/Client+Media.swift +++ b/ClientKit/Sources/ClientKit/Client+Media.swift @@ -9,11 +9,11 @@ import PixelfedKit extension Client { public class Media: BaseClient { - func upload(data: Data, fileName: String, mimeType: String) async throws -> UploadedAttachment? { + public func upload(data: Data, fileName: String, mimeType: String) async throws -> UploadedAttachment? { return try await pixelfedClient.upload(data: data, fileName: fileName, mimeType: mimeType) } - func update(id: String, description: String?, focus: CGPoint?) async throws -> UploadedAttachment? { + public func update(id: String, description: String?, focus: CGPoint?) async throws -> UploadedAttachment? { return try await pixelfedClient.update(id: id, description: description, focus: focus) } } diff --git a/Vernissage/EnvironmentObjects/Client+Mutes.swift b/ClientKit/Sources/ClientKit/Client+Mutes.swift similarity index 100% rename from Vernissage/EnvironmentObjects/Client+Mutes.swift rename to ClientKit/Sources/ClientKit/Client+Mutes.swift diff --git a/Vernissage/EnvironmentObjects/Client+Notifications.swift b/ClientKit/Sources/ClientKit/Client+Notifications.swift similarity index 100% rename from Vernissage/EnvironmentObjects/Client+Notifications.swift rename to ClientKit/Sources/ClientKit/Client+Notifications.swift diff --git a/Vernissage/EnvironmentObjects/Client+Places.swift b/ClientKit/Sources/ClientKit/Client+Places.swift similarity index 100% rename from Vernissage/EnvironmentObjects/Client+Places.swift rename to ClientKit/Sources/ClientKit/Client+Places.swift diff --git a/Vernissage/EnvironmentObjects/Client+Report.swift b/ClientKit/Sources/ClientKit/Client+Report.swift similarity index 51% rename from Vernissage/EnvironmentObjects/Client+Report.swift rename to ClientKit/Sources/ClientKit/Client+Report.swift index 41a06ed..426889d 100644 --- a/Vernissage/EnvironmentObjects/Client+Report.swift +++ b/ClientKit/Sources/ClientKit/Client+Report.swift @@ -9,8 +9,8 @@ import PixelfedKit extension Client { public class Reports: BaseClient { - func report(objectType: Report.ObjectType, objectId: EntityId, reportType: Report.ReportType) async throws -> Report { - return try await pixelfedClient.report(objectType: objectType, objectId: objectId, reportType: reportType) + public func report(objectType: Report.ObjectType, objectId: EntityId, reportType: Report.ReportType) async throws { + try await pixelfedClient.report(objectType: objectType, objectId: objectId, reportType: reportType) } } } diff --git a/Vernissage/EnvironmentObjects/Client+Search.swift b/ClientKit/Sources/ClientKit/Client+Search.swift similarity index 100% rename from Vernissage/EnvironmentObjects/Client+Search.swift rename to ClientKit/Sources/ClientKit/Client+Search.swift diff --git a/Vernissage/EnvironmentObjects/Client+Statuses.swift b/ClientKit/Sources/ClientKit/Client+Statuses.swift similarity index 75% rename from Vernissage/EnvironmentObjects/Client+Statuses.swift rename to ClientKit/Sources/ClientKit/Client+Statuses.swift index edd9210..5e6ce4c 100644 --- a/Vernissage/EnvironmentObjects/Client+Statuses.swift +++ b/ClientKit/Sources/ClientKit/Client+Statuses.swift @@ -14,47 +14,47 @@ extension Client { return try await pixelfedClient.status(statusId: statusId) } - func favourite(statusId: String) async throws -> Status? { + public func favourite(statusId: String) async throws -> Status? { return try await pixelfedClient.favourite(statusId: statusId) } - func unfavourite(statusId: String) async throws -> Status? { + public func unfavourite(statusId: String) async throws -> Status? { return try await pixelfedClient.unfavourite(statusId: statusId) } - func pin(statusId: String) async throws -> Status? { + public func pin(statusId: String) async throws -> Status? { return try await pixelfedClient.pin(statusId: statusId) } - func unpin(statusId: String) async throws -> Status? { + public func unpin(statusId: String) async throws -> Status? { return try await pixelfedClient.unpin(statusId: statusId) } - func boost(statusId: String) async throws -> Status? { + public func boost(statusId: String) async throws -> Status? { return try await pixelfedClient.boost(statusId: statusId) } - func unboost(statusId: String) async throws -> Status? { + public func unboost(statusId: String) async throws -> Status? { return try await pixelfedClient.unboost(statusId: statusId) } - func bookmark(statusId: String) async throws -> Status? { + public func bookmark(statusId: String) async throws -> Status? { return try await pixelfedClient.bookmark(statusId: statusId) } - func unbookmark(statusId: String) async throws -> Status? { + public func unbookmark(statusId: String) async throws -> Status? { return try await pixelfedClient.unbookmark(statusId: statusId) } - func new(status: Pixelfed.Statuses.Components) async throws -> Status? { + public func new(status: Pixelfed.Statuses.Components) async throws -> Status? { return try await pixelfedClient.new(statusComponents: status) } - func delete(statusId: String) async throws { + public func delete(statusId: String) async throws { try await pixelfedClient.delete(statusId: statusId) } - func comments(to statusId: String) async throws -> [CommentModel] { + public func comments(to statusId: String) async throws -> [CommentModel] { var commentViewModels: [CommentModel] = [] try await self.getCommentDescendants(to: statusId, showDivider: true, to: &commentViewModels) diff --git a/Vernissage/EnvironmentObjects/Client+Tags.swift b/ClientKit/Sources/ClientKit/Client+Tags.swift similarity index 100% rename from Vernissage/EnvironmentObjects/Client+Tags.swift rename to ClientKit/Sources/ClientKit/Client+Tags.swift diff --git a/Vernissage/EnvironmentObjects/Client+Timeline.swift b/ClientKit/Sources/ClientKit/Client+Timeline.swift similarity index 100% rename from Vernissage/EnvironmentObjects/Client+Timeline.swift rename to ClientKit/Sources/ClientKit/Client+Timeline.swift diff --git a/Vernissage/EnvironmentObjects/Client+Trends.swift b/ClientKit/Sources/ClientKit/Client+Trends.swift similarity index 100% rename from Vernissage/EnvironmentObjects/Client+Trends.swift rename to ClientKit/Sources/ClientKit/Client+Trends.swift diff --git a/Vernissage/EnvironmentObjects/Client.swift b/ClientKit/Sources/ClientKit/Client.swift similarity index 95% rename from Vernissage/EnvironmentObjects/Client.swift rename to ClientKit/Sources/ClientKit/Client.swift index 04e8988..bf11ab9 100644 --- a/Vernissage/EnvironmentObjects/Client.swift +++ b/ClientKit/Sources/ClientKit/Client.swift @@ -13,7 +13,7 @@ public class Client: ObservableObject { private var pixelfedClient: PixelfedClientAuthenticated? - func setAccount(account: AccountModel) { + public func setAccount(account: AccountModel) { guard let accessToken = account.accessToken else { return } @@ -21,7 +21,7 @@ public class Client: ObservableObject { self.pixelfedClient = PixelfedClient(baseURL: account.serverUrl).getAuthenticated(token: accessToken) } - func clearAccount() { + public func clearAccount() { self.pixelfedClient = nil } } diff --git a/Vernissage/Extensions/Data+Exif.swift b/ClientKit/Sources/ClientKit/Extensions/Data+Exif.swift similarity index 98% rename from Vernissage/Extensions/Data+Exif.swift rename to ClientKit/Sources/ClientKit/Extensions/Data+Exif.swift index 1028b66..f2f3bd2 100644 --- a/Vernissage/Extensions/Data+Exif.swift +++ b/ClientKit/Sources/ClientKit/Extensions/Data+Exif.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/Vernissage/Extensions/Double+Round.swift b/ClientKit/Sources/ClientKit/Extensions/Double+Round.swift similarity index 100% rename from Vernissage/Extensions/Double+Round.swift rename to ClientKit/Sources/ClientKit/Extensions/Double+Round.swift diff --git a/Vernissage/Extensions/Status+MediaAttachmentType.swift b/ClientKit/Sources/ClientKit/Extensions/Status+MediaAttachmentType.swift similarity index 94% rename from Vernissage/Extensions/Status+MediaAttachmentType.swift rename to ClientKit/Sources/ClientKit/Extensions/Status+MediaAttachmentType.swift index 7307a85..7732af2 100644 --- a/Vernissage/Extensions/Status+MediaAttachmentType.swift +++ b/ClientKit/Sources/ClientKit/Extensions/Status+MediaAttachmentType.swift @@ -7,7 +7,7 @@ import Foundation import PixelfedKit -extension [Status] { +public extension [Status] { func getStatusesWithImagesOnly() -> [Status] { return self.filter { status in status.statusContainsImage() @@ -15,7 +15,7 @@ extension [Status] { } } -extension Status { +public extension Status { func statusContainsImage() -> Bool { return getAllImageMediaAttachments().isEmpty == false } diff --git a/Vernissage/Extensions/String+Exif.swift b/ClientKit/Sources/ClientKit/Extensions/String+Exif.swift similarity index 96% rename from Vernissage/Extensions/String+Exif.swift rename to ClientKit/Sources/ClientKit/Extensions/String+Exif.swift index 052dcec..71b58a1 100644 --- a/Vernissage/Extensions/String+Exif.swift +++ b/ClientKit/Sources/ClientKit/Extensions/String+Exif.swift @@ -6,7 +6,7 @@ import Foundation -extension String { +public extension String { func calculateExifNumber() -> String? { guard self.contains("/") else { return self diff --git a/ClientKit/Sources/ClientKit/Models/AccountModel.swift b/ClientKit/Sources/ClientKit/Models/AccountModel.swift new file mode 100644 index 0000000..c6dce71 --- /dev/null +++ b/ClientKit/Sources/ClientKit/Models/AccountModel.swift @@ -0,0 +1,82 @@ +// +// https://mczachurski.dev +// Copyright © 2023 Marcin Czachurski and the repository contributors. +// Licensed under the Apache License 2.0. +// + +import Foundation + +public class AccountModel: ObservableObject, Identifiable { + public let id: String + public let accessToken: String? + public let refreshToken: String? + public let acct: String + public let avatar: URL? + public let clientId: String + public let clientSecret: String + public let clientVapidKey: String + public let createdAt: String + public let displayName: String? + public let followersCount: Int32 + public let followingCount: Int32 + public let header: URL? + public let locked: Bool + public let note: String? + public let serverUrl: URL + public let statusesCount: Int32 + public let url: URL? + public let username: String + public let lastSeenStatusId: String? + + @Published public var avatarData: Data? + + public init(id: String, + accessToken: String?, + refreshToken: String?, + acct: String, + avatar: URL?, + clientId: String, + clientSecret: String, + clientVapidKey: String, + createdAt: String, + displayName: String?, + followersCount: Int32, + followingCount: Int32, + header: URL?, + locked: Bool, + note: String?, + serverUrl: URL, + statusesCount: Int32, + url: URL?, + username: String, + lastSeenStatusId: String?, + avatarData: Data? = nil) { + self.id = id + self.accessToken = accessToken + self.refreshToken = refreshToken + self.acct = acct + self.avatar = avatar + self.clientId = clientId + self.clientSecret = clientSecret + self.clientVapidKey = clientVapidKey + self.createdAt = createdAt + self.displayName = displayName + self.followersCount = followersCount + self.followingCount = followingCount + self.header = header + self.locked = locked + self.note = note + self.serverUrl = serverUrl + self.statusesCount = statusesCount + self.url = url + self.username = username + self.lastSeenStatusId = lastSeenStatusId + self.avatarData = avatarData + } +} + +extension AccountModel: Equatable { + public static func == (lhs: AccountModel, rhs: AccountModel) -> Bool { + lhs.id == rhs.id + } +} diff --git a/Vernissage/Models/AttachmentModel.swift b/ClientKit/Sources/ClientKit/Models/AttachmentModel.swift similarity index 84% rename from Vernissage/Models/AttachmentModel.swift rename to ClientKit/Sources/ClientKit/Models/AttachmentModel.swift index 34035d4..b903d58 100644 --- a/Vernissage/Models/AttachmentModel.swift +++ b/ClientKit/Sources/ClientKit/Models/AttachmentModel.swift @@ -27,21 +27,21 @@ public class AttachmentModel: ObservableObject, Identifiable { @Published public var exifLens: String? @Published public var data: Data? - init(id: String, - type: MediaAttachment.MediaAttachmentType, - url: URL, - previewUrl: URL? = nil, - remoteUrl: URL? = nil, - description: String? = nil, - blurhash: String? = nil, - meta: Metadata? = nil, - exifCamera: String? = nil, - exifCreatedDate: String? = nil, - exifExposure: String? = nil, - exifLens: String? = nil, - metaImageWidth: Int32? = nil, - metaImageHeight: Int32? = nil, - data: Data? = nil + public init(id: String, + type: MediaAttachment.MediaAttachmentType, + url: URL, + previewUrl: URL? = nil, + remoteUrl: URL? = nil, + description: String? = nil, + blurhash: String? = nil, + meta: Metadata? = nil, + exifCamera: String? = nil, + exifCreatedDate: String? = nil, + exifExposure: String? = nil, + exifLens: String? = nil, + metaImageWidth: Int32? = nil, + metaImageHeight: Int32? = nil, + data: Data? = nil ) { self.id = id self.type = type @@ -118,7 +118,7 @@ public class AttachmentModel: ObservableObject, Identifiable { } extension [AttachmentModel] { - func getHighestImage() -> AttachmentModel? { + public func getHighestImage() -> AttachmentModel? { var attachment = self.first var imgHeight = 0.0 diff --git a/Vernissage/Models/CommentModel.swift b/ClientKit/Sources/ClientKit/Models/CommentModel.swift similarity index 64% rename from Vernissage/Models/CommentModel.swift rename to ClientKit/Sources/ClientKit/Models/CommentModel.swift index a2b1989..686e3fe 100644 --- a/Vernissage/Models/CommentModel.swift +++ b/ClientKit/Sources/ClientKit/Models/CommentModel.swift @@ -7,8 +7,13 @@ import Foundation public struct CommentModel { - var status: StatusModel - var showDivider: Bool + public var status: StatusModel + public var showDivider: Bool + + public init(status: StatusModel, showDivider: Bool) { + self.status = status + self.showDivider = showDivider + } } extension CommentModel: Equatable { diff --git a/Vernissage/Models/StatusModel.swift b/ClientKit/Sources/ClientKit/Models/StatusModel.swift similarity index 99% rename from Vernissage/Models/StatusModel.swift rename to ClientKit/Sources/ClientKit/Models/StatusModel.swift index a9dd09a..c13b29d 100644 --- a/Vernissage/Models/StatusModel.swift +++ b/ClientKit/Sources/ClientKit/Models/StatusModel.swift @@ -41,7 +41,7 @@ public class StatusModel: ObservableObject { @Published public var mediaAttachments: [AttachmentModel] - init(status: Status) { + public init(status: Status) { // If status has been rebloged we are saving orginal status here. let orginalStatus = status.reblog ?? status diff --git a/ClientKit/Tests/ClientKitTests/ClientKitTests.swift b/ClientKit/Tests/ClientKitTests/ClientKitTests.swift new file mode 100644 index 0000000..ea94749 --- /dev/null +++ b/ClientKit/Tests/ClientKitTests/ClientKitTests.swift @@ -0,0 +1,11 @@ +import XCTest +@testable import ClientKit + +final class ClientKitTests: XCTestCase { + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + // XCTAssertEqual(ClientKit().text, "Hello, World!") + } +} diff --git a/CoreData/AccountData+AccountModel.swift b/CoreData/AccountData+AccountModel.swift new file mode 100644 index 0000000..c3abe09 --- /dev/null +++ b/CoreData/AccountData+AccountModel.swift @@ -0,0 +1,35 @@ +// +// https://mczachurski.dev +// Copyright © 2023 Marcin Czachurski and the repository contributors. +// Licensed under the Apache License 2.0. +// + +import Foundation +import ClientKit + +extension AccountData { + func toAccountModel() -> AccountModel { + let accountModel = AccountModel(id: self.id, + accessToken: self.accessToken, + refreshToken: self.refreshToken, + acct: self.acct, + avatar: self.avatar, + clientId: self.clientId, + clientSecret: self.clientSecret, + clientVapidKey: self.clientVapidKey, + createdAt: self.createdAt, + displayName: self.displayName, + followersCount: self.followersCount, + followingCount: self.followingCount, + header: self.header, + locked: self.locked, + note: self.note, + serverUrl: self.serverUrl, + statusesCount: self.statusesCount, + url: self.url, + username: self.username, + lastSeenStatusId: self.lastSeenStatusId, + avatarData: self.avatarData) + return accountModel + } +} diff --git a/CoreData/AccountData+CoreDataClass.swift b/CoreData/AccountData+CoreDataClass.swift index ff342d8..3b9b9b3 100644 --- a/CoreData/AccountData+CoreDataClass.swift +++ b/CoreData/AccountData+CoreDataClass.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/CoreData/AccountDataHandler.swift b/CoreData/AccountDataHandler.swift index ad36367..641af21 100644 --- a/CoreData/AccountDataHandler.swift +++ b/CoreData/AccountDataHandler.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/CoreData/ApplicationSettings+CoreDataClass.swift b/CoreData/ApplicationSettings+CoreDataClass.swift index 1fb6cea..6025088 100644 --- a/CoreData/ApplicationSettings+CoreDataClass.swift +++ b/CoreData/ApplicationSettings+CoreDataClass.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/CoreData/ApplicationSettingsHandler.swift b/CoreData/ApplicationSettingsHandler.swift index f302c8c..8ebe66e 100644 --- a/CoreData/ApplicationSettingsHandler.swift +++ b/CoreData/ApplicationSettingsHandler.swift @@ -1,11 +1,12 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // import Foundation import CoreData +import EnvironmentKit class ApplicationSettingsHandler { public static let shared = ApplicationSettingsHandler() @@ -35,6 +36,36 @@ class ApplicationSettingsHandler { } } + func update(applicationState: ApplicationState) { + let defaultSettings = ApplicationSettingsHandler.shared.get() + + if let tintColor = TintColor(rawValue: Int(defaultSettings.tintColor)) { + applicationState.tintColor = tintColor + } + + if let theme = Theme(rawValue: Int(defaultSettings.theme)) { + applicationState.theme = theme + } + + if let avatarShape = AvatarShape(rawValue: Int(defaultSettings.avatarShape)) { + applicationState.avatarShape = avatarShape + } + + applicationState.activeIcon = defaultSettings.activeIcon + applicationState.showSensitive = defaultSettings.showSensitive + applicationState.showPhotoDescription = defaultSettings.showPhotoDescription + + if let menuPosition = MenuPosition(rawValue: Int(defaultSettings.menuPosition)) { + applicationState.menuPosition = menuPosition + } + + applicationState.hapticTabSelectionEnabled = defaultSettings.hapticTabSelectionEnabled + applicationState.hapticRefreshEnabled = defaultSettings.hapticRefreshEnabled + applicationState.hapticButtonPressEnabled = defaultSettings.hapticButtonPressEnabled + applicationState.hapticAnimationEnabled = defaultSettings.hapticAnimationEnabled + applicationState.hapticNotificationEnabled = defaultSettings.hapticNotificationEnabled + } + func set(accountId: String?) { let defaultSettings = self.get() defaultSettings.currentAccount = accountId diff --git a/CoreData/CoreDataHandler.swift b/CoreData/CoreDataHandler.swift index 6576179..b7c8e7f 100644 --- a/CoreData/CoreDataHandler.swift +++ b/CoreData/CoreDataHandler.swift @@ -1,10 +1,11 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // import CoreData +import EnvironmentKit public class CoreDataHandler { public static let shared = CoreDataHandler() diff --git a/EnvironmentKit/.gitignore b/EnvironmentKit/.gitignore new file mode 100644 index 0000000..3b29812 --- /dev/null +++ b/EnvironmentKit/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/EnvironmentKit/Package.swift b/EnvironmentKit/Package.swift new file mode 100644 index 0000000..7a7e0cb --- /dev/null +++ b/EnvironmentKit/Package.swift @@ -0,0 +1,36 @@ +// swift-tools-version: 5.8 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "EnvironmentKit", + platforms: [ + .iOS(.v16), + .macOS(.v12), + .watchOS(.v8) + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "EnvironmentKit", + targets: ["EnvironmentKit"]) + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + .package(name: "ClientKit", path: "../ClientKit") + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "EnvironmentKit", + dependencies: [ + .product(name: "ClientKit", package: "ClientKit") + ] + ), + .testTarget( + name: "EnvironmentKitTests", + dependencies: ["EnvironmentKit"]) + ] +) diff --git a/Vernissage/EnvironmentObjects/ApplicationState.swift b/EnvironmentKit/Sources/EnvironmentKit/ApplicationState.swift similarity index 67% rename from Vernissage/EnvironmentObjects/ApplicationState.swift rename to EnvironmentKit/Sources/EnvironmentKit/ApplicationState.swift index 6f90209..bc7ade4 100644 --- a/Vernissage/EnvironmentObjects/ApplicationState.swift +++ b/EnvironmentKit/Sources/EnvironmentKit/ApplicationState.swift @@ -1,12 +1,13 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // import Foundation import SwiftUI import PixelfedKit +import ClientKit public class ApplicationState: ObservableObject { public static let shared = ApplicationState() @@ -23,70 +24,70 @@ public class ApplicationState: ObservableObject { private static let defaults = Defaults() /// Actual signed in account. - @Published private(set) var account: AccountModel? + @Published public private(set) var account: AccountModel? /// The maximum number of allowed characters per status. - @Published private(set) var statusMaxCharacters = defaults.statusMaxCharacters + @Published public private(set) var statusMaxCharacters = defaults.statusMaxCharacters /// The maximum number of media attachments that can be added to a status. - @Published private(set) var statusMaxMediaAttachments = defaults.statusMaxMediaAttachments + @Published public private(set) var statusMaxMediaAttachments = defaults.statusMaxMediaAttachments /// Each URL in a status will be assumed to be exactly this many characters. - @Published private(set) var statusCharactersReservedPerUrl = defaults.statusCharactersReservedPerUrl + @Published public private(set) var statusCharactersReservedPerUrl = defaults.statusCharactersReservedPerUrl /// Last status seen by the user. - @Published var lastSeenStatusId: String? + @Published public var lastSeenStatusId: String? /// Amount of new statuses which are not displayed yet to the user. - @Published var amountOfNewStatuses = 0 + @Published public var amountOfNewStatuses = 0 /// Model for newly created comment. - @Published var newComment: CommentModel? + @Published public var newComment: CommentModel? /// Active icon name. - @Published var activeIcon = "Default" + @Published public var activeIcon = "Default" /// Tint color in whole application. - @Published var tintColor = TintColor.accentColor2 + @Published public var tintColor = TintColor.accentColor2 /// Application theme. - @Published var theme = Theme.system + @Published public var theme = Theme.system /// Avatar shape. - @Published var avatarShape = AvatarShape.circle + @Published public var avatarShape = AvatarShape.circle /// Status id for showed interaction row. - @Published var showInteractionStatusId = String.empty() + @Published public var showInteractionStatusId = "" /// Should we fire haptic when user change tabs. - @Published var hapticTabSelectionEnabled = true + @Published public var hapticTabSelectionEnabled = true /// Should we fire haptic when user refresh list. - @Published var hapticRefreshEnabled = true + @Published public var hapticRefreshEnabled = true /// Should we fire haptic when user tap button. - @Published var hapticButtonPressEnabled = true + @Published public var hapticButtonPressEnabled = true /// Should we fire haptic when animation is finished. - @Published var hapticAnimationEnabled = true + @Published public var hapticAnimationEnabled = true /// Should we fire haptic when notification occures. - @Published var hapticNotificationEnabled = true + @Published public var hapticNotificationEnabled = true /// Should sensitive photos without mask. - @Published var showSensitive = false + @Published public var showSensitive = false /// Should photo description for visually impaired be displayed. - @Published var showPhotoDescription = false + @Published public var showPhotoDescription = false /// Status which should be shown from URL. - @Published var showStatusId: String? + @Published public var showStatusId: String? /// Updated user profile. - @Published var updatedProfile: Account? + @Published public var updatedProfile: Account? /// Information which menu should be shown (top or bottom). - @Published var menuPosition = MenuPosition.top + @Published public var menuPosition = MenuPosition.top public func changeApplicationState(accountModel: AccountModel, instance: Instance?, lastSeenStatusId: String?) { self.account = accountModel diff --git a/Vernissage/Extensions/AvatarShape+Shape.swift b/EnvironmentKit/Sources/EnvironmentKit/Extensions/AvatarShape+Shape.swift similarity index 93% rename from Vernissage/Extensions/AvatarShape+Shape.swift rename to EnvironmentKit/Sources/EnvironmentKit/Extensions/AvatarShape+Shape.swift index 58ad328..b6d8c0b 100644 --- a/Vernissage/Extensions/AvatarShape+Shape.swift +++ b/EnvironmentKit/Sources/EnvironmentKit/Extensions/AvatarShape+Shape.swift @@ -7,7 +7,7 @@ import Foundation import SwiftUI -extension AvatarShape { +public extension AvatarShape { func shape() -> some Shape { switch self { case .circle: diff --git a/Vernissage/Extensions/Color+Assets.swift b/EnvironmentKit/Sources/EnvironmentKit/Extensions/Color+Assets.swift similarity index 95% rename from Vernissage/Extensions/Color+Assets.swift rename to EnvironmentKit/Sources/EnvironmentKit/Extensions/Color+Assets.swift index 78c6cea..b22b6a1 100644 --- a/Vernissage/Extensions/Color+Assets.swift +++ b/EnvironmentKit/Sources/EnvironmentKit/Extensions/Color+Assets.swift @@ -6,7 +6,7 @@ import SwiftUI -extension Color { +public extension Color { // MARK: - Text Colors static let dangerColor = Color("DangerColor") @@ -28,7 +28,7 @@ extension Color { static let accentColor10 = Color("AccentColor10") } -extension Color { +public extension Color { func toUIColor() -> UIColor { UIColor(self) } diff --git a/Vernissage/Extensions/Color+SystemColors.swift b/EnvironmentKit/Sources/EnvironmentKit/Extensions/Color+SystemColors.swift similarity index 99% rename from Vernissage/Extensions/Color+SystemColors.swift rename to EnvironmentKit/Sources/EnvironmentKit/Extensions/Color+SystemColors.swift index 2b76ded..a04d735 100644 --- a/Vernissage/Extensions/Color+SystemColors.swift +++ b/EnvironmentKit/Sources/EnvironmentKit/Extensions/Color+SystemColors.swift @@ -6,7 +6,7 @@ import SwiftUI -extension Color { +public extension Color { // MARK: - Text Colors static let lightText = Color(UIColor.lightText) diff --git a/Vernissage/Extensions/Theme+ColorScheme.swift b/EnvironmentKit/Sources/EnvironmentKit/Extensions/Theme+ColorScheme.swift similarity index 85% rename from Vernissage/Extensions/Theme+ColorScheme.swift rename to EnvironmentKit/Sources/EnvironmentKit/Extensions/Theme+ColorScheme.swift index 3f92078..cc47cf2 100644 --- a/Vernissage/Extensions/Theme+ColorScheme.swift +++ b/EnvironmentKit/Sources/EnvironmentKit/Extensions/Theme+ColorScheme.swift @@ -7,8 +7,8 @@ import Foundation import SwiftUI -extension Theme { - public func colorScheme() -> ColorScheme? { +public extension Theme { + func colorScheme() -> ColorScheme? { switch self { case .system: return nil diff --git a/Vernissage/Extensions/TintColor+Color.swift b/EnvironmentKit/Sources/EnvironmentKit/Extensions/TintColor+Color.swift similarity index 90% rename from Vernissage/Extensions/TintColor+Color.swift rename to EnvironmentKit/Sources/EnvironmentKit/Extensions/TintColor+Color.swift index 035a8fb..4de8a44 100644 --- a/Vernissage/Extensions/TintColor+Color.swift +++ b/EnvironmentKit/Sources/EnvironmentKit/Extensions/TintColor+Color.swift @@ -7,8 +7,8 @@ import Foundation import SwiftUI -extension TintColor { - public func color() -> Color { +public extension TintColor { + func color() -> Color { switch self { case .accentColor1: return Color.accentColor1 @@ -33,7 +33,7 @@ extension TintColor { } } - public func uiColor() -> UIColor { + func uiColor() -> UIColor { return self.color().toUIColor() } } diff --git a/Models/AppConstants.swift b/EnvironmentKit/Sources/EnvironmentKit/Models/AppConstants.swift similarity index 100% rename from Models/AppConstants.swift rename to EnvironmentKit/Sources/EnvironmentKit/Models/AppConstants.swift diff --git a/Models/AvatarShape.swift b/EnvironmentKit/Sources/EnvironmentKit/Models/AvatarShape.swift similarity index 100% rename from Models/AvatarShape.swift rename to EnvironmentKit/Sources/EnvironmentKit/Models/AvatarShape.swift diff --git a/Models/MenuPosition.swift b/EnvironmentKit/Sources/EnvironmentKit/Models/MenuPosition.swift similarity index 100% rename from Models/MenuPosition.swift rename to EnvironmentKit/Sources/EnvironmentKit/Models/MenuPosition.swift diff --git a/Models/Theme.swift b/EnvironmentKit/Sources/EnvironmentKit/Models/Theme.swift similarity index 100% rename from Models/Theme.swift rename to EnvironmentKit/Sources/EnvironmentKit/Models/Theme.swift diff --git a/Models/TintColor.swift b/EnvironmentKit/Sources/EnvironmentKit/Models/TintColor.swift similarity index 100% rename from Models/TintColor.swift rename to EnvironmentKit/Sources/EnvironmentKit/Models/TintColor.swift diff --git a/EnvironmentKit/Tests/EnvironmentKitTests/EnvironmentKitTests.swift b/EnvironmentKit/Tests/EnvironmentKitTests/EnvironmentKitTests.swift new file mode 100644 index 0000000..27cb6bd --- /dev/null +++ b/EnvironmentKit/Tests/EnvironmentKitTests/EnvironmentKitTests.swift @@ -0,0 +1,11 @@ +import XCTest +@testable import EnvironmentKit + +final class EnvironmentKitTests: XCTestCase { + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + // XCTAssertEqual(EnvironmentKit().text, "Hello, World!") + } +} diff --git a/Localization/en.lproj/Localizable.strings b/Localization/en.lproj/Localizable.strings index 611a6f2..9181c01 100644 --- a/Localization/en.lproj/Localizable.strings +++ b/Localization/en.lproj/Localizable.strings @@ -110,6 +110,8 @@ "userProfile.error.block" = "Block/unblock action failed."; "userProfile.error.relationship" = "Relationship action failed."; "userProfile.title.edit" = "Edit"; +"userProfile.title.muted" = "Muted"; +"userProfile.title.blocked" = "Blocked"; // Mark: Notifications view. "notifications.navigationBar.title" = "Notifications"; diff --git a/Localization/eu.lproj/Localizable.strings b/Localization/eu.lproj/Localizable.strings index 77c000e..ea9eb8c 100644 --- a/Localization/eu.lproj/Localizable.strings +++ b/Localization/eu.lproj/Localizable.strings @@ -2,7 +2,7 @@ "global.title.contentWarning" = "Eduki hunkigarria"; "global.title.seePost" = "Ikusi bidalketa"; "global.title.refresh" = "Freskatu"; -"global.title.momentsAgo" = "moments ago"; +"global.title.momentsAgo" = "oraintxe bertan"; // MARK: Global errors. "global.error.unexpected" = "Espero ez zen errorea."; @@ -110,6 +110,8 @@ "userProfile.error.block" = "Blokeatu/Blokeatzeari uzteak huts egin du."; "userProfile.error.relationship" = "Harreman ekintzak huts egin du."; "userProfile.title.edit" = "Editatu"; +"userProfile.title.muted" = "Mutututa"; +"userProfile.title.blocked" = "Blokeatuta"; // Mark: Notifications view. "notifications.navigationBar.title" = "Jakinarazpenak"; diff --git a/Localization/pl.lproj/Localizable.strings b/Localization/pl.lproj/Localizable.strings index 520623a..5814d1a 100644 --- a/Localization/pl.lproj/Localizable.strings +++ b/Localization/pl.lproj/Localizable.strings @@ -110,6 +110,8 @@ "userProfile.error.block" = "Błąd podczas blokowania/odblokowywania użytkownika."; "userProfile.error.relationship" = "Błąd podczas zmiany relacji z użytkownikiem."; "userProfile.title.edit" = "Edytuj"; +"userProfile.title.muted" = "Wyciszony"; +"userProfile.title.blocked" = "Zablokowany"; // Mark: Notifications view. "notifications.navigationBar.title" = "Powiadomienia"; diff --git a/PixelfedKit/Package.swift b/PixelfedKit/Package.swift index 5631fa6..cc18133 100644 --- a/PixelfedKit/Package.swift +++ b/PixelfedKit/Package.swift @@ -28,7 +28,11 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "PixelfedKit", - dependencies: ["OAuthSwift", "HTML2Markdown"]), + dependencies: [ + .product(name: "OAuthSwift", package: "OAuthSwift"), + .product(name: "HTML2Markdown", package: "HTML2Markdown") + ] + ), .testTarget( name: "PixelfedKitTests", dependencies: ["PixelfedKit"]) diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Account.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Account.swift index 67d5d99..3c97365 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Account.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Account.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Application.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Application.swift index d81b6be..901275d 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Application.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Application.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Context.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Context.swift index d78959b..2b00c4c 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Context.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Context.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Focus.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Focus.swift index 4834510..2e61f1d 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Focus.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Focus.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/ImageInfo.swift b/PixelfedKit/Sources/PixelfedKit/Entities/ImageInfo.swift index 81ea7e5..30096ab 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/ImageInfo.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/ImageInfo.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/ImageMetadata.swift b/PixelfedKit/Sources/PixelfedKit/Entities/ImageMetadata.swift index 8f80a19..43f7a6c 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/ImageMetadata.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/ImageMetadata.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Instance.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Instance.swift index fc763c9..326c5a9 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Instance.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Instance.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Markers.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Markers.swift index dba1cbd..107957d 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Markers.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Markers.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/MediaAttachment.swift b/PixelfedKit/Sources/PixelfedKit/Entities/MediaAttachment.swift index 733f94d..2dbedf2 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/MediaAttachment.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/MediaAttachment.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Mention.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Mention.swift index 318cff3..121e2f7 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Mention.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Mention.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Meta.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Meta.swift index a6c1bff..f555198 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Meta.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Meta.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Notification.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Notification.swift index 15c5950..d180874 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Notification.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Notification.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/PreviewCard.swift b/PixelfedKit/Sources/PixelfedKit/Entities/PreviewCard.swift index 4576950..49ef2f0 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/PreviewCard.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/PreviewCard.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Relationship.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Relationship.swift index 4f64d0a..0f496be 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Relationship.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Relationship.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Report.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Report.swift index ea211ae..11d2481 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Report.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Report.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/SearchResults.swift b/PixelfedKit/Sources/PixelfedKit/Entities/SearchResults.swift index 2fc749a..4df4fee 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/SearchResults.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/SearchResults.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Status.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Status.swift index 601d435..82e605d 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Status.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Status.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Tag.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Tag.swift index df8f779..37def91 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Tag.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Tag.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/UploadedAttachment.swift b/PixelfedKit/Sources/PixelfedKit/Entities/UploadedAttachment.swift index fd59c2c..bfab0a5 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/UploadedAttachment.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/UploadedAttachment.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Errors/ReportError.swift b/PixelfedKit/Sources/PixelfedKit/Errors/ReportError.swift new file mode 100644 index 0000000..834fe2b --- /dev/null +++ b/PixelfedKit/Sources/PixelfedKit/Errors/ReportError.swift @@ -0,0 +1,47 @@ +// +// https://mczachurski.dev +// Copyright © 2023 Marcin Czachurski and the repository contributors. +// Licensed under the Apache License 2.0. +// + +import Foundation + +public enum ReportError: Error { + case noSelfReports + case invalidObjectId + case duplicate + case invalidParameters + case invalidType + case invalidObject +} + +extension ReportError: LocalizedError { + public var errorDescription: String? { + switch self { + case .noSelfReports: + return NSLocalizedString("report.error.noSelfReports", + bundle: Bundle.module, + comment: "Self-reporting is not allowed.") + case .invalidObjectId: + return NSLocalizedString("report.error.invalidObjectId", + bundle: Bundle.module, + comment: "Incorrect object Id.") + case .duplicate: + return NSLocalizedString("report.error.duplicate", + bundle: Bundle.module, + comment: "The report has already been sent.") + case .invalidParameters: + return NSLocalizedString("report.error.invalidParameters", + bundle: Bundle.module, + comment: "Invalid report parameters.") + case .invalidType: + return NSLocalizedString("report.error.invalidType", + bundle: Bundle.module, + comment: "Invalid report type.") + case .invalidObject: + return NSLocalizedString("report.error.invalidObject", + bundle: Bundle.module, + comment: "Invalid object type.") + } + } +} diff --git a/PixelfedKit/Sources/PixelfedKit/Extensions/Primitive+AsString.swift b/PixelfedKit/Sources/PixelfedKit/Extensions/Primitive+AsString.swift index ad7569e..364b667 100644 --- a/PixelfedKit/Sources/PixelfedKit/Extensions/Primitive+AsString.swift +++ b/PixelfedKit/Sources/PixelfedKit/Extensions/Primitive+AsString.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Extensions/String+AsURL.swift b/PixelfedKit/Sources/PixelfedKit/Extensions/String+AsURL.swift index 0b25ff9..623591c 100644 --- a/PixelfedKit/Sources/PixelfedKit/Extensions/String+AsURL.swift +++ b/PixelfedKit/Sources/PixelfedKit/Extensions/String+AsURL.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Extensions/URL+OptionalString.swift b/PixelfedKit/Sources/PixelfedKit/Extensions/URL+OptionalString.swift index 31f7d07..7f82db2 100644 --- a/PixelfedKit/Sources/PixelfedKit/Extensions/URL+OptionalString.swift +++ b/PixelfedKit/Sources/PixelfedKit/Extensions/URL+OptionalString.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Networking/MultipartFormData.swift b/PixelfedKit/Sources/PixelfedKit/Networking/MultipartFormData.swift index 0d444bc..4cb4916 100644 --- a/PixelfedKit/Sources/PixelfedKit/Networking/MultipartFormData.swift +++ b/PixelfedKit/Sources/PixelfedKit/Networking/MultipartFormData.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Networking/TargetType.swift b/PixelfedKit/Sources/PixelfedKit/Networking/TargetType.swift index 71e80fa..7ded940 100644 --- a/PixelfedKit/Sources/PixelfedKit/Networking/TargetType.swift +++ b/PixelfedKit/Sources/PixelfedKit/Networking/TargetType.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Blocks.swift b/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Blocks.swift index 2a59390..e654955 100644 --- a/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Blocks.swift +++ b/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Blocks.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Convenience.swift b/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Convenience.swift index 70d00db..d4661d7 100644 --- a/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Convenience.swift +++ b/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Convenience.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Instances.swift b/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Instances.swift index 3f0dda4..be08fdb 100644 --- a/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Instances.swift +++ b/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Instances.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Mutes.swift b/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Mutes.swift index 01f3f34..27907e1 100644 --- a/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Mutes.swift +++ b/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Mutes.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Report.swift b/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Report.swift index 6e8a826..7fc3125 100644 --- a/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Report.swift +++ b/PixelfedKit/Sources/PixelfedKit/PixelfedClient+Report.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // @@ -9,13 +9,34 @@ import Foundation public extension PixelfedClientAuthenticated { func report(objectType: Report.ObjectType, objectId: EntityId, - reportType: Report.ReportType) async throws -> Report { + reportType: Report.ReportType) async throws { let request = try Self.request( for: baseURL, target: Pixelfed.Reports.report(objectType, objectId, reportType), withBearerToken: token ) - return try await downloadJson(Report.self, request: request) + // API reports returns bad request even if data is correct. + let (data, response) = try await urlSession.data(for: request) + + guard (response as? HTTPURLResponse)?.status?.responseType == .success else { + if let json = String(data: data, encoding: .utf8) { + if json.contains("ERROR_NO_SELF_REPORTS") { + throw ReportError.noSelfReports + } else if json.contains("ERROR_INVALID_OBJECT_ID") { + throw ReportError.invalidObjectId + } else if json.contains("ERROR_REPORT_DUPLICATE") { + throw ReportError.duplicate + } else if json.contains("ERROR_INVALID_PARAMS") { + throw ReportError.invalidParameters + } else if json.contains("ERROR_TYPE_INVALID") { + throw ReportError.invalidType + } else if json.contains("ERROR_REPORT_OBJECT_TYPE_INVALID") { + throw ReportError.invalidObject + } + } + + throw NetworkError.notSuccessResponse(response) + } } } diff --git a/PixelfedKit/Sources/PixelfedKit/PixelfedClient+StatusActions.swift b/PixelfedKit/Sources/PixelfedKit/PixelfedClient+StatusActions.swift index b7ad62c..0fb9493 100644 --- a/PixelfedKit/Sources/PixelfedKit/PixelfedClient+StatusActions.swift +++ b/PixelfedKit/Sources/PixelfedKit/PixelfedClient+StatusActions.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/PixelfedClient.swift b/PixelfedKit/Sources/PixelfedKit/PixelfedClient.swift index 0aea2ed..fd7a742 100644 --- a/PixelfedKit/Sources/PixelfedKit/PixelfedClient.swift +++ b/PixelfedKit/Sources/PixelfedKit/PixelfedClient.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Resources/en.lproj/Localizable.strings b/PixelfedKit/Sources/PixelfedKit/Resources/en.lproj/Localizable.strings index 40f7506..8106e7b 100644 --- a/PixelfedKit/Sources/PixelfedKit/Resources/en.lproj/Localizable.strings +++ b/PixelfedKit/Sources/PixelfedKit/Resources/en.lproj/Localizable.strings @@ -1,3 +1,11 @@ // MARK: Network errors. "global.error.notSuccessResponse" = "Server response: %@."; "global.error.unknownError" = "Unexpected error."; + +// Mark: Report errors. +"report.error.noSelfReports" = "Self-reporting is not allowed."; +"report.error.invalidObjectId" = "Incorrect object Id."; +"report.error.duplicate" = "The report has already been sent."; +"report.error.invalidParameters" = "Invalid report parameters."; +"report.error.invalidType" = "Invalid report type."; +"report.error.invalidObject" = "Invalid object type."; diff --git a/PixelfedKit/Sources/PixelfedKit/Resources/eu.lproj/Localizable.strings b/PixelfedKit/Sources/PixelfedKit/Resources/eu.lproj/Localizable.strings index 3de0a44..c6790e8 100644 --- a/PixelfedKit/Sources/PixelfedKit/Resources/eu.lproj/Localizable.strings +++ b/PixelfedKit/Sources/PixelfedKit/Resources/eu.lproj/Localizable.strings @@ -1,3 +1,11 @@ // MARK: Network errors. "global.error.notSuccessResponse" = "Zerbitzariaren erantzuna: %@."; "global.error.unknownError" = "Espero ez zen errorea."; + +// Mark: Report errors. +"report.error.noSelfReports" = "Ezin duzu zure burua salatu."; +"report.error.invalidObjectId" = "Elementuaren IDa ez da zuzena."; +"report.error.duplicate" = "Txostena bidali da dagoeneko."; +"report.error.invalidParameters" = "Txostenaren parametroak ez dira baliozkoak."; +"report.error.invalidType" = "Txosten-mota ez da baliozkoa."; +"report.error.invalidObject" = "Elementu-mota ez da baliozkoa."; diff --git a/PixelfedKit/Sources/PixelfedKit/Resources/pl.lproj/Localizable.strings b/PixelfedKit/Sources/PixelfedKit/Resources/pl.lproj/Localizable.strings index 6d6bf82..f570b2c 100644 --- a/PixelfedKit/Sources/PixelfedKit/Resources/pl.lproj/Localizable.strings +++ b/PixelfedKit/Sources/PixelfedKit/Resources/pl.lproj/Localizable.strings @@ -1,3 +1,11 @@ // MARK: Network errors. "global.error.notSuccessResponse" = "Odpowiedź serwera: %@."; "global.error.unknownError" = "Nieznany błąd serwera."; + +// Mark: Report errors. +"report.error.noSelfReports" = "Zgłaszanie siebie jest niedozwolone."; +"report.error.invalidObjectId" = "Niepoprawny Id obiektu."; +"report.error.duplicate" = "Zgłoszenie zostało już wysłane."; +"report.error.invalidParameters" = "Niepoprawne parametry zgłoszenia."; +"report.error.invalidType" = "Niepoprawny typ raportu."; +"report.error.invalidObject" = "Niepoprawny typ obiektu."; diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Accounts.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Accounts.swift index da8da36..f5ca0ac 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Accounts.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Accounts.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Apps.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Apps.swift index c75be90..d57f24a 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Apps.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Apps.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Blocks.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Blocks.swift index 120c793..767f625 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Blocks.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Blocks.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Bookmarks.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Bookmarks.swift index acb5fb1..e381ae0 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Bookmarks.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Bookmarks.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Favourites.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Favourites.swift index 02b4e0f..62b2f4f 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Favourites.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Favourites.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/FollowRequests.swift b/PixelfedKit/Sources/PixelfedKit/Targets/FollowRequests.swift index 94190eb..9f15795 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/FollowRequests.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/FollowRequests.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Follows.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Follows.swift index c9d7cc4..9e97730 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Follows.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Follows.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Instances.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Instances.swift index a352aef..0a3f534 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Instances.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Instances.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Marker.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Marker.swift index badeba6..bce8d2a 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Marker.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Marker.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Media.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Media.swift index 50d2da0..e8faf4f 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Media.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Media.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Mutes.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Mutes.swift index 96f02a7..d0dd46c 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Mutes.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Mutes.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Notifications.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Notifications.swift index 259c2db..2f97d67 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Notifications.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Notifications.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/OAuth.swift b/PixelfedKit/Sources/PixelfedKit/Targets/OAuth.swift index 3f185e5..298d57a 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/OAuth.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/OAuth.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Pixelfed.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Pixelfed.swift index 0510734..3db17b7 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Pixelfed.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Pixelfed.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Places.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Places.swift index 09c7ad1..30041a8 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Places.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Places.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Reports.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Reports.swift index 5113aaf..906ba61 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Reports.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Reports.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Search.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Search.swift index 8b178b9..c55f36b 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Search.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Search.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Statuses.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Statuses.swift index 25c6631..936c844 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Statuses.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Statuses.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Tags.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Tags.swift index 3c9f74a..e674cb1 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Tags.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Tags.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Timelines.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Timelines.swift index d242575..b7cbfad 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Timelines.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Timelines.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/PixelfedKit/Sources/PixelfedKit/Targets/Trends.swift b/PixelfedKit/Sources/PixelfedKit/Targets/Trends.swift index bb198ee..ad9e871 100644 --- a/PixelfedKit/Sources/PixelfedKit/Targets/Trends.swift +++ b/PixelfedKit/Sources/PixelfedKit/Targets/Trends.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/ServicesKit/.gitignore b/ServicesKit/.gitignore new file mode 100644 index 0000000..3b29812 --- /dev/null +++ b/ServicesKit/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/ServicesKit/Package.swift b/ServicesKit/Package.swift new file mode 100644 index 0000000..035dd13 --- /dev/null +++ b/ServicesKit/Package.swift @@ -0,0 +1,41 @@ +// swift-tools-version: 5.8 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "ServicesKit", + platforms: [ + .iOS(.v16), + .macOS(.v12), + .watchOS(.v8) + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "ServicesKit", + targets: ["ServicesKit"]) + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + .package(url: "https://github.com/omaralbeik/Drops", .upToNextMajor(from: "1.6.1")), + .package(url: "https://github.com/kean/Nuke", .upToNextMajor(from: "12.0.0")), + .package(name: "PixelfedKit", path: "../PixelfedKit"), + .package(name: "EnvironmentKit", path: "../EnvironmentKit") + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "ServicesKit", + dependencies: [ + .product(name: "Drops", package: "Drops"), + .product(name: "Nuke", package: "Nuke"), + .product(name: "NukeUI", package: "Nuke"), + .product(name: "EnvironmentKit", package: "EnvironmentKit") + ]), + .testTarget( + name: "ServicesKitTests", + dependencies: ["ServicesKit"]) + ] +) diff --git a/Vernissage/Cache/MemoryCache.swift b/ServicesKit/Sources/ServicesKit/Cache/MemoryCache.swift similarity index 85% rename from Vernissage/Cache/MemoryCache.swift rename to ServicesKit/Sources/ServicesKit/Cache/MemoryCache.swift index 3d97b3d..1686328 100644 --- a/Vernissage/Cache/MemoryCache.swift +++ b/ServicesKit/Sources/ServicesKit/Cache/MemoryCache.swift @@ -7,24 +7,23 @@ import Foundation /// Memory cache based on article: https://www.swiftbysundell.com/articles/caching-in-swift/ -final class MemoryCache { +public final class MemoryCache { private let wrapped = NSCache() private let dateProvider: () -> Date private let entryLifetime: TimeInterval - init(dateProvider: @escaping () -> Date = Date.init, - entryLifetime: TimeInterval = 12 * 60 * 60) { + public init(dateProvider: @escaping () -> Date = Date.init, entryLifetime: TimeInterval = 12 * 60 * 60) { self.dateProvider = dateProvider self.entryLifetime = entryLifetime } - func insert(_ value: Value, forKey key: Key) { + public func insert(_ value: Value, forKey key: Key) { let date = dateProvider().addingTimeInterval(entryLifetime) let entry = Entry(value: value, expirationDate: date) wrapped.setObject(entry, forKey: WrappedKey(key)) } - func value(forKey key: Key) -> Value? { + public func value(forKey key: Key) -> Value? { guard let entry = wrapped.object(forKey: WrappedKey(key)) else { return nil } @@ -38,7 +37,7 @@ final class MemoryCache { return entry.value } - func removeValue(forKey key: Key) { + public func removeValue(forKey key: Key) { wrapped.removeObject(forKey: WrappedKey(key)) } } @@ -73,7 +72,7 @@ private extension MemoryCache { } } -extension MemoryCache { +public extension MemoryCache { subscript(key: Key) -> Value? { get { return value(forKey: key) } set { diff --git a/Vernissage/Services/CacheImageService.swift b/ServicesKit/Sources/ServicesKit/CacheImageService.swift similarity index 92% rename from Vernissage/Services/CacheImageService.swift rename to ServicesKit/Sources/ServicesKit/CacheImageService.swift index 1584ab3..10be8d3 100644 --- a/Vernissage/Services/CacheImageService.swift +++ b/ServicesKit/Sources/ServicesKit/CacheImageService.swift @@ -13,7 +13,7 @@ public class CacheImageService { private var memoryCacheData = MemoryCache(entryLifetime: 600) - func download(url: URL?) async { + public func download(url: URL?) async { guard let url else { return } @@ -32,7 +32,7 @@ public class CacheImageService { } } - func get(for url: URL) -> Image? { + public func get(for url: URL) -> Image? { return self.memoryCacheData[url] } diff --git a/Vernissage/Services/ErrorsService.swift b/ServicesKit/Sources/ServicesKit/ErrorsService.swift similarity index 94% rename from Vernissage/Services/ErrorsService.swift rename to ServicesKit/Sources/ServicesKit/ErrorsService.swift index c00d415..8892b52 100644 --- a/Vernissage/Services/ErrorsService.swift +++ b/ServicesKit/Sources/ServicesKit/ErrorsService.swift @@ -14,7 +14,7 @@ public class ErrorService { public func handle(_ error: Error, message: String, showToastr: Bool = false) { if showToastr { switch error { - case is NetworkError, is URLError: + case is LocalizedError: ToastrService.shared.showError(title: message, subtitle: error.localizedDescription) default: ToastrService.shared.showError(subtitle: message) diff --git a/Vernissage/Haptics/HapticService.swift b/ServicesKit/Sources/ServicesKit/HapticService.swift similarity index 98% rename from Vernissage/Haptics/HapticService.swift rename to ServicesKit/Sources/ServicesKit/HapticService.swift index f511701..808e3f8 100644 --- a/Vernissage/Haptics/HapticService.swift +++ b/ServicesKit/Sources/ServicesKit/HapticService.swift @@ -6,6 +6,7 @@ import CoreHaptics import UIKit +import EnvironmentKit public class HapticService { public static let shared: HapticService = .init() diff --git a/ServicesKit/Sources/ServicesKit/ImageCompressService.swift b/ServicesKit/Sources/ServicesKit/ImageCompressService.swift new file mode 100644 index 0000000..0aaadfe --- /dev/null +++ b/ServicesKit/Sources/ServicesKit/ImageCompressService.swift @@ -0,0 +1,63 @@ +// +// https://mczachurski.dev +// Copyright © 2023 Marcin Czachurski and the repository contributors. +// Licensed under the Apache License 2.0. +// + +import Foundation +import AVFoundation +import UIKit + +public class ImageCompressService { + public static let shared = ImageCompressService() + private init() { } + + public func compressImageFrom(url: URL) async -> Data? { + return await withCheckedContinuation { continuation in + let sourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary + + guard let source = CGImageSourceCreateWithURL(url as CFURL, sourceOptions) else { + continuation.resume(returning: nil) + return + } + + let maxPixelSize: Int + if Bundle.main.bundlePath.hasSuffix(".appex") { + maxPixelSize = 2048 + } else { + maxPixelSize = 4096 + } + + let downsampleOptions = [ + kCGImageSourceCreateThumbnailFromImageAlways: true, + kCGImageSourceCreateThumbnailWithTransform: true, + kCGImageSourceThumbnailMaxPixelSize: maxPixelSize + ] as [CFString: Any] as CFDictionary + + guard let cgImage = CGImageSourceCreateThumbnailAtIndex(source, 0, downsampleOptions) else { + continuation.resume(returning: nil) + return + } + + let data = NSMutableData() + guard let imageDestination = CGImageDestinationCreateWithData(data, UTType.jpeg.identifier as CFString, 1, nil) else { + continuation.resume(returning: nil) + return + } + + let isPNG: Bool = { + guard let utType = cgImage.utType else { return false } + return (utType as String) == UTType.png.identifier + }() + + let destinationProperties = [ + kCGImageDestinationLossyCompressionQuality: isPNG ? 1.0 : 0.85 + ] as CFDictionary + + CGImageDestinationAddImage(imageDestination, cgImage, destinationProperties) + CGImageDestinationFinalize(imageDestination) + + continuation.resume(returning: data as Data) + } + } +} diff --git a/Vernissage/Services/ImageSizeService.swift b/ServicesKit/Sources/ServicesKit/ImageSizeService.swift similarity index 77% rename from Vernissage/Services/ImageSizeService.swift rename to ServicesKit/Sources/ServicesKit/ImageSizeService.swift index a456084..3e5944d 100644 --- a/Vernissage/Services/ImageSizeService.swift +++ b/ServicesKit/Sources/ServicesKit/ImageSizeService.swift @@ -13,19 +13,19 @@ public class ImageSizeService { private var memoryCacheData = MemoryCache(entryLifetime: 3600) - func get(for url: URL) -> CGSize? { + public func get(for url: URL) -> CGSize? { return self.memoryCacheData[url] } - func calculate(for url: URL, width: Int32, height: Int32) -> CGSize { + public func calculate(for url: URL, width: Int32, height: Int32) -> CGSize { return calculate(for: url, width: Double(width), height: Double(height)) } - func calculate(for url: URL, width: Int, height: Int) -> CGSize { + public func calculate(for url: URL, width: Int, height: Int) -> CGSize { return calculate(for: url, width: Double(width), height: Double(height)) } - func calculate(for url: URL, width: Double, height: Double) -> CGSize { + public func calculate(for url: URL, width: Double, height: Double) -> CGSize { let divider = Double(width) / UIScreen.main.bounds.size.width let calculatedHeight = Double(height) / divider diff --git a/Vernissage/Services/RemoteFileService.swift b/ServicesKit/Sources/ServicesKit/RemoteFileService.swift similarity index 92% rename from Vernissage/Services/RemoteFileService.swift rename to ServicesKit/Sources/ServicesKit/RemoteFileService.swift index 704935a..e86c5d4 100644 --- a/Vernissage/Services/RemoteFileService.swift +++ b/ServicesKit/Sources/ServicesKit/RemoteFileService.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/Vernissage/Services/ToastrService.swift b/ServicesKit/Sources/ServicesKit/ToastrService.swift similarity index 100% rename from Vernissage/Services/ToastrService.swift rename to ServicesKit/Sources/ServicesKit/ToastrService.swift diff --git a/ServicesKit/Tests/ServicesKitTests/ServicesKitTests.swift b/ServicesKit/Tests/ServicesKitTests/ServicesKitTests.swift new file mode 100644 index 0000000..2903743 --- /dev/null +++ b/ServicesKit/Tests/ServicesKitTests/ServicesKitTests.swift @@ -0,0 +1,11 @@ +import XCTest +@testable import ServicesKit + +final class ServicesKitTests: XCTestCase { + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + // XCTAssertEqual(ServicesKit().text, "Hello, World!") + } +} diff --git a/Vernissage/Assets.xcassets/AccentColors/AccentColor.colorset/Contents.json b/SharedAssets.xcassets/AccentColors/AccentColor.colorset/Contents.json similarity index 100% rename from Vernissage/Assets.xcassets/AccentColors/AccentColor.colorset/Contents.json rename to SharedAssets.xcassets/AccentColors/AccentColor.colorset/Contents.json diff --git a/Vernissage/Assets.xcassets/AccentColors/AccentColor1.colorset/Contents.json b/SharedAssets.xcassets/AccentColors/AccentColor1.colorset/Contents.json similarity index 76% rename from Vernissage/Assets.xcassets/AccentColors/AccentColor1.colorset/Contents.json rename to SharedAssets.xcassets/AccentColors/AccentColor1.colorset/Contents.json index 1470134..157acc2 100644 --- a/Vernissage/Assets.xcassets/AccentColors/AccentColor1.colorset/Contents.json +++ b/SharedAssets.xcassets/AccentColors/AccentColor1.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "85", - "green" : "123", - "red" : "238" + "blue" : "0.333", + "green" : "0.482", + "red" : "0.933" } }, "idiom" : "universal" @@ -23,9 +23,9 @@ "color-space" : "display-p3", "components" : { "alpha" : "1.000", - "blue" : "101", - "green" : "137", - "red" : "238" + "blue" : "0.396", + "green" : "0.537", + "red" : "0.933" } }, "idiom" : "universal" diff --git a/Vernissage/Assets.xcassets/AccentColors/AccentColor10.colorset/Contents.json b/SharedAssets.xcassets/AccentColors/AccentColor10.colorset/Contents.json similarity index 88% rename from Vernissage/Assets.xcassets/AccentColors/AccentColor10.colorset/Contents.json rename to SharedAssets.xcassets/AccentColors/AccentColor10.colorset/Contents.json index 6a9ad80..6463fe9 100644 --- a/Vernissage/Assets.xcassets/AccentColors/AccentColor10.colorset/Contents.json +++ b/SharedAssets.xcassets/AccentColors/AccentColor10.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "61", - "green" : "78", - "red" : "235" + "blue" : "0.239", + "green" : "0.306", + "red" : "0.922" } }, "idiom" : "universal" diff --git a/Vernissage/Assets.xcassets/AccentColors/AccentColor2.colorset/Contents.json b/SharedAssets.xcassets/AccentColors/AccentColor2.colorset/Contents.json similarity index 100% rename from Vernissage/Assets.xcassets/AccentColors/AccentColor2.colorset/Contents.json rename to SharedAssets.xcassets/AccentColors/AccentColor2.colorset/Contents.json diff --git a/Vernissage/Assets.xcassets/AccentColors/AccentColor3.colorset/Contents.json b/SharedAssets.xcassets/AccentColors/AccentColor3.colorset/Contents.json similarity index 88% rename from Vernissage/Assets.xcassets/AccentColors/AccentColor3.colorset/Contents.json rename to SharedAssets.xcassets/AccentColors/AccentColor3.colorset/Contents.json index eb76f13..b46a501 100644 --- a/Vernissage/Assets.xcassets/AccentColors/AccentColor3.colorset/Contents.json +++ b/SharedAssets.xcassets/AccentColors/AccentColor3.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "207", - "green" : "90", - "red" : "86" + "blue" : "0.812", + "green" : "0.353", + "red" : "0.337" } }, "idiom" : "universal" diff --git a/Vernissage/Assets.xcassets/AccentColors/AccentColor4.colorset/Contents.json b/SharedAssets.xcassets/AccentColors/AccentColor4.colorset/Contents.json similarity index 88% rename from Vernissage/Assets.xcassets/AccentColors/AccentColor4.colorset/Contents.json rename to SharedAssets.xcassets/AccentColors/AccentColor4.colorset/Contents.json index 478170a..7aad98b 100644 --- a/Vernissage/Assets.xcassets/AccentColors/AccentColor4.colorset/Contents.json +++ b/SharedAssets.xcassets/AccentColors/AccentColor4.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "215", - "green" : "90", - "red" : "163" + "blue" : "0.843", + "green" : "0.353", + "red" : "0.639" } }, "idiom" : "universal" diff --git a/Vernissage/Assets.xcassets/AccentColors/AccentColor5.colorset/Contents.json b/SharedAssets.xcassets/AccentColors/AccentColor5.colorset/Contents.json similarity index 91% rename from Vernissage/Assets.xcassets/AccentColors/AccentColor5.colorset/Contents.json rename to SharedAssets.xcassets/AccentColors/AccentColor5.colorset/Contents.json index 2f92c71..954552c 100644 --- a/Vernissage/Assets.xcassets/AccentColors/AccentColor5.colorset/Contents.json +++ b/SharedAssets.xcassets/AccentColors/AccentColor5.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "197", - "green" : "174", - "red" : "88" + "blue" : "0.773", + "green" : "0.682", + "red" : "0.345" } }, "idiom" : "universal" diff --git a/Vernissage/Assets.xcassets/AccentColors/AccentColor6.colorset/Contents.json b/SharedAssets.xcassets/AccentColors/AccentColor6.colorset/Contents.json similarity index 88% rename from Vernissage/Assets.xcassets/AccentColors/AccentColor6.colorset/Contents.json rename to SharedAssets.xcassets/AccentColors/AccentColor6.colorset/Contents.json index 93ea185..2d57900 100644 --- a/Vernissage/Assets.xcassets/AccentColors/AccentColor6.colorset/Contents.json +++ b/SharedAssets.xcassets/AccentColors/AccentColor6.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "102", - "green" : "195", - "red" : "101" + "blue" : "0.400", + "green" : "0.765", + "red" : "0.396" } }, "idiom" : "universal" diff --git a/Vernissage/Assets.xcassets/AccentColors/AccentColor7.colorset/Contents.json b/SharedAssets.xcassets/AccentColors/AccentColor7.colorset/Contents.json similarity index 88% rename from Vernissage/Assets.xcassets/AccentColors/AccentColor7.colorset/Contents.json rename to SharedAssets.xcassets/AccentColors/AccentColor7.colorset/Contents.json index fad688e..a87ca32 100644 --- a/Vernissage/Assets.xcassets/AccentColors/AccentColor7.colorset/Contents.json +++ b/SharedAssets.xcassets/AccentColors/AccentColor7.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "68", - "green" : "204", - "red" : "246" + "blue" : "0.267", + "green" : "0.800", + "red" : "0.965" } }, "idiom" : "universal" diff --git a/Vernissage/Assets.xcassets/AccentColors/AccentColor8.colorset/Contents.json b/SharedAssets.xcassets/AccentColors/AccentColor8.colorset/Contents.json similarity index 88% rename from Vernissage/Assets.xcassets/AccentColors/AccentColor8.colorset/Contents.json rename to SharedAssets.xcassets/AccentColors/AccentColor8.colorset/Contents.json index 5e50bde..072d606 100644 --- a/Vernissage/Assets.xcassets/AccentColors/AccentColor8.colorset/Contents.json +++ b/SharedAssets.xcassets/AccentColors/AccentColor8.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "54", - "green" : "152", - "red" : "241" + "blue" : "0.212", + "green" : "0.596", + "red" : "0.945" } }, "idiom" : "universal" diff --git a/Vernissage/Assets.xcassets/AccentColors/AccentColor9.colorset/Contents.json b/SharedAssets.xcassets/AccentColors/AccentColor9.colorset/Contents.json similarity index 88% rename from Vernissage/Assets.xcassets/AccentColors/AccentColor9.colorset/Contents.json rename to SharedAssets.xcassets/AccentColors/AccentColor9.colorset/Contents.json index d86e8b2..77bc6a5 100644 --- a/Vernissage/Assets.xcassets/AccentColors/AccentColor9.colorset/Contents.json +++ b/SharedAssets.xcassets/AccentColors/AccentColor9.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "90", - "green" : "68", - "red" : "235" + "blue" : "0.353", + "green" : "0.267", + "red" : "0.922" } }, "idiom" : "universal" diff --git a/Vernissage/Assets.xcassets/AccentColors/Contents.json b/SharedAssets.xcassets/AccentColors/Contents.json similarity index 100% rename from Vernissage/Assets.xcassets/AccentColors/Contents.json rename to SharedAssets.xcassets/AccentColors/Contents.json diff --git a/Vernissage/Assets.xcassets/Avatar.imageset/Contents.json b/SharedAssets.xcassets/Avatar.imageset/Contents.json similarity index 100% rename from Vernissage/Assets.xcassets/Avatar.imageset/Contents.json rename to SharedAssets.xcassets/Avatar.imageset/Contents.json diff --git a/Vernissage/Assets.xcassets/Avatar.imageset/avatar.png b/SharedAssets.xcassets/Avatar.imageset/avatar.png similarity index 100% rename from Vernissage/Assets.xcassets/Avatar.imageset/avatar.png rename to SharedAssets.xcassets/Avatar.imageset/avatar.png diff --git a/Vernissage/Assets.xcassets/Avatar.imageset/avatar@2x.png b/SharedAssets.xcassets/Avatar.imageset/avatar@2x.png similarity index 100% rename from Vernissage/Assets.xcassets/Avatar.imageset/avatar@2x.png rename to SharedAssets.xcassets/Avatar.imageset/avatar@2x.png diff --git a/Vernissage/Assets.xcassets/Avatar.imageset/avatar@3x.png b/SharedAssets.xcassets/Avatar.imageset/avatar@3x.png similarity index 100% rename from Vernissage/Assets.xcassets/Avatar.imageset/avatar@3x.png rename to SharedAssets.xcassets/Avatar.imageset/avatar@3x.png diff --git a/Vernissage/Assets.xcassets/Blurhash.imageset/Blurhash.png b/SharedAssets.xcassets/Blurhash.imageset/Blurhash.png similarity index 100% rename from Vernissage/Assets.xcassets/Blurhash.imageset/Blurhash.png rename to SharedAssets.xcassets/Blurhash.imageset/Blurhash.png diff --git a/Vernissage/Assets.xcassets/Blurhash.imageset/Blurhash@2x.png b/SharedAssets.xcassets/Blurhash.imageset/Blurhash@2x.png similarity index 100% rename from Vernissage/Assets.xcassets/Blurhash.imageset/Blurhash@2x.png rename to SharedAssets.xcassets/Blurhash.imageset/Blurhash@2x.png diff --git a/Vernissage/Assets.xcassets/Blurhash.imageset/Blurhash@3x.png b/SharedAssets.xcassets/Blurhash.imageset/Blurhash@3x.png similarity index 100% rename from Vernissage/Assets.xcassets/Blurhash.imageset/Blurhash@3x.png rename to SharedAssets.xcassets/Blurhash.imageset/Blurhash@3x.png diff --git a/Vernissage/Assets.xcassets/Blurhash.imageset/Contents.json b/SharedAssets.xcassets/Blurhash.imageset/Contents.json similarity index 100% rename from Vernissage/Assets.xcassets/Blurhash.imageset/Contents.json rename to SharedAssets.xcassets/Blurhash.imageset/Contents.json diff --git a/SharedAssets.xcassets/Contents.json b/SharedAssets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/SharedAssets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SharedAssets.xcassets/DangerColor.colorset/Contents.json b/SharedAssets.xcassets/DangerColor.colorset/Contents.json new file mode 100644 index 0000000..11a9ac4 --- /dev/null +++ b/SharedAssets.xcassets/DangerColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.267", + "green" : "0.341", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.267", + "green" : "0.341", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Vernissage/Assets.xcassets/ImagePlaceholder.imageset/Contents.json b/SharedAssets.xcassets/ImagePlaceholder.imageset/Contents.json similarity index 100% rename from Vernissage/Assets.xcassets/ImagePlaceholder.imageset/Contents.json rename to SharedAssets.xcassets/ImagePlaceholder.imageset/Contents.json diff --git a/Vernissage/Assets.xcassets/ImagePlaceholder.imageset/ImagePlaceholder.png b/SharedAssets.xcassets/ImagePlaceholder.imageset/ImagePlaceholder.png similarity index 100% rename from Vernissage/Assets.xcassets/ImagePlaceholder.imageset/ImagePlaceholder.png rename to SharedAssets.xcassets/ImagePlaceholder.imageset/ImagePlaceholder.png diff --git a/Vernissage/Assets.xcassets/ImagePlaceholder.imageset/ImagePlaceholder@2x.png b/SharedAssets.xcassets/ImagePlaceholder.imageset/ImagePlaceholder@2x.png similarity index 100% rename from Vernissage/Assets.xcassets/ImagePlaceholder.imageset/ImagePlaceholder@2x.png rename to SharedAssets.xcassets/ImagePlaceholder.imageset/ImagePlaceholder@2x.png diff --git a/Vernissage/Assets.xcassets/ImagePlaceholder.imageset/ImagePlaceholder@3x.png b/SharedAssets.xcassets/ImagePlaceholder.imageset/ImagePlaceholder@3x.png similarity index 100% rename from Vernissage/Assets.xcassets/ImagePlaceholder.imageset/ImagePlaceholder@3x.png rename to SharedAssets.xcassets/ImagePlaceholder.imageset/ImagePlaceholder@3x.png diff --git a/Vernissage/Assets.xcassets/ImagePlaceholder.imageset/ImagePlaceholderLight.png b/SharedAssets.xcassets/ImagePlaceholder.imageset/ImagePlaceholderLight.png similarity index 100% rename from Vernissage/Assets.xcassets/ImagePlaceholder.imageset/ImagePlaceholderLight.png rename to SharedAssets.xcassets/ImagePlaceholder.imageset/ImagePlaceholderLight.png diff --git a/Vernissage/Assets.xcassets/ImagePlaceholder.imageset/ImagePlaceholderLight@2x.png b/SharedAssets.xcassets/ImagePlaceholder.imageset/ImagePlaceholderLight@2x.png similarity index 100% rename from Vernissage/Assets.xcassets/ImagePlaceholder.imageset/ImagePlaceholderLight@2x.png rename to SharedAssets.xcassets/ImagePlaceholder.imageset/ImagePlaceholderLight@2x.png diff --git a/Vernissage/Assets.xcassets/ImagePlaceholder.imageset/ImagePlaceholderLight@3x.png b/SharedAssets.xcassets/ImagePlaceholder.imageset/ImagePlaceholderLight@3x.png similarity index 100% rename from Vernissage/Assets.xcassets/ImagePlaceholder.imageset/ImagePlaceholderLight@3x.png rename to SharedAssets.xcassets/ImagePlaceholder.imageset/ImagePlaceholderLight@3x.png diff --git a/Vernissage/Assets.xcassets/SelectedRowColor.colorset/Contents.json b/SharedAssets.xcassets/KeyboardToolbar.colorset/Contents.json similarity index 76% rename from Vernissage/Assets.xcassets/SelectedRowColor.colorset/Contents.json rename to SharedAssets.xcassets/KeyboardToolbar.colorset/Contents.json index 86c24e0..207b76d 100644 --- a/Vernissage/Assets.xcassets/SelectedRowColor.colorset/Contents.json +++ b/SharedAssets.xcassets/KeyboardToolbar.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "248", - "green" : "248", - "red" : "248" + "blue" : "0.969", + "green" : "0.969", + "red" : "0.969" } }, "idiom" : "universal" @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "25", - "green" : "25", - "red" : "25" + "blue" : "0.165", + "green" : "0.157", + "red" : "0.157" } }, "idiom" : "universal" diff --git a/Vernissage/Assets.xcassets/KeyboardToolbar.colorset/Contents.json b/SharedAssets.xcassets/LightGrayColor.colorset/Contents.json similarity index 76% rename from Vernissage/Assets.xcassets/KeyboardToolbar.colorset/Contents.json rename to SharedAssets.xcassets/LightGrayColor.colorset/Contents.json index 026cda1..ccb2fbc 100644 --- a/Vernissage/Assets.xcassets/KeyboardToolbar.colorset/Contents.json +++ b/SharedAssets.xcassets/LightGrayColor.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "247", - "green" : "247", - "red" : "247" + "blue" : "0.627", + "green" : "0.627", + "red" : "0.627" } }, "idiom" : "universal" @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "42", - "green" : "40", - "red" : "40" + "blue" : "0.627", + "green" : "0.627", + "red" : "0.627" } }, "idiom" : "universal" diff --git a/SharedAssets.xcassets/MainTextColor.colorset/Contents.json b/SharedAssets.xcassets/MainTextColor.colorset/Contents.json new file mode 100644 index 0000000..364fa31 --- /dev/null +++ b/SharedAssets.xcassets/MainTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.039", + "green" : "0.039", + "red" : "0.039" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.961", + "green" : "0.961", + "red" : "0.961" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SharedAssets.xcassets/SelectedRowColor.colorset/Contents.json b/SharedAssets.xcassets/SelectedRowColor.colorset/Contents.json new file mode 100644 index 0000000..4aacf9a --- /dev/null +++ b/SharedAssets.xcassets/SelectedRowColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.973", + "green" : "0.973", + "red" : "0.973" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.098", + "green" : "0.098", + "red" : "0.098" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Vernissage/Assets.xcassets/ViewTextColor.colorset/Contents.json b/SharedAssets.xcassets/ViewBackgroundColor.colorset/Contents.json similarity index 88% rename from Vernissage/Assets.xcassets/ViewTextColor.colorset/Contents.json rename to SharedAssets.xcassets/ViewBackgroundColor.colorset/Contents.json index 13f4d66..c82979e 100644 --- a/Vernissage/Assets.xcassets/ViewTextColor.colorset/Contents.json +++ b/SharedAssets.xcassets/ViewBackgroundColor.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "247", - "green" : "247", - "red" : "247" + "blue" : "0.157", + "green" : "0.157", + "red" : "0.157" } }, "idiom" : "universal" @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.157", - "green" : "0.157", - "red" : "0.157" + "blue" : "0.969", + "green" : "0.969", + "red" : "0.969" } }, "idiom" : "universal" diff --git a/SharedAssets.xcassets/ViewTextColor.colorset/Contents.json b/SharedAssets.xcassets/ViewTextColor.colorset/Contents.json new file mode 100644 index 0000000..13e7c90 --- /dev/null +++ b/SharedAssets.xcassets/ViewTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.969", + "green" : "0.969", + "red" : "0.969" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.157", + "green" : "0.157", + "red" : "0.157" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Vernissage.xcodeproj/project.pbxproj b/Vernissage.xcodeproj/project.pbxproj index 9fdd25f..fb7e15a 100644 --- a/Vernissage.xcodeproj/project.pbxproj +++ b/Vernissage.xcodeproj/project.pbxproj @@ -14,7 +14,6 @@ F80048082961E6DE00E6868A /* StatusDataHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80048072961E6DE00E6868A /* StatusDataHandler.swift */; }; F800480A2961EA1900E6868A /* AttachmentDataHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80048092961EA1900E6868A /* AttachmentDataHandler.swift */; }; F802884F297AEED5000BDD51 /* DatabaseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F802884E297AEED5000BDD51 /* DatabaseError.swift */; }; - F805DCEF29DBED96006A1FD9 /* Client+Report.swift in Sources */ = {isa = PBXBuildFile; fileRef = F805DCEE29DBED96006A1FD9 /* Client+Report.swift */; }; F805DCF129DBEF83006A1FD9 /* ReportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F805DCF029DBEF83006A1FD9 /* ReportView.swift */; }; F808641429756666009F035C /* NotificationRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F808641329756666009F035C /* NotificationRowView.swift */; }; F8121CA8298A86D600B466C7 /* InstanceRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8121CA7298A86D600B466C7 /* InstanceRowView.swift */; }; @@ -24,34 +23,22 @@ F8210DD92966BB7E001D9973 /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = F8210DD82966BB7E001D9973 /* NukeUI */; }; F8210DDD2966CF17001D9973 /* StatusData+Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8210DDC2966CF17001D9973 /* StatusData+Status.swift */; }; F8210DDF2966CFC7001D9973 /* AttachmentData+Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8210DDE2966CFC7001D9973 /* AttachmentData+Attachment.swift */; }; - F8210DE52966E160001D9973 /* Color+SystemColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8210DE42966E160001D9973 /* Color+SystemColors.swift */; }; - F8210DE72966E1D1001D9973 /* Color+Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8210DE62966E1D1001D9973 /* Color+Assets.swift */; }; F8210DEA2966E4F9001D9973 /* AnimatePlaceholderModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8210DE92966E4F9001D9973 /* AnimatePlaceholderModifier.swift */; }; - F829193C2983012400367CE2 /* ImageSizeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F829193B2983012400367CE2 /* ImageSizeService.swift */; }; - F8341F90295C636C009C8EE6 /* Data+Exif.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8341F8F295C636C009C8EE6 /* Data+Exif.swift */; }; F835082329BEF9C400DE3247 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F835082629BEF9C400DE3247 /* Localizable.strings */; }; F835082429BEF9C400DE3247 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F835082629BEF9C400DE3247 /* Localizable.strings */; }; - F83901A6295D8EC000456AE2 /* LabelIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = F83901A5295D8EC000456AE2 /* LabelIcon.swift */; }; F83CBEFB298298A1002972C8 /* ImageCarouselPicture.swift in Sources */ = {isa = PBXBuildFile; fileRef = F83CBEFA298298A1002972C8 /* ImageCarouselPicture.swift */; }; - F83E00ED29A2237C005D25A3 /* PixelfedKit in Frameworks */ = {isa = PBXBuildFile; productRef = F83E00EC29A2237C005D25A3 /* PixelfedKit */; }; - F857F9FD297D8ED3002C109C /* ActionMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F857F9FC297D8ED3002C109C /* ActionMenu.swift */; }; + F858906B29E1CC7A00D4BDED /* UIApplication+Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = F858906A29E1CC7A00D4BDED /* UIApplication+Window.swift */; }; F85D4971296402DC00751DF7 /* AuthorizationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85D4970296402DC00751DF7 /* AuthorizationService.swift */; }; - F85D4973296406E700751DF7 /* BottomRight.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85D4972296406E700751DF7 /* BottomRight.swift */; }; F85D4975296407F100751DF7 /* HomeTimelineService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85D4974296407F100751DF7 /* HomeTimelineService.swift */; }; F85D497729640A5200751DF7 /* ImageRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85D497629640A5200751DF7 /* ImageRow.swift */; }; F85D497929640B9D00751DF7 /* ImagesCarousel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85D497829640B9D00751DF7 /* ImagesCarousel.swift */; }; - F85D497B29640C8200751DF7 /* UsernameRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85D497A29640C8200751DF7 /* UsernameRow.swift */; }; F85D497D29640D5900751DF7 /* InteractionRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85D497C29640D5900751DF7 /* InteractionRow.swift */; }; F85D497F296416C800751DF7 /* CommentsSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85D497E296416C800751DF7 /* CommentsSectionView.swift */; }; F85D498329642FAC00751DF7 /* AttachmentData+Comperable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85D498229642FAC00751DF7 /* AttachmentData+Comperable.swift */; }; F85D49852964301800751DF7 /* StatusData+Attachments.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85D49842964301800751DF7 /* StatusData+Attachments.swift */; }; - F85D49872964334100751DF7 /* String+Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85D49862964334100751DF7 /* String+Date.swift */; }; F85D4DFE29B78C8400345267 /* HashtagModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85D4DFD29B78C8400345267 /* HashtagModel.swift */; }; F85DBF8F296732E20069BF89 /* AccountsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85DBF8E296732E20069BF89 /* AccountsView.swift */; }; - F85E1320297409CD006A051D /* ErrorsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85E131F297409CD006A051D /* ErrorsService.swift */; }; - F85E132529741F05006A051D /* ActivityIndicatorView in Frameworks */ = {isa = PBXBuildFile; productRef = F85E132429741F05006A051D /* ActivityIndicatorView */; }; F86167C6297FE6CC004D1F67 /* AvatarShapesSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86167C5297FE6CC004D1F67 /* AvatarShapesSectionView.swift */; }; - F86167C8297FE781004D1F67 /* AvatarShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86167C7297FE781004D1F67 /* AvatarShape.swift */; }; F864F75F29BB91B400B13921 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F864F75E29BB91B400B13921 /* WidgetKit.framework */; }; F864F76129BB91B400B13921 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F864F76029BB91B400B13921 /* SwiftUI.framework */; }; F864F76429BB91B400B13921 /* VernissageWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F76329BB91B400B13921 /* VernissageWidgetBundle.swift */; }; @@ -76,13 +63,6 @@ F864F78A29BB9A8000B13921 /* ApplicationSettingsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F866F6A429604194002E8F88 /* ApplicationSettingsHandler.swift */; }; F864F78B29BB9A8300B13921 /* StatusDataHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80048072961E6DE00E6868A /* StatusDataHandler.swift */; }; F864F78C29BB9A8500B13921 /* AttachmentDataHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80048092961EA1900E6868A /* AttachmentDataHandler.swift */; }; - F864F78E29BB9B2F00B13921 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89D6C3E29716E41001DA3D4 /* Theme.swift */; }; - F864F78F29BB9B3100B13921 /* AvatarShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86167C7297FE781004D1F67 /* AvatarShape.swift */; }; - F864F79029BB9B3300B13921 /* TintColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8CC95CD2970761D00C9C2AC /* TintColor.swift */; }; - F864F79D29BB9D3400B13921 /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87AEB932986C51B00434FB6 /* AppConstants.swift */; }; - F864F79F29BB9E6A00B13921 /* TintColor+Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F79E29BB9E6A00B13921 /* TintColor+Color.swift */; }; - F864F7A129BB9E8F00B13921 /* AvatarShape+Shape.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F7A029BB9E8F00B13921 /* AvatarShape+Shape.swift */; }; - F864F7A329BB9EC700B13921 /* Theme+ColorScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F7A229BB9EC700B13921 /* Theme+ColorScheme.swift */; }; F864F7A529BBA01D00B13921 /* CoreDataError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F7A429BBA01D00B13921 /* CoreDataError.swift */; }; F864F7A629BBA01D00B13921 /* CoreDataError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F7A429BBA01D00B13921 /* CoreDataError.swift */; }; F866F6A0296040A8002E8F88 /* ApplicationSettings+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F866F69E296040A8002E8F88 /* ApplicationSettings+CoreDataClass.swift */; }; @@ -100,32 +80,52 @@ F86A4307299AA5E900DF7645 /* ThanksView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86A4306299AA5E900DF7645 /* ThanksView.swift */; }; F86B7214296BFDCE00EE59EC /* UserProfileHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86B7213296BFDCE00EE59EC /* UserProfileHeaderView.swift */; }; F86B7216296BFFDA00EE59EC /* UserProfileStatusesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86B7215296BFFDA00EE59EC /* UserProfileStatusesView.swift */; }; - F86B7218296C27C100EE59EC /* ActionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86B7217296C27C100EE59EC /* ActionButton.swift */; }; - F86B721E296C458700EE59EC /* BlurredImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86B721D296C458700EE59EC /* BlurredImage.swift */; }; F86B7221296C49A300EE59EC /* EmptyButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86B7220296C49A300EE59EC /* EmptyButtonStyle.swift */; }; - F86B7223296C4BF500EE59EC /* ContentWarning.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86B7222296C4BF500EE59EC /* ContentWarning.swift */; }; - F86FB555298BF83F000131F0 /* FavouriteTouch.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86FB554298BF83F000131F0 /* FavouriteTouch.swift */; }; - F873F14C29BDB67300DE72D1 /* UIImage+Rounded.swift in Sources */ = {isa = PBXBuildFile; fileRef = F873F14B29BDB67300DE72D1 /* UIImage+Rounded.swift */; }; F8742FC429990AFB00E9642B /* ClientError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8742FC329990AFB00E9642B /* ClientError.swift */; }; F8764187298ABB520057D362 /* ViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8764186298ABB520057D362 /* ViewState.swift */; }; - F8764189298ABEC80057D362 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8764188298ABEC80057D362 /* ErrorView.swift */; }; - F876418B298AC1B80057D362 /* NoDataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F876418A298AC1B80057D362 /* NoDataView.swift */; }; F876418D298AE5020057D362 /* PaginableStatusesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F876418C298AE5020057D362 /* PaginableStatusesView.swift */; }; F878842229A4A4E3003CFAD2 /* AppMetadataService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F878842129A4A4E3003CFAD2 /* AppMetadataService.swift */; }; F87AEB922986C44E00434FB6 /* AuthorizationSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87AEB912986C44E00434FB6 /* AuthorizationSession.swift */; }; - F87AEB942986C51B00434FB6 /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87AEB932986C51B00434FB6 /* AppConstants.swift */; }; F87AEB972986D16D00434FB6 /* AuthorisationError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87AEB962986D16D00434FB6 /* AuthorisationError.swift */; }; F883402029B62AE900C3E096 /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F883401F29B62AE900C3E096 /* SearchView.swift */; }; - F8864CE929ACAF820020C534 /* TextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8864CE829ACAF820020C534 /* TextView.swift */; }; - F8864CEB29ACBAA80020C534 /* TextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8864CEA29ACBAA80020C534 /* TextModel.swift */; }; - F8864CEF29ACE90B0020C534 /* UIFont+Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8864CEE29ACE90B0020C534 /* UIFont+Font.swift */; }; - F8864CF129ACFFB80020C534 /* View+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8864CF029ACFFB80020C534 /* View+Keyboard.swift */; }; - F886F257297859E300879356 /* CacheImageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F886F256297859E300879356 /* CacheImageService.swift */; }; F88AB05329B3613900345EDE /* PhotoUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88AB05229B3613900345EDE /* PhotoUrl.swift */; }; F88AB05529B3626300345EDE /* ImageGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88AB05429B3626300345EDE /* ImageGrid.swift */; }; F88AB05829B36B8200345EDE /* AccountsPhotoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88AB05729B36B8200345EDE /* AccountsPhotoView.swift */; }; - F88ABD9229686F1C004EF61E /* MemoryCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88ABD9129686F1C004EF61E /* MemoryCache.swift */; }; F88ABD9429687CA4004EF61E /* ComposeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88ABD9329687CA4004EF61E /* ComposeView.swift */; }; + F88BC50529E02F3900CE6141 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88BC50429E02F3900CE6141 /* ShareViewController.swift */; }; + F88BC50C29E02F3900CE6141 /* VernissageShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = F88BC50229E02F3900CE6141 /* VernissageShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + F88BC51329E02FD800CE6141 /* ComposeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88BC51229E02FD800CE6141 /* ComposeView.swift */; }; + F88BC51629E0307F00CE6141 /* NotificationsName.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88BC51529E0307F00CE6141 /* NotificationsName.swift */; }; + F88BC51B29E0350300CE6141 /* ClientKit in Frameworks */ = {isa = PBXBuildFile; productRef = F88BC51A29E0350300CE6141 /* ClientKit */; }; + F88BC51D29E0377B00CE6141 /* AccountData+AccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88BC51C29E0377B00CE6141 /* AccountData+AccountModel.swift */; }; + F88BC51F29E03ED300CE6141 /* ClientKit in Frameworks */ = {isa = PBXBuildFile; productRef = F88BC51E29E03ED300CE6141 /* ClientKit */; }; + F88BC52729E0431D00CE6141 /* ServicesKit in Frameworks */ = {isa = PBXBuildFile; productRef = F88BC52629E0431D00CE6141 /* ServicesKit */; }; + F88BC52A29E046D700CE6141 /* WidgetsKit in Frameworks */ = {isa = PBXBuildFile; productRef = F88BC52929E046D700CE6141 /* WidgetsKit */; }; + F88BC52D29E04BB600CE6141 /* EnvironmentKit in Frameworks */ = {isa = PBXBuildFile; productRef = F88BC52C29E04BB600CE6141 /* EnvironmentKit */; }; + F88BC52F29E04C5F00CE6141 /* EnvironmentKit in Frameworks */ = {isa = PBXBuildFile; productRef = F88BC52E29E04C5F00CE6141 /* EnvironmentKit */; }; + F88BC53029E0672000CE6141 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F835082629BEF9C400DE3247 /* Localizable.strings */; }; + F88BC53229E0677000CE6141 /* EnvironmentKit in Frameworks */ = {isa = PBXBuildFile; productRef = F88BC53129E0677000CE6141 /* EnvironmentKit */; }; + F88BC53B29E06A5100CE6141 /* ImageContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88BC53A29E06A5100CE6141 /* ImageContextMenu.swift */; }; + F88BC53D29E06EAD00CE6141 /* ServicesKit in Frameworks */ = {isa = PBXBuildFile; productRef = F88BC53C29E06EAD00CE6141 /* ServicesKit */; }; + F88BC53F29E06EB100CE6141 /* WidgetsKit in Frameworks */ = {isa = PBXBuildFile; productRef = F88BC53E29E06EB100CE6141 /* WidgetsKit */; }; + F88BC54129E072A600CE6141 /* CoreDataError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F864F7A429BBA01D00B13921 /* CoreDataError.swift */; }; + F88BC54229E072A900CE6141 /* AttachmentDataHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80048092961EA1900E6868A /* AttachmentDataHandler.swift */; }; + F88BC54329E072AC00CE6141 /* StatusDataHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80048072961E6DE00E6868A /* StatusDataHandler.swift */; }; + F88BC54429E072AF00CE6141 /* ApplicationSettingsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F866F6A429604194002E8F88 /* ApplicationSettingsHandler.swift */; }; + F88BC54529E072B200CE6141 /* AccountDataHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F866F6A229604161002E8F88 /* AccountDataHandler.swift */; }; + F88BC54629E072B500CE6141 /* CoreDataHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88C2474295C37BB0006098B /* CoreDataHandler.swift */; }; + F88BC54729E072B800CE6141 /* AccountData+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88FAD29295F43B8009B20C9 /* AccountData+CoreDataProperties.swift */; }; + F88BC54829E072BC00CE6141 /* AccountData+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88FAD28295F43B8009B20C9 /* AccountData+CoreDataClass.swift */; }; + F88BC54929E072C000CE6141 /* ApplicationSettings+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F866F69F296040A8002E8F88 /* ApplicationSettings+CoreDataProperties.swift */; }; + F88BC54A29E072C400CE6141 /* ApplicationSettings+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F866F69E296040A8002E8F88 /* ApplicationSettings+CoreDataClass.swift */; }; + F88BC54B29E072CA00CE6141 /* StatusData+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80048022961850500E6868A /* StatusData+CoreDataProperties.swift */; }; + F88BC54C29E072CD00CE6141 /* StatusData+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80048012961850500E6868A /* StatusData+CoreDataClass.swift */; }; + F88BC54D29E072D600CE6141 /* AttachmentData+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80048002961850500E6868A /* AttachmentData+CoreDataProperties.swift */; }; + F88BC54E29E072D900CE6141 /* AttachmentData+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80047FF2961850500E6868A /* AttachmentData+CoreDataClass.swift */; }; + F88BC54F29E073BC00CE6141 /* AccountData+AccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88BC51C29E0377B00CE6141 /* AccountData+AccountModel.swift */; }; + F88BC55029E074EB00CE6141 /* Vernissage.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = F88C2476295C37BB0006098B /* Vernissage.xcdatamodeld */; }; + F88BC55229E0798900CE6141 /* SharedAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F88BC55129E0798900CE6141 /* SharedAssets.xcassets */; }; + F88BC55429E0798900CE6141 /* SharedAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F88BC55129E0798900CE6141 /* SharedAssets.xcassets */; }; F88C246C295C37B80006098B /* VernissageApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88C246B295C37B80006098B /* VernissageApp.swift */; }; F88C246E295C37B80006098B /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88C246D295C37B80006098B /* MainView.swift */; }; F88C2470295C37BB0006098B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F88C246F295C37BB0006098B /* Assets.xcassets */; }; @@ -134,53 +134,30 @@ F88C2478295C37BB0006098B /* Vernissage.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = F88C2476295C37BB0006098B /* Vernissage.xcdatamodeld */; }; F88C2482295C3A4F0006098B /* StatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88C2481295C3A4F0006098B /* StatusView.swift */; }; F88E4D42297E69FD0057491A /* StatusesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88E4D41297E69FD0057491A /* StatusesView.swift */; }; - F88E4D44297E82EB0057491A /* Status+MediaAttachmentType.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88E4D43297E82EB0057491A /* Status+MediaAttachmentType.swift */; }; F88E4D48297E90CD0057491A /* TrendStatusesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88E4D47297E90CD0057491A /* TrendStatusesView.swift */; }; F88E4D4A297EA0490057491A /* RouterPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88E4D49297EA0490057491A /* RouterPath.swift */; }; F88E4D4D297EA4290057491A /* EmojiText in Frameworks */ = {isa = PBXBuildFile; productRef = F88E4D4C297EA4290057491A /* EmojiText */; }; - F88E4D54297EA7EE0057491A /* MarkdownFormattedText.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88E4D53297EA7EE0057491A /* MarkdownFormattedText.swift */; }; F88E4D56297EAD6E0057491A /* AppRouteur.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88E4D55297EAD6E0057491A /* AppRouteur.swift */; }; F88FAD21295F3944009B20C9 /* HomeFeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88FAD20295F3944009B20C9 /* HomeFeedView.swift */; }; F88FAD27295F400E009B20C9 /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88FAD26295F400E009B20C9 /* NotificationsView.swift */; }; F88FAD2A295F43B8009B20C9 /* AccountData+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88FAD28295F43B8009B20C9 /* AccountData+CoreDataClass.swift */; }; F88FAD2B295F43B8009B20C9 /* AccountData+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88FAD29295F43B8009B20C9 /* AccountData+CoreDataProperties.swift */; }; - F88FAD2D295F4AD7009B20C9 /* ApplicationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88FAD2C295F4AD7009B20C9 /* ApplicationState.swift */; }; - F88FAD32295F5029009B20C9 /* RemoteFileService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88FAD31295F5029009B20C9 /* RemoteFileService.swift */; }; - F8911A1729DE914D00770F44 /* NavigationMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8911A1629DE914D00770F44 /* NavigationMenu.swift */; }; - F8911A1A29DEA0F500770F44 /* MenuPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8911A1929DEA0F500770F44 /* MenuPosition.swift */; }; - F8911A1B29DEA0F500770F44 /* MenuPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8911A1929DEA0F500770F44 /* MenuPosition.swift */; }; F891E7CE29C35BF50022C449 /* ImageRowItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F891E7CD29C35BF50022C449 /* ImageRowItem.swift */; }; F891E7D029C368750022C449 /* ImageRowItemAsync.swift in Sources */ = {isa = PBXBuildFile; fileRef = F891E7CF29C368750022C449 /* ImageRowItemAsync.swift */; }; - F897978829681B9C00B22335 /* UserAvatar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F897978729681B9C00B22335 /* UserAvatar.swift */; }; - F897978A2968314A00B22335 /* LoadingIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89797892968314A00B22335 /* LoadingIndicator.swift */; }; - F897978D2968369600B22335 /* HapticService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F897978C2968369600B22335 /* HapticService.swift */; }; F897978F29684BCB00B22335 /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F897978E29684BCB00B22335 /* LoadingView.swift */; }; - F8984E4D296B648000A2610F /* UIImage+Blurhash.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8984E4C296B648000A2610F /* UIImage+Blurhash.swift */; }; - F898DE702972868A004B4A6A /* String+Empty.swift in Sources */ = {isa = PBXBuildFile; fileRef = F898DE6F2972868A004B4A6A /* String+Empty.swift */; }; - F898DE7229728CB2004B4A6A /* CommentModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F898DE7129728CB2004B4A6A /* CommentModel.swift */; }; - F8996DEB2971D29D0043EEC6 /* View+Transition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8996DEA2971D29D0043EEC6 /* View+Transition.swift */; }; F89992C9296D6DC7005994BF /* CommentBodyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89992C8296D6DC7005994BF /* CommentBodyView.swift */; }; - F89992CC296D9231005994BF /* StatusModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89992CB296D9231005994BF /* StatusModel.swift */; }; - F89992CE296D92E7005994BF /* AttachmentModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89992CD296D92E7005994BF /* AttachmentModel.swift */; }; F89A46DC296EAACE0062125F /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89A46DB296EAACE0062125F /* SettingsView.swift */; }; F89A46DE296EABA20062125F /* StatusPlaceholderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89A46DD296EABA20062125F /* StatusPlaceholderView.swift */; }; F89AC00529A1F9B500F4159F /* AppMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89AC00429A1F9B500F4159F /* AppMetadata.swift */; }; - F89AC00729A208CC00F4159F /* PlaceSelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89AC00629A208CC00F4159F /* PlaceSelectorView.swift */; }; - F89AC00929A20C5C00F4159F /* Client+Places.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89AC00829A20C5C00F4159F /* Client+Places.swift */; }; F89B5CC029D019B600549F2F /* HTMLString in Frameworks */ = {isa = PBXBuildFile; productRef = F89B5CBF29D019B600549F2F /* HTMLString */; }; F89B5CC229D01BF700549F2F /* InstanceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89B5CC129D01BF700549F2F /* InstanceView.swift */; }; F89CEB802984198600A1376F /* AttachmentData+HighestImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89CEB7F2984198600A1376F /* AttachmentData+HighestImage.swift */; }; - F89D6C3F29716E41001DA3D4 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89D6C3E29716E41001DA3D4 /* Theme.swift */; }; F89D6C4229717FDC001DA3D4 /* AccountsSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89D6C4129717FDC001DA3D4 /* AccountsSectionView.swift */; }; F89D6C4429718092001DA3D4 /* AccentsSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89D6C4329718092001DA3D4 /* AccentsSectionView.swift */; }; F89D6C4629718193001DA3D4 /* GeneralSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89D6C4529718193001DA3D4 /* GeneralSectionView.swift */; }; F89D6C4A297196FF001DA3D4 /* ImageViewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89D6C49297196FF001DA3D4 /* ImageViewer.swift */; }; - F89F57AA29D1AE5D00001EE3 /* Client+Blocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89F57A929D1AE5D00001EE3 /* Client+Blocks.swift */; }; - F89F57AC29D1AEBC00001EE3 /* Client+Mutes.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89F57AB29D1AEBC00001EE3 /* Client+Mutes.swift */; }; - F89F57AE29D1B82700001EE3 /* TagWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89F57AD29D1B82600001EE3 /* TagWidget.swift */; }; F89F57B029D1C11200001EE3 /* RelationshipModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89F57AF29D1C11200001EE3 /* RelationshipModel.swift */; }; F8A93D7E2965FD89001D8331 /* UserProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8A93D7D2965FD89001D8331 /* UserProfileView.swift */; }; - F8AD061329A565620042F111 /* String+Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8AD061229A565620042F111 /* String+Random.swift */; }; F8AFF7C129B259150087D083 /* HashtagsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8AFF7C029B259150087D083 /* HashtagsView.swift */; }; F8AFF7C429B25EF40087D083 /* ImagesGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8AFF7C329B25EF40087D083 /* ImagesGrid.swift */; }; F8B05ACB29B489B100857221 /* HapticsSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B05ACA29B489B100857221 /* HapticsSectionView.swift */; }; @@ -188,43 +165,15 @@ F8B0885E29942E31002AB40A /* ThirdPartyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B0885D29942E31002AB40A /* ThirdPartyView.swift */; }; F8B0886029943498002AB40A /* OtherSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B0885F29943498002AB40A /* OtherSectionView.swift */; }; F8B08862299435C9002AB40A /* SupportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B08861299435C9002AB40A /* SupportView.swift */; }; - F8B1E64F2973F61400EE0D10 /* Drops in Frameworks */ = {isa = PBXBuildFile; productRef = F8B1E64E2973F61400EE0D10 /* Drops */; }; - F8B1E6512973FB7E00EE0D10 /* ToastrService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B1E6502973FB7E00EE0D10 /* ToastrService.swift */; }; - F8B9B345298D1FCB009CC69C /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B9B344298D1FCB009CC69C /* Client.swift */; }; - F8B9B347298D4A7C009CC69C /* Client+Trends.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B9B346298D4A7C009CC69C /* Client+Trends.swift */; }; - F8B9B349298D4AA2009CC69C /* Client+Timeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B9B348298D4AA2009CC69C /* Client+Timeline.swift */; }; - F8B9B34B298D4ACE009CC69C /* Client+Tags.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B9B34A298D4ACE009CC69C /* Client+Tags.swift */; }; - F8B9B34D298D4AE4009CC69C /* Client+Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B9B34C298D4AE4009CC69C /* Client+Notifications.swift */; }; - F8B9B34F298D4B14009CC69C /* Client+Statuses.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B9B34E298D4B14009CC69C /* Client+Statuses.swift */; }; - F8B9B351298D4B34009CC69C /* Client+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B9B350298D4B34009CC69C /* Client+Account.swift */; }; - F8B9B353298D4B5D009CC69C /* Client+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B9B352298D4B5D009CC69C /* Client+Search.swift */; }; - F8B9B356298D4C1E009CC69C /* Client+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B9B355298D4C1E009CC69C /* Client+Instance.swift */; }; - F8C14392296AF0B3001FE31D /* String+Exif.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8C14391296AF0B3001FE31D /* String+Exif.swift */; }; - F8C14394296AF21B001FE31D /* Double+Round.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8C14393296AF21B001FE31D /* Double+Round.swift */; }; - F8C5E55F2988E92600ADF6A7 /* AccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8C5E55E2988E92600ADF6A7 /* AccountModel.swift */; }; - F8C5E56229892CC300ADF6A7 /* FirstAppear.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8C5E56129892CC300ADF6A7 /* FirstAppear.swift */; }; - F8CAE63E29B8902D001E0372 /* ClearButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8CAE63D29B8902D001E0372 /* ClearButton.swift */; }; - F8CAE64029B8E6E1001E0372 /* UIApplication+Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8CAE63F29B8E6E1001E0372 /* UIApplication+Window.swift */; }; - F8CC95CE2970761D00C9C2AC /* TintColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8CC95CD2970761D00C9C2AC /* TintColor.swift */; }; - F8CEEDF829ABADDD00DBED66 /* UIImage+Size.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8CEEDF729ABADDD00DBED66 /* UIImage+Size.swift */; }; - F8CEEDFA29ABAFD200DBED66 /* ImageFileTranseferable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8CEEDF929ABAFD200DBED66 /* ImageFileTranseferable.swift */; }; F8D5444329D4066C002225D6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8D5444229D4066C002225D6 /* AppDelegate.swift */; }; F8DF38E429DD68820047F1AA /* ViewOffsetKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DF38E329DD68820047F1AA /* ViewOffsetKey.swift */; }; F8DF38E629DDB98A0047F1AA /* SocialsSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DF38E529DDB98A0047F1AA /* SocialsSectionView.swift */; }; F8E6D03329CDD52500416CCA /* EditProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E6D03229CDD52500416CCA /* EditProfileView.swift */; }; - F8E6D03529CE161B00416CCA /* UIImage+Jpeg.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E6D03429CE161B00416CCA /* UIImage+Jpeg.swift */; }; - F8E9391F29C0BCFA002BB3B8 /* ImageContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E9391E29C0BCFA002BB3B8 /* ImageContextMenu.swift */; }; - F8E9392129C0DA7E002BB3B8 /* LazyImageState+ImageResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E9392029C0DA7E002BB3B8 /* LazyImageState+ImageResponse.swift */; }; F8F6E44229BC58F20004795E /* Vernissage.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = F88C2476295C37BB0006098B /* Vernissage.xcdatamodeld */; }; F8F6E44C29BCC1F70004795E /* SmallWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44629BCC0DC0004795E /* SmallWidgetView.swift */; }; F8F6E44D29BCC1F90004795E /* MediumWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44829BCC0F00004795E /* MediumWidgetView.swift */; }; F8F6E44E29BCC1FB0004795E /* LargeWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44A29BCC0FF0004795E /* LargeWidgetView.swift */; }; F8F6E45129BCE9190004795E /* UIImage+Resize.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E45029BCE9190004795E /* UIImage+Resize.swift */; }; - F8FA9917299F7DBD007AB130 /* Client+Media.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FA9916299F7DBD007AB130 /* Client+Media.swift */; }; - F8FA9919299FA35A007AB130 /* PhotoAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FA9918299FA35A007AB130 /* PhotoAttachment.swift */; }; - F8FA991C299FA8C2007AB130 /* ImageUploadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FA991B299FA8C2007AB130 /* ImageUploadView.swift */; }; - F8FA991E299FAB92007AB130 /* PhotoEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FA991D299FAB92007AB130 /* PhotoEditorView.swift */; }; - F8FA9920299FDDC3007AB130 /* TextInputField.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FA991F299FDDC3007AB130 /* TextInputField.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -235,6 +184,13 @@ remoteGlobalIDString = F864F75C29BB91B400B13921; remoteInfo = VernissageWidgetExtension; }; + F88BC50A29E02F3900CE6141 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F88C2460295C37B80006098B /* Project object */; + proxyType = 1; + remoteGlobalIDString = F88BC50129E02F3900CE6141; + remoteInfo = VernissageShareExtension; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -245,6 +201,7 @@ dstSubfolderSpec = 13; files = ( F864F76C29BB91B600B13921 /* VernissageWidgetExtension.appex in Embed Foundation Extensions */, + F88BC50C29E02F3900CE6141 /* VernissageShareExtension.appex in Embed Foundation Extensions */, ); name = "Embed Foundation Extensions"; runOnlyForDeploymentPostprocessing = 0; @@ -259,41 +216,30 @@ F80048072961E6DE00E6868A /* StatusDataHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusDataHandler.swift; sourceTree = ""; }; F80048092961EA1900E6868A /* AttachmentDataHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentDataHandler.swift; sourceTree = ""; }; F802884E297AEED5000BDD51 /* DatabaseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseError.swift; sourceTree = ""; }; - F805DCEE29DBED96006A1FD9 /* Client+Report.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Client+Report.swift"; sourceTree = ""; }; F805DCF029DBEF83006A1FD9 /* ReportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportView.swift; sourceTree = ""; }; F808641329756666009F035C /* NotificationRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationRowView.swift; sourceTree = ""; }; F8121CA7298A86D600B466C7 /* InstanceRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceRowView.swift; sourceTree = ""; }; F8210DCE2966B600001D9973 /* ImageRowAsync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRowAsync.swift; sourceTree = ""; }; F8210DDC2966CF17001D9973 /* StatusData+Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StatusData+Status.swift"; sourceTree = ""; }; F8210DDE2966CFC7001D9973 /* AttachmentData+Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttachmentData+Attachment.swift"; sourceTree = ""; }; - F8210DE42966E160001D9973 /* Color+SystemColors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+SystemColors.swift"; sourceTree = ""; }; - F8210DE62966E1D1001D9973 /* Color+Assets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Assets.swift"; sourceTree = ""; }; F8210DE92966E4F9001D9973 /* AnimatePlaceholderModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatePlaceholderModifier.swift; sourceTree = ""; }; - F829193B2983012400367CE2 /* ImageSizeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageSizeService.swift; sourceTree = ""; }; - F8341F8F295C636C009C8EE6 /* Data+Exif.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Exif.swift"; sourceTree = ""; }; F835082529BEF9C400DE3247 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; F835082729BEFA1E00DE3247 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; F837269429A221420098D3C4 /* PixelfedKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = PixelfedKit; sourceTree = ""; }; - F83901A5295D8EC000456AE2 /* LabelIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelIcon.swift; sourceTree = ""; }; F83CBEFA298298A1002972C8 /* ImageCarouselPicture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCarouselPicture.swift; sourceTree = ""; }; F844F42429D2DC39000DD896 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; - F857F9FC297D8ED3002C109C /* ActionMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionMenu.swift; sourceTree = ""; }; + F858906A29E1CC7A00D4BDED /* UIApplication+Window.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+Window.swift"; sourceTree = ""; }; F85D4970296402DC00751DF7 /* AuthorizationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorizationService.swift; sourceTree = ""; }; - F85D4972296406E700751DF7 /* BottomRight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomRight.swift; sourceTree = ""; }; F85D4974296407F100751DF7 /* HomeTimelineService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTimelineService.swift; sourceTree = ""; }; F85D497629640A5200751DF7 /* ImageRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRow.swift; sourceTree = ""; }; F85D497829640B9D00751DF7 /* ImagesCarousel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagesCarousel.swift; sourceTree = ""; }; - F85D497A29640C8200751DF7 /* UsernameRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsernameRow.swift; sourceTree = ""; }; F85D497C29640D5900751DF7 /* InteractionRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionRow.swift; sourceTree = ""; }; F85D497E296416C800751DF7 /* CommentsSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentsSectionView.swift; sourceTree = ""; }; F85D498229642FAC00751DF7 /* AttachmentData+Comperable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttachmentData+Comperable.swift"; sourceTree = ""; }; F85D49842964301800751DF7 /* StatusData+Attachments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StatusData+Attachments.swift"; sourceTree = ""; }; - F85D49862964334100751DF7 /* String+Date.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Date.swift"; sourceTree = ""; }; F85D4DFD29B78C8400345267 /* HashtagModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagModel.swift; sourceTree = ""; }; F85DBF8E296732E20069BF89 /* AccountsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsView.swift; sourceTree = ""; }; - F85E131F297409CD006A051D /* ErrorsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorsService.swift; sourceTree = ""; }; F86167C5297FE6CC004D1F67 /* AvatarShapesSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarShapesSectionView.swift; sourceTree = ""; }; - F86167C7297FE781004D1F67 /* AvatarShape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarShape.swift; sourceTree = ""; }; F864F75D29BB91B400B13921 /* VernissageWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = VernissageWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; F864F75E29BB91B400B13921 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; F864F76029BB91B400B13921 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; @@ -305,9 +251,6 @@ F864F77329BB929A00B13921 /* Provider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Provider.swift; sourceTree = ""; }; F864F77729BB930000B13921 /* WidgetEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetEntry.swift; sourceTree = ""; }; F864F77B29BB982100B13921 /* ImageFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageFetcher.swift; sourceTree = ""; }; - F864F79E29BB9E6A00B13921 /* TintColor+Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TintColor+Color.swift"; sourceTree = ""; }; - F864F7A029BB9E8F00B13921 /* AvatarShape+Shape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AvatarShape+Shape.swift"; sourceTree = ""; }; - F864F7A229BB9EC700B13921 /* Theme+ColorScheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+ColorScheme.swift"; sourceTree = ""; }; F864F7A429BBA01D00B13921 /* CoreDataError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataError.swift; sourceTree = ""; }; F866F69E296040A8002E8F88 /* ApplicationSettings+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ApplicationSettings+CoreDataClass.swift"; sourceTree = ""; }; F866F69F296040A8002E8F88 /* ApplicationSettings+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ApplicationSettings+CoreDataProperties.swift"; sourceTree = ""; }; @@ -325,33 +268,32 @@ F86A4306299AA5E900DF7645 /* ThanksView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThanksView.swift; sourceTree = ""; }; F86B7213296BFDCE00EE59EC /* UserProfileHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileHeaderView.swift; sourceTree = ""; }; F86B7215296BFFDA00EE59EC /* UserProfileStatusesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileStatusesView.swift; sourceTree = ""; }; - F86B7217296C27C100EE59EC /* ActionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionButton.swift; sourceTree = ""; }; - F86B721D296C458700EE59EC /* BlurredImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurredImage.swift; sourceTree = ""; }; F86B7220296C49A300EE59EC /* EmptyButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyButtonStyle.swift; sourceTree = ""; }; - F86B7222296C4BF500EE59EC /* ContentWarning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentWarning.swift; sourceTree = ""; }; - F86FB554298BF83F000131F0 /* FavouriteTouch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavouriteTouch.swift; sourceTree = ""; }; - F873F14B29BDB67300DE72D1 /* UIImage+Rounded.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Rounded.swift"; sourceTree = ""; }; F8742FC329990AFB00E9642B /* ClientError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientError.swift; sourceTree = ""; }; F8764186298ABB520057D362 /* ViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewState.swift; sourceTree = ""; }; - F8764188298ABEC80057D362 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = ""; }; - F876418A298AC1B80057D362 /* NoDataView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoDataView.swift; sourceTree = ""; }; F876418C298AE5020057D362 /* PaginableStatusesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginableStatusesView.swift; sourceTree = ""; }; F878842129A4A4E3003CFAD2 /* AppMetadataService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMetadataService.swift; sourceTree = ""; }; F87AEB912986C44E00434FB6 /* AuthorizationSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorizationSession.swift; sourceTree = ""; }; - F87AEB932986C51B00434FB6 /* AppConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = ""; }; F87AEB962986D16D00434FB6 /* AuthorisationError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorisationError.swift; sourceTree = ""; }; F883401F29B62AE900C3E096 /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = ""; }; - F8864CE829ACAF820020C534 /* TextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextView.swift; sourceTree = ""; }; - F8864CEA29ACBAA80020C534 /* TextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextModel.swift; sourceTree = ""; }; - F8864CEE29ACE90B0020C534 /* UIFont+Font.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+Font.swift"; sourceTree = ""; }; - F8864CF029ACFFB80020C534 /* View+Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Keyboard.swift"; sourceTree = ""; }; - F886F256297859E300879356 /* CacheImageService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheImageService.swift; sourceTree = ""; }; F88AB05229B3613900345EDE /* PhotoUrl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoUrl.swift; sourceTree = ""; }; F88AB05429B3626300345EDE /* ImageGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageGrid.swift; sourceTree = ""; }; F88AB05729B36B8200345EDE /* AccountsPhotoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsPhotoView.swift; sourceTree = ""; }; - F88ABD9129686F1C004EF61E /* MemoryCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryCache.swift; sourceTree = ""; }; F88ABD9329687CA4004EF61E /* ComposeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeView.swift; sourceTree = ""; }; F88ABD9529687D4D004EF61E /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + F88BC50229E02F3900CE6141 /* VernissageShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = VernissageShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + F88BC50429E02F3900CE6141 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; + F88BC50929E02F3900CE6141 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F88BC51229E02FD800CE6141 /* ComposeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeView.swift; sourceTree = ""; }; + F88BC51429E02FEB00CE6141 /* VernissageShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = VernissageShareExtension.entitlements; sourceTree = ""; }; + F88BC51529E0307F00CE6141 /* NotificationsName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsName.swift; sourceTree = ""; }; + F88BC51929E0344000CE6141 /* ClientKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = ClientKit; sourceTree = ""; }; + F88BC51C29E0377B00CE6141 /* AccountData+AccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountData+AccountModel.swift"; sourceTree = ""; }; + F88BC52529E0421F00CE6141 /* ServicesKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = ServicesKit; sourceTree = ""; }; + F88BC52829E0467400CE6141 /* WidgetsKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = WidgetsKit; sourceTree = ""; }; + F88BC52B29E04AC200CE6141 /* EnvironmentKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = EnvironmentKit; sourceTree = ""; }; + F88BC53A29E06A5100CE6141 /* ImageContextMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageContextMenu.swift; sourceTree = ""; }; + F88BC55129E0798900CE6141 /* SharedAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = SharedAssets.xcassets; sourceTree = ""; }; F88C2468295C37B80006098B /* Vernissage.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Vernissage.app; sourceTree = BUILT_PRODUCTS_DIR; }; F88C246B295C37B80006098B /* VernissageApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VernissageApp.swift; sourceTree = ""; }; F88C246D295C37B80006098B /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; @@ -361,52 +303,30 @@ F88C2477295C37BB0006098B /* Vernissage.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Vernissage.xcdatamodel; sourceTree = ""; }; F88C2481295C3A4F0006098B /* StatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusView.swift; sourceTree = ""; }; F88E4D41297E69FD0057491A /* StatusesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusesView.swift; sourceTree = ""; }; - F88E4D43297E82EB0057491A /* Status+MediaAttachmentType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Status+MediaAttachmentType.swift"; sourceTree = ""; }; F88E4D47297E90CD0057491A /* TrendStatusesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendStatusesView.swift; sourceTree = ""; }; F88E4D49297EA0490057491A /* RouterPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterPath.swift; sourceTree = ""; }; - F88E4D53297EA7EE0057491A /* MarkdownFormattedText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkdownFormattedText.swift; sourceTree = ""; }; F88E4D55297EAD6E0057491A /* AppRouteur.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouteur.swift; sourceTree = ""; }; F88FAD20295F3944009B20C9 /* HomeFeedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeFeedView.swift; sourceTree = ""; }; F88FAD26295F400E009B20C9 /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = ""; }; F88FAD28295F43B8009B20C9 /* AccountData+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountData+CoreDataClass.swift"; sourceTree = ""; }; F88FAD29295F43B8009B20C9 /* AccountData+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountData+CoreDataProperties.swift"; sourceTree = ""; }; - F88FAD2C295F4AD7009B20C9 /* ApplicationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationState.swift; sourceTree = ""; }; - F88FAD31295F5029009B20C9 /* RemoteFileService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteFileService.swift; sourceTree = ""; }; - F8911A1629DE914D00770F44 /* NavigationMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationMenu.swift; sourceTree = ""; }; F8911A1829DE9E5500770F44 /* Vernissage-007.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-007.xcdatamodel"; sourceTree = ""; }; - F8911A1929DEA0F500770F44 /* MenuPosition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuPosition.swift; sourceTree = ""; }; F891E7CD29C35BF50022C449 /* ImageRowItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRowItem.swift; sourceTree = ""; }; F891E7CF29C368750022C449 /* ImageRowItemAsync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRowItemAsync.swift; sourceTree = ""; }; - F897978729681B9C00B22335 /* UserAvatar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAvatar.swift; sourceTree = ""; }; - F89797892968314A00B22335 /* LoadingIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingIndicator.swift; sourceTree = ""; }; - F897978C2968369600B22335 /* HapticService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HapticService.swift; sourceTree = ""; }; F897978E29684BCB00B22335 /* LoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingView.swift; sourceTree = ""; }; - F8984E4C296B648000A2610F /* UIImage+Blurhash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Blurhash.swift"; sourceTree = ""; }; - F898DE6F2972868A004B4A6A /* String+Empty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Empty.swift"; sourceTree = ""; }; - F898DE7129728CB2004B4A6A /* CommentModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentModel.swift; sourceTree = ""; }; - F8996DEA2971D29D0043EEC6 /* View+Transition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Transition.swift"; sourceTree = ""; }; F89992C8296D6DC7005994BF /* CommentBodyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentBodyView.swift; sourceTree = ""; }; - F89992CB296D9231005994BF /* StatusModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusModel.swift; sourceTree = ""; }; - F89992CD296D92E7005994BF /* AttachmentModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentModel.swift; sourceTree = ""; }; F89A46DB296EAACE0062125F /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; F89A46DD296EABA20062125F /* StatusPlaceholderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusPlaceholderView.swift; sourceTree = ""; }; F89AC00429A1F9B500F4159F /* AppMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMetadata.swift; sourceTree = ""; }; - F89AC00629A208CC00F4159F /* PlaceSelectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceSelectorView.swift; sourceTree = ""; }; - F89AC00829A20C5C00F4159F /* Client+Places.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Client+Places.swift"; sourceTree = ""; }; F89B5CC129D01BF700549F2F /* InstanceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceView.swift; sourceTree = ""; }; F89CEB7F2984198600A1376F /* AttachmentData+HighestImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttachmentData+HighestImage.swift"; sourceTree = ""; }; - F89D6C3E29716E41001DA3D4 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; }; F89D6C4129717FDC001DA3D4 /* AccountsSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsSectionView.swift; sourceTree = ""; }; F89D6C4329718092001DA3D4 /* AccentsSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccentsSectionView.swift; sourceTree = ""; }; F89D6C4529718193001DA3D4 /* GeneralSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSectionView.swift; sourceTree = ""; }; F89D6C49297196FF001DA3D4 /* ImageViewer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageViewer.swift; sourceTree = ""; }; F89F0605299139F6003DC875 /* Vernissage-002.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-002.xcdatamodel"; sourceTree = ""; }; - F89F57A929D1AE5D00001EE3 /* Client+Blocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Client+Blocks.swift"; sourceTree = ""; }; - F89F57AB29D1AEBC00001EE3 /* Client+Mutes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Client+Mutes.swift"; sourceTree = ""; }; - F89F57AD29D1B82600001EE3 /* TagWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagWidget.swift; sourceTree = ""; }; F89F57AF29D1C11200001EE3 /* RelationshipModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelationshipModel.swift; sourceTree = ""; }; F8A93D7D2965FD89001D8331 /* UserProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileView.swift; sourceTree = ""; }; - F8AD061229A565620042F111 /* String+Random.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Random.swift"; sourceTree = ""; }; F8AFF7C029B259150087D083 /* HashtagsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagsView.swift; sourceTree = ""; }; F8AFF7C329B25EF40087D083 /* ImagesGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagesGrid.swift; sourceTree = ""; }; F8B05AC929B488C600857221 /* Vernissage-003.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-003.xcdatamodel"; sourceTree = ""; }; @@ -416,37 +336,15 @@ F8B0885D29942E31002AB40A /* ThirdPartyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThirdPartyView.swift; sourceTree = ""; }; F8B0885F29943498002AB40A /* OtherSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OtherSectionView.swift; sourceTree = ""; }; F8B08861299435C9002AB40A /* SupportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportView.swift; sourceTree = ""; }; - F8B1E6502973FB7E00EE0D10 /* ToastrService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastrService.swift; sourceTree = ""; }; F8B3699A29D86EB600BE3808 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = ""; }; F8B3699B29D86EBD00BE3808 /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = ""; }; - F8B9B344298D1FCB009CC69C /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = ""; }; - F8B9B346298D4A7C009CC69C /* Client+Trends.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Client+Trends.swift"; sourceTree = ""; }; - F8B9B348298D4AA2009CC69C /* Client+Timeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Client+Timeline.swift"; sourceTree = ""; }; - F8B9B34A298D4ACE009CC69C /* Client+Tags.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Client+Tags.swift"; sourceTree = ""; }; - F8B9B34C298D4AE4009CC69C /* Client+Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Client+Notifications.swift"; sourceTree = ""; }; - F8B9B34E298D4B14009CC69C /* Client+Statuses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Client+Statuses.swift"; sourceTree = ""; }; - F8B9B350298D4B34009CC69C /* Client+Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Client+Account.swift"; sourceTree = ""; }; - F8B9B352298D4B5D009CC69C /* Client+Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Client+Search.swift"; sourceTree = ""; }; - F8B9B355298D4C1E009CC69C /* Client+Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Client+Instance.swift"; sourceTree = ""; }; - F8C14391296AF0B3001FE31D /* String+Exif.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Exif.swift"; sourceTree = ""; }; - F8C14393296AF21B001FE31D /* Double+Round.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+Round.swift"; sourceTree = ""; }; - F8C5E55E2988E92600ADF6A7 /* AccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountModel.swift; sourceTree = ""; }; - F8C5E56129892CC300ADF6A7 /* FirstAppear.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstAppear.swift; sourceTree = ""; }; F8C937A929882CA90004D782 /* Vernissage-001.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-001.xcdatamodel"; sourceTree = ""; }; - F8CAE63D29B8902D001E0372 /* ClearButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearButton.swift; sourceTree = ""; }; - F8CAE63F29B8E6E1001E0372 /* UIApplication+Window.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Window.swift"; sourceTree = ""; }; F8CAE64129B8F1AF001E0372 /* Vernissage-005.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-005.xcdatamodel"; sourceTree = ""; }; - F8CC95CD2970761D00C9C2AC /* TintColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TintColor.swift; sourceTree = ""; }; - F8CEEDF729ABADDD00DBED66 /* UIImage+Size.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Size.swift"; sourceTree = ""; }; - F8CEEDF929ABAFD200DBED66 /* ImageFileTranseferable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageFileTranseferable.swift; sourceTree = ""; }; F8D5444229D4066C002225D6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; F8DF38E329DD68820047F1AA /* ViewOffsetKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewOffsetKey.swift; sourceTree = ""; }; F8DF38E529DDB98A0047F1AA /* SocialsSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocialsSectionView.swift; sourceTree = ""; }; F8DF38E729DDC3D20047F1AA /* eu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = eu; path = eu.lproj/Localizable.strings; sourceTree = ""; }; F8E6D03229CDD52500416CCA /* EditProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditProfileView.swift; sourceTree = ""; }; - F8E6D03429CE161B00416CCA /* UIImage+Jpeg.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Jpeg.swift"; sourceTree = ""; }; - F8E9391E29C0BCFA002BB3B8 /* ImageContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageContextMenu.swift; sourceTree = ""; }; - F8E9392029C0DA7E002BB3B8 /* LazyImageState+ImageResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LazyImageState+ImageResponse.swift"; sourceTree = ""; }; F8EF371429C624DA00669F45 /* Vernissage-006.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-006.xcdatamodel"; sourceTree = ""; }; F8F6E44329BC5CAA0004795E /* VernissageWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = VernissageWidgetExtension.entitlements; sourceTree = ""; }; F8F6E44429BC5CC50004795E /* Vernissage.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Vernissage.entitlements; sourceTree = ""; }; @@ -454,11 +352,6 @@ F8F6E44829BCC0F00004795E /* MediumWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediumWidgetView.swift; sourceTree = ""; }; F8F6E44A29BCC0FF0004795E /* LargeWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeWidgetView.swift; sourceTree = ""; }; F8F6E45029BCE9190004795E /* UIImage+Resize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Resize.swift"; sourceTree = ""; }; - F8FA9916299F7DBD007AB130 /* Client+Media.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Client+Media.swift"; sourceTree = ""; }; - F8FA9918299FA35A007AB130 /* PhotoAttachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoAttachment.swift; sourceTree = ""; }; - F8FA991B299FA8C2007AB130 /* ImageUploadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageUploadView.swift; sourceTree = ""; }; - F8FA991D299FAB92007AB130 /* PhotoEditorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoEditorView.swift; sourceTree = ""; }; - F8FA991F299FDDC3007AB130 /* TextInputField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextInputField.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -469,6 +362,18 @@ F864F76129BB91B400B13921 /* SwiftUI.framework in Frameworks */, F864F77A29BB94A800B13921 /* PixelfedKit in Frameworks */, F864F75F29BB91B400B13921 /* WidgetKit.framework in Frameworks */, + F88BC52F29E04C5F00CE6141 /* EnvironmentKit in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F88BC4FF29E02F3900CE6141 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F88BC51F29E03ED300CE6141 /* ClientKit in Frameworks */, + F88BC53F29E06EB100CE6141 /* WidgetsKit in Frameworks */, + F88BC53229E0677000CE6141 /* EnvironmentKit in Frameworks */, + F88BC53D29E06EAD00CE6141 /* ServicesKit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -477,14 +382,15 @@ buildActionMask = 2147483647; files = ( F86A42FD299A8B8E00DF7645 /* StoreKit.framework in Frameworks */, + F88BC52729E0431D00CE6141 /* ServicesKit in Frameworks */, F8210DD52966BB7E001D9973 /* Nuke in Frameworks */, + F88BC51B29E0350300CE6141 /* ClientKit in Frameworks */, F88E4D4D297EA4290057491A /* EmojiText in Frameworks */, F8210DD72966BB7E001D9973 /* NukeExtensions in Frameworks */, - F83E00ED29A2237C005D25A3 /* PixelfedKit in Frameworks */, + F88BC52D29E04BB600CE6141 /* EnvironmentKit in Frameworks */, F8210DD92966BB7E001D9973 /* NukeUI in Frameworks */, - F85E132529741F05006A051D /* ActivityIndicatorView in Frameworks */, F89B5CC029D019B600549F2F /* HTMLString in Frameworks */, - F8B1E64F2973F61400EE0D10 /* Drops in Frameworks */, + F88BC52A29E046D700CE6141 /* WidgetsKit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -536,8 +442,8 @@ F808641229756583009F035C /* NotificationsView */, F8121CA6298A86B300B466C7 /* SignInView */, F89D6C4829718868001DA3D4 /* StatusView */, - F8FA991A299FA8A5007AB130 /* ComposeView */, F88C246D295C37B80006098B /* MainView.swift */, + F88ABD9329687CA4004EF61E /* ComposeView.swift */, F88FAD20295F3944009B20C9 /* HomeFeedView.swift */, F88AB05729B36B8200345EDE /* AccountsPhotoView.swift */, F88E4D47297E90CD0057491A /* TrendStatusesView.swift */, @@ -548,8 +454,6 @@ F85DBF8E296732E20069BF89 /* AccountsView.swift */, F897978E29684BCB00B22335 /* LoadingView.swift */, F8B0885D29942E31002AB40A /* ThirdPartyView.swift */, - F8FA991D299FAB92007AB130 /* PhotoEditorView.swift */, - F89AC00629A208CC00F4159F /* PlaceSelectorView.swift */, F8E6D03229CDD52500416CCA /* EditProfileView.swift */, F89B5CC129D01BF700549F2F /* InstanceView.swift */, F805DCF029DBEF83006A1FD9 /* ReportView.swift */, @@ -557,46 +461,12 @@ path = Views; sourceTree = ""; }; - F8341F94295C63FE009C8EE6 /* Extensions */ = { - isa = PBXGroup; - children = ( - F8341F8F295C636C009C8EE6 /* Data+Exif.swift */, - F85D49862964334100751DF7 /* String+Date.swift */, - F8C14391296AF0B3001FE31D /* String+Exif.swift */, - F898DE6F2972868A004B4A6A /* String+Empty.swift */, - F8AD061229A565620042F111 /* String+Random.swift */, - F8210DE42966E160001D9973 /* Color+SystemColors.swift */, - F8210DE62966E1D1001D9973 /* Color+Assets.swift */, - F8C14393296AF21B001FE31D /* Double+Round.swift */, - F8984E4C296B648000A2610F /* UIImage+Blurhash.swift */, - F8CEEDF729ABADDD00DBED66 /* UIImage+Size.swift */, - F8E6D03429CE161B00416CCA /* UIImage+Jpeg.swift */, - F8996DEA2971D29D0043EEC6 /* View+Transition.swift */, - F88E4D43297E82EB0057491A /* Status+MediaAttachmentType.swift */, - F8864CEE29ACE90B0020C534 /* UIFont+Font.swift */, - F8864CF029ACFFB80020C534 /* View+Keyboard.swift */, - F8CAE63F29B8E6E1001E0372 /* UIApplication+Window.swift */, - F864F79E29BB9E6A00B13921 /* TintColor+Color.swift */, - F864F7A029BB9E8F00B13921 /* AvatarShape+Shape.swift */, - F864F7A229BB9EC700B13921 /* Theme+ColorScheme.swift */, - F873F14B29BDB67300DE72D1 /* UIImage+Rounded.swift */, - F8E9392029C0DA7E002BB3B8 /* LazyImageState+ImageResponse.swift */, - ); - path = Extensions; - sourceTree = ""; - }; F8341F95295C640C009C8EE6 /* Models */ = { isa = PBXGroup; children = ( - F89992CB296D9231005994BF /* StatusModel.swift */, - F89992CD296D92E7005994BF /* AttachmentModel.swift */, - F898DE7129728CB2004B4A6A /* CommentModel.swift */, - F8C5E55E2988E92600ADF6A7 /* AccountModel.swift */, F866F6AD29606367002E8F88 /* ApplicationViewMode.swift */, F8764186298ABB520057D362 /* ViewState.swift */, - F8FA9918299FA35A007AB130 /* PhotoAttachment.swift */, F89AC00429A1F9B500F4159F /* AppMetadata.swift */, - F8CEEDF929ABAFD200DBED66 /* ImageFileTranseferable.swift */, F88AB05229B3613900345EDE /* PhotoUrl.swift */, F85D4DFD29B78C8400345267 /* HashtagModel.swift */, F89F57AF29D1C11200001EE3 /* RelationshipModel.swift */, @@ -622,6 +492,7 @@ F866F69F296040A8002E8F88 /* ApplicationSettings+CoreDataProperties.swift */, F88FAD28295F43B8009B20C9 /* AccountData+CoreDataClass.swift */, F88FAD29295F43B8009B20C9 /* AccountData+CoreDataProperties.swift */, + F88BC51C29E0377B00CE6141 /* AccountData+AccountModel.swift */, F88C2474295C37BB0006098B /* CoreDataHandler.swift */, F866F6A229604161002E8F88 /* AccountDataHandler.swift */, F866F6A429604194002E8F88 /* ApplicationSettingsHandler.swift */, @@ -643,36 +514,28 @@ F83901A2295D863B00456AE2 /* Widgets */ = { isa = PBXGroup; children = ( - F8864CF229AD05420020C534 /* TextView */, - F83901A5295D8EC000456AE2 /* LabelIcon.swift */, - F85D4972296406E700751DF7 /* BottomRight.swift */, F85D497629640A5200751DF7 /* ImageRow.swift */, F891E7CD29C35BF50022C449 /* ImageRowItem.swift */, F8210DCE2966B600001D9973 /* ImageRowAsync.swift */, F891E7CF29C368750022C449 /* ImageRowItemAsync.swift */, F85D497829640B9D00751DF7 /* ImagesCarousel.swift */, F83CBEFA298298A1002972C8 /* ImageCarouselPicture.swift */, - F89F57AD29D1B82600001EE3 /* TagWidget.swift */, - F85D497A29640C8200751DF7 /* UsernameRow.swift */, F85D497C29640D5900751DF7 /* InteractionRow.swift */, - F897978729681B9C00B22335 /* UserAvatar.swift */, - F89797892968314A00B22335 /* LoadingIndicator.swift */, F88AB05429B3626300345EDE /* ImageGrid.swift */, F8AFF7C329B25EF40087D083 /* ImagesGrid.swift */, - F86B7217296C27C100EE59EC /* ActionButton.swift */, - F86B721D296C458700EE59EC /* BlurredImage.swift */, - F86B7222296C4BF500EE59EC /* ContentWarning.swift */, F89D6C49297196FF001DA3D4 /* ImageViewer.swift */, - F857F9FC297D8ED3002C109C /* ActionMenu.swift */, - F88E4D53297EA7EE0057491A /* MarkdownFormattedText.swift */, - F8764188298ABEC80057D362 /* ErrorView.swift */, - F876418A298AC1B80057D362 /* NoDataView.swift */, - F86FB554298BF83F000131F0 /* FavouriteTouch.swift */, - F8FA991F299FDDC3007AB130 /* TextInputField.swift */, ); path = Widgets; sourceTree = ""; }; + F858906729E1CC2900D4BDED /* Extensions */ = { + isa = PBXGroup; + children = ( + F858906A29E1CC7A00D4BDED /* UIApplication+Window.swift */, + ); + path = Extensions; + sourceTree = ""; + }; F864F76229BB91B400B13921 /* VernissageWidget */ = { isa = PBXGroup; children = ( @@ -691,18 +554,6 @@ path = VernissageWidget; sourceTree = ""; }; - F864F79C29BB9D2400B13921 /* Models */ = { - isa = PBXGroup; - children = ( - F8CC95CD2970761D00C9C2AC /* TintColor.swift */, - F86167C7297FE781004D1F67 /* AvatarShape.swift */, - F89D6C3E29716E41001DA3D4 /* Theme.swift */, - F87AEB932986C51B00434FB6 /* AppConstants.swift */, - F8911A1929DEA0F500770F44 /* MenuPosition.swift */, - ); - path = Models; - sourceTree = ""; - }; F86B721F296C498B00EE59EC /* Styles */ = { isa = PBXGroup; children = ( @@ -763,45 +614,45 @@ path = Subviews; sourceTree = ""; }; - F878842029A494E3003CFAD2 /* Subviews */ = { + F88BC50329E02F3900CE6141 /* VernissageShare */ = { isa = PBXGroup; children = ( - F8FA991B299FA8C2007AB130 /* ImageUploadView.swift */, + F88BC51429E02FEB00CE6141 /* VernissageShareExtension.entitlements */, + F88BC51229E02FD800CE6141 /* ComposeView.swift */, + F88BC51529E0307F00CE6141 /* NotificationsName.swift */, + F88BC50429E02F3900CE6141 /* ShareViewController.swift */, + F88BC50929E02F3900CE6141 /* Info.plist */, ); - path = Subviews; + path = VernissageShare; sourceTree = ""; }; - F8864CF229AD05420020C534 /* TextView */ = { + F88BC53729E068D200CE6141 /* ViewModifiers */ = { isa = PBXGroup; children = ( - F8864CEA29ACBAA80020C534 /* TextModel.swift */, - F8864CE829ACAF820020C534 /* TextView.swift */, + F88BC53A29E06A5100CE6141 /* ImageContextMenu.swift */, ); - path = TextView; - sourceTree = ""; - }; - F88ABD9029686F00004EF61E /* Cache */ = { - isa = PBXGroup; - children = ( - F88ABD9129686F1C004EF61E /* MemoryCache.swift */, - ); - path = Cache; + path = ViewModifiers; sourceTree = ""; }; F88C245F295C37B80006098B = { isa = PBXGroup; children = ( + F88BC55129E0798900CE6141 /* SharedAssets.xcassets */, + F88BC52B29E04AC200CE6141 /* EnvironmentKit */, + F88BC52829E0467400CE6141 /* WidgetsKit */, + F88BC52529E0421F00CE6141 /* ServicesKit */, F837269429A221420098D3C4 /* PixelfedKit */, + F88BC51929E0344000CE6141 /* ClientKit */, F88ABD9529687D4D004EF61E /* README.md */, F844F42429D2DC39000DD896 /* LICENSE */, F8B3699A29D86EB600BE3808 /* .swiftlint.yml */, F8B3699B29D86EBD00BE3808 /* .gitignore */, F8CB3DF029D80B1E00CDAE5A /* Resources */, F835081F29BEF88600DE3247 /* Localization */, - F864F79C29BB9D2400B13921 /* Models */, F8341F96295C6427009C8EE6 /* CoreData */, F88C246A295C37B80006098B /* Vernissage */, F864F76229BB91B400B13921 /* VernissageWidget */, + F88BC50329E02F3900CE6141 /* VernissageShare */, F88C2469295C37B80006098B /* Products */, F89992C5296D3DF8005994BF /* Frameworks */, ); @@ -812,6 +663,7 @@ children = ( F88C2468295C37B80006098B /* Vernissage.app */, F864F75D29BB91B400B13921 /* VernissageWidgetExtension.appex */, + F88BC50229E02F3900CE6141 /* VernissageShareExtension.appex */, ); name = Products; sourceTree = ""; @@ -821,17 +673,15 @@ children = ( F8F6E44429BC5CC50004795E /* Vernissage.entitlements */, F866F6A829604FFF002E8F88 /* Info.plist */, + F858906729E1CC2900D4BDED /* Extensions */, + F88BC53729E068D200CE6141 /* ViewModifiers */, F802884D297AEEAA000BDD51 /* Errors */, F86B721F296C498B00EE59EC /* Styles */, - F88ABD9029686F00004EF61E /* Cache */, - F897978B2968367E00B22335 /* Haptics */, F8210DE82966E4D8001D9973 /* Modifiers */, F88FAD30295F5010009B20C9 /* Services */, - F8C5E56029892C8A00ADF6A7 /* ViewModifiers */, F83901A2295D863B00456AE2 /* Widgets */, F8341F95295C640C009C8EE6 /* Models */, F8B9B354298D4B88009CC69C /* EnvironmentObjects */, - F8341F94295C63FE009C8EE6 /* Extensions */, F8341F93295C63E2009C8EE6 /* Views */, F88C246B295C37B80006098B /* VernissageApp.swift */, F8D5444229D4066C002225D6 /* AppDelegate.swift */, @@ -856,28 +706,15 @@ F88FAD30295F5010009B20C9 /* Services */ = { isa = PBXGroup; children = ( - F85E131F297409CD006A051D /* ErrorsService.swift */, - F8B1E6502973FB7E00EE0D10 /* ToastrService.swift */, - F88FAD31295F5029009B20C9 /* RemoteFileService.swift */, F85D4970296402DC00751DF7 /* AuthorizationService.swift */, F87AEB912986C44E00434FB6 /* AuthorizationSession.swift */, F85D4974296407F100751DF7 /* HomeTimelineService.swift */, - F886F256297859E300879356 /* CacheImageService.swift */, F88E4D49297EA0490057491A /* RouterPath.swift */, - F829193B2983012400367CE2 /* ImageSizeService.swift */, F878842129A4A4E3003CFAD2 /* AppMetadataService.swift */, ); path = Services; sourceTree = ""; }; - F897978B2968367E00B22335 /* Haptics */ = { - isa = PBXGroup; - children = ( - F897978C2968369600B22335 /* HapticService.swift */, - ); - path = Haptics; - sourceTree = ""; - }; F89992C5296D3DF8005994BF /* Frameworks */ = { isa = PBXGroup; children = ( @@ -918,37 +755,11 @@ F8B9B354298D4B88009CC69C /* EnvironmentObjects */ = { isa = PBXGroup; children = ( - F88FAD2C295F4AD7009B20C9 /* ApplicationState.swift */, - F8B9B344298D1FCB009CC69C /* Client.swift */, - F8B9B346298D4A7C009CC69C /* Client+Trends.swift */, - F89F57A929D1AE5D00001EE3 /* Client+Blocks.swift */, - F8B9B348298D4AA2009CC69C /* Client+Timeline.swift */, - F8B9B34A298D4ACE009CC69C /* Client+Tags.swift */, - F8B9B34C298D4AE4009CC69C /* Client+Notifications.swift */, - F8B9B34E298D4B14009CC69C /* Client+Statuses.swift */, - F8FA9916299F7DBD007AB130 /* Client+Media.swift */, - F89F57AB29D1AEBC00001EE3 /* Client+Mutes.swift */, - F8B9B350298D4B34009CC69C /* Client+Account.swift */, - F8B9B352298D4B5D009CC69C /* Client+Search.swift */, - F89AC00829A20C5C00F4159F /* Client+Places.swift */, - F805DCEE29DBED96006A1FD9 /* Client+Report.swift */, - F8B9B355298D4C1E009CC69C /* Client+Instance.swift */, F86A4302299A9AF500DF7645 /* TipsStore.swift */, ); path = EnvironmentObjects; sourceTree = ""; }; - F8C5E56029892C8A00ADF6A7 /* ViewModifiers */ = { - isa = PBXGroup; - children = ( - F8C5E56129892CC300ADF6A7 /* FirstAppear.swift */, - F8CAE63D29B8902D001E0372 /* ClearButton.swift */, - F8E9391E29C0BCFA002BB3B8 /* ImageContextMenu.swift */, - F8911A1629DE914D00770F44 /* NavigationMenu.swift */, - ); - path = ViewModifiers; - sourceTree = ""; - }; F8CB3DF029D80B1E00CDAE5A /* Resources */ = { isa = PBXGroup; children = ( @@ -974,15 +785,6 @@ path = Extensions; sourceTree = ""; }; - F8FA991A299FA8A5007AB130 /* ComposeView */ = { - isa = PBXGroup; - children = ( - F878842029A494E3003CFAD2 /* Subviews */, - F88ABD9329687CA4004EF61E /* ComposeView.swift */, - ); - path = ComposeView; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -1001,11 +803,35 @@ name = VernissageWidgetExtension; packageProductDependencies = ( F864F77929BB94A800B13921 /* PixelfedKit */, + F88BC52E29E04C5F00CE6141 /* EnvironmentKit */, ); productName = VernissageWidgetExtension; productReference = F864F75D29BB91B400B13921 /* VernissageWidgetExtension.appex */; productType = "com.apple.product-type.app-extension"; }; + F88BC50129E02F3900CE6141 /* VernissageShareExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = F88BC50F29E02F3900CE6141 /* Build configuration list for PBXNativeTarget "VernissageShareExtension" */; + buildPhases = ( + F88BC4FE29E02F3900CE6141 /* Sources */, + F88BC4FF29E02F3900CE6141 /* Frameworks */, + F88BC50029E02F3900CE6141 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = VernissageShareExtension; + packageProductDependencies = ( + F88BC51E29E03ED300CE6141 /* ClientKit */, + F88BC53129E0677000CE6141 /* EnvironmentKit */, + F88BC53C29E06EAD00CE6141 /* ServicesKit */, + F88BC53E29E06EB100CE6141 /* WidgetsKit */, + ); + productName = VernissageShareExtension; + productReference = F88BC50229E02F3900CE6141 /* VernissageShareExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; F88C2467295C37B80006098B /* Vernissage */ = { isa = PBXNativeTarget; buildConfigurationList = F88C247B295C37BB0006098B /* Build configuration list for PBXNativeTarget "Vernissage" */; @@ -1020,17 +846,19 @@ ); dependencies = ( F864F76B29BB91B600B13921 /* PBXTargetDependency */, + F88BC50B29E02F3900CE6141 /* PBXTargetDependency */, ); name = Vernissage; packageProductDependencies = ( F8210DD42966BB7E001D9973 /* Nuke */, F8210DD62966BB7E001D9973 /* NukeExtensions */, F8210DD82966BB7E001D9973 /* NukeUI */, - F8B1E64E2973F61400EE0D10 /* Drops */, - F85E132429741F05006A051D /* ActivityIndicatorView */, F88E4D4C297EA4290057491A /* EmojiText */, - F83E00EC29A2237C005D25A3 /* PixelfedKit */, F89B5CBF29D019B600549F2F /* HTMLString */, + F88BC51A29E0350300CE6141 /* ClientKit */, + F88BC52629E0431D00CE6141 /* ServicesKit */, + F88BC52929E046D700CE6141 /* WidgetsKit */, + F88BC52C29E04BB600CE6141 /* EnvironmentKit */, ); productName = Vernissage; productReference = F88C2468295C37B80006098B /* Vernissage.app */; @@ -1043,12 +871,15 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1420; + LastSwiftUpdateCheck = 1430; LastUpgradeCheck = 1420; TargetAttributes = { F864F75C29BB91B400B13921 = { CreatedOnToolsVersion = 14.2; }; + F88BC50129E02F3900CE6141 = { + CreatedOnToolsVersion = 14.3; + }; F88C2467295C37B80006098B = { CreatedOnToolsVersion = 14.2; }; @@ -1067,8 +898,6 @@ mainGroup = F88C245F295C37B80006098B; packageReferences = ( F8210DD32966BB7E001D9973 /* XCRemoteSwiftPackageReference "Nuke" */, - F8B1E64D2973F61400EE0D10 /* XCRemoteSwiftPackageReference "Drops" */, - F85E132329741F05006A051D /* XCRemoteSwiftPackageReference "ActivityIndicatorView" */, F88E4D4B297EA4290057491A /* XCRemoteSwiftPackageReference "EmojiText" */, F89B5CBE29D019B600549F2F /* XCRemoteSwiftPackageReference "HTMLString" */, ); @@ -1078,6 +907,7 @@ targets = ( F88C2467295C37B80006098B /* Vernissage */, F864F75C29BB91B400B13921 /* VernissageWidgetExtension */, + F88BC50129E02F3900CE6141 /* VernissageShareExtension */, ); }; /* End PBXProject section */ @@ -1092,10 +922,20 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + F88BC50029E02F3900CE6141 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F88BC53029E0672000CE6141 /* Localizable.strings in Resources */, + F88BC55429E0798900CE6141 /* SharedAssets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; F88C2466295C37B80006098B /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + F88BC55229E0798900CE6141 /* SharedAssets.xcassets in Resources */, F88C2473295C37BB0006098B /* Preview Assets.xcassets in Resources */, F835082329BEF9C400DE3247 /* Localizable.strings in Resources */, F88C2470295C37BB0006098B /* Assets.xcassets in Resources */, @@ -1134,21 +974,16 @@ F864F77829BB930000B13921 /* WidgetEntry.swift in Sources */, F864F77529BB92CE00B13921 /* Provider.swift in Sources */, F864F77629BB92CE00B13921 /* VernissageWidgetEntryView.swift in Sources */, - F864F79D29BB9D3400B13921 /* AppConstants.swift in Sources */, F864F77C29BB982100B13921 /* ImageFetcher.swift in Sources */, F8F6E44229BC58F20004795E /* Vernissage.xcdatamodeld in Sources */, F8F6E44C29BCC1F70004795E /* SmallWidgetView.swift in Sources */, F864F76629BB91B400B13921 /* VernissageWidget.swift in Sources */, F8F6E44D29BCC1F90004795E /* MediumWidgetView.swift in Sources */, - F864F79029BB9B3300B13921 /* TintColor.swift in Sources */, F8F6E44E29BCC1FB0004795E /* LargeWidgetView.swift in Sources */, F864F76429BB91B400B13921 /* VernissageWidgetBundle.swift in Sources */, - F864F78F29BB9B3100B13921 /* AvatarShape.swift in Sources */, - F864F78E29BB9B2F00B13921 /* Theme.swift in Sources */, F864F77D29BB9A4600B13921 /* AttachmentData+CoreDataClass.swift in Sources */, F864F7A629BBA01D00B13921 /* CoreDataError.swift in Sources */, F864F77E29BB9A4900B13921 /* AttachmentData+CoreDataProperties.swift in Sources */, - F8911A1B29DEA0F500770F44 /* MenuPosition.swift in Sources */, F864F78229BB9A6500B13921 /* StatusData+CoreDataClass.swift in Sources */, F864F78329BB9A6800B13921 /* StatusData+CoreDataProperties.swift in Sources */, F864F78429BB9A6E00B13921 /* ApplicationSettings+CoreDataClass.swift in Sources */, @@ -1164,6 +999,32 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + F88BC4FE29E02F3900CE6141 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F88BC54529E072B200CE6141 /* AccountDataHandler.swift in Sources */, + F88BC54729E072B800CE6141 /* AccountData+CoreDataProperties.swift in Sources */, + F88BC54D29E072D600CE6141 /* AttachmentData+CoreDataProperties.swift in Sources */, + F88BC54F29E073BC00CE6141 /* AccountData+AccountModel.swift in Sources */, + F88BC54629E072B500CE6141 /* CoreDataHandler.swift in Sources */, + F88BC50529E02F3900CE6141 /* ShareViewController.swift in Sources */, + F88BC54129E072A600CE6141 /* CoreDataError.swift in Sources */, + F88BC54229E072A900CE6141 /* AttachmentDataHandler.swift in Sources */, + F88BC54429E072AF00CE6141 /* ApplicationSettingsHandler.swift in Sources */, + F88BC51629E0307F00CE6141 /* NotificationsName.swift in Sources */, + F88BC54829E072BC00CE6141 /* AccountData+CoreDataClass.swift in Sources */, + F88BC51329E02FD800CE6141 /* ComposeView.swift in Sources */, + F88BC54E29E072D900CE6141 /* AttachmentData+CoreDataClass.swift in Sources */, + F88BC54C29E072CD00CE6141 /* StatusData+CoreDataClass.swift in Sources */, + F88BC54B29E072CA00CE6141 /* StatusData+CoreDataProperties.swift in Sources */, + F88BC54A29E072C400CE6141 /* ApplicationSettings+CoreDataClass.swift in Sources */, + F88BC54929E072C000CE6141 /* ApplicationSettings+CoreDataProperties.swift in Sources */, + F88BC55029E074EB00CE6141 /* Vernissage.xcdatamodeld in Sources */, + F88BC54329E072AC00CE6141 /* StatusDataHandler.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; F88C2464295C37B80006098B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1172,171 +1033,96 @@ F8210DDF2966CFC7001D9973 /* AttachmentData+Attachment.swift in Sources */, F88AB05529B3626300345EDE /* ImageGrid.swift in Sources */, F87AEB922986C44E00434FB6 /* AuthorizationSession.swift in Sources */, - F88E4D44297E82EB0057491A /* Status+MediaAttachmentType.swift in Sources */, - F89F57AC29D1AEBC00001EE3 /* Client+Mutes.swift in Sources */, F86A4301299A97F500DF7645 /* ProductIdentifiers.swift in Sources */, F89D6C4229717FDC001DA3D4 /* AccountsSectionView.swift in Sources */, F80048082961E6DE00E6868A /* StatusDataHandler.swift in Sources */, F866F6A0296040A8002E8F88 /* ApplicationSettings+CoreDataClass.swift in Sources */, - F8764189298ABEC80057D362 /* ErrorView.swift in Sources */, - F864F7A129BB9E8F00B13921 /* AvatarShape+Shape.swift in Sources */, F8210DEA2966E4F9001D9973 /* AnimatePlaceholderModifier.swift in Sources */, - F886F257297859E300879356 /* CacheImageService.swift in Sources */, F8B08862299435C9002AB40A /* SupportView.swift in Sources */, - F8984E4D296B648000A2610F /* UIImage+Blurhash.swift in Sources */, - F8CAE64029B8E6E1001E0372 /* UIApplication+Window.swift in Sources */, - F897978A2968314A00B22335 /* LoadingIndicator.swift in Sources */, - F8B9B351298D4B34009CC69C /* Client+Account.swift in Sources */, - F8210DE52966E160001D9973 /* Color+SystemColors.swift in Sources */, - F8CAE63E29B8902D001E0372 /* ClearButton.swift in Sources */, F8B05ACB29B489B100857221 /* HapticsSectionView.swift in Sources */, F88FAD2B295F43B8009B20C9 /* AccountData+CoreDataProperties.swift in Sources */, F85D4975296407F100751DF7 /* HomeTimelineService.swift in Sources */, F80048062961850500E6868A /* StatusData+CoreDataProperties.swift in Sources */, - F8864CF129ACFFB80020C534 /* View+Keyboard.swift in Sources */, F88FAD21295F3944009B20C9 /* HomeFeedView.swift in Sources */, - F8FA991E299FAB92007AB130 /* PhotoEditorView.swift in Sources */, - F8911A1729DE914D00770F44 /* NavigationMenu.swift in Sources */, F88C2475295C37BB0006098B /* CoreDataHandler.swift in Sources */, F87AEB972986D16D00434FB6 /* AuthorisationError.swift in Sources */, F8742FC429990AFB00E9642B /* ClientError.swift in Sources */, - F829193C2983012400367CE2 /* ImageSizeService.swift in Sources */, F883402029B62AE900C3E096 /* SearchView.swift in Sources */, - F8B9B345298D1FCB009CC69C /* Client.swift in Sources */, F88FAD2A295F43B8009B20C9 /* AccountData+CoreDataClass.swift in Sources */, F85DBF8F296732E20069BF89 /* AccountsView.swift in Sources */, - F85D49872964334100751DF7 /* String+Date.swift in Sources */, - F897978829681B9C00B22335 /* UserAvatar.swift in Sources */, F805DCF129DBEF83006A1FD9 /* ReportView.swift in Sources */, F8B0886029943498002AB40A /* OtherSectionView.swift in Sources */, F808641429756666009F035C /* NotificationRowView.swift in Sources */, F8210DDD2966CF17001D9973 /* StatusData+Status.swift in Sources */, F8210DCF2966B600001D9973 /* ImageRowAsync.swift in Sources */, F85D498329642FAC00751DF7 /* AttachmentData+Comperable.swift in Sources */, - F8B9B353298D4B5D009CC69C /* Client+Search.swift in Sources */, - F85D497B29640C8200751DF7 /* UsernameRow.swift in Sources */, F86A4305299AA12800DF7645 /* PurchaseError.swift in Sources */, F8B05ACE29B48E2F00857221 /* MediaSettingsView.swift in Sources */, F89D6C4429718092001DA3D4 /* AccentsSectionView.swift in Sources */, F88E4D42297E69FD0057491A /* StatusesView.swift in Sources */, - F8E9391F29C0BCFA002BB3B8 /* ImageContextMenu.swift in Sources */, - F86FB555298BF83F000131F0 /* FavouriteTouch.swift in Sources */, F878842229A4A4E3003CFAD2 /* AppMetadataService.swift in Sources */, F85D497929640B9D00751DF7 /* ImagesCarousel.swift in Sources */, - F8C5E55F2988E92600ADF6A7 /* AccountModel.swift in Sources */, - F89D6C3F29716E41001DA3D4 /* Theme.swift in Sources */, - F8864CE929ACAF820020C534 /* TextView.swift in Sources */, F89AC00529A1F9B500F4159F /* AppMetadata.swift in Sources */, - F8CC95CE2970761D00C9C2AC /* TintColor.swift in Sources */, - F89992CC296D9231005994BF /* StatusModel.swift in Sources */, F80048052961850500E6868A /* StatusData+CoreDataClass.swift in Sources */, F891E7CE29C35BF50022C449 /* ImageRowItem.swift in Sources */, F86B7221296C49A300EE59EC /* EmptyButtonStyle.swift in Sources */, F80048042961850500E6868A /* AttachmentData+CoreDataProperties.swift in Sources */, - F86B7223296C4BF500EE59EC /* ContentWarning.swift in Sources */, F88E4D4A297EA0490057491A /* RouterPath.swift in Sources */, - F83901A6295D8EC000456AE2 /* LabelIcon.swift in Sources */, - F8FA991C299FA8C2007AB130 /* ImageUploadView.swift in Sources */, - F8B1E6512973FB7E00EE0D10 /* ToastrService.swift in Sources */, - F8CEEDF829ABADDD00DBED66 /* UIImage+Size.swift in Sources */, F88E4D48297E90CD0057491A /* TrendStatusesView.swift in Sources */, - F89992CE296D92E7005994BF /* AttachmentModel.swift in Sources */, F800480A2961EA1900E6868A /* AttachmentDataHandler.swift in Sources */, F80048032961850500E6868A /* AttachmentData+CoreDataClass.swift in Sources */, F891E7D029C368750022C449 /* ImageRowItemAsync.swift in Sources */, - F897978D2968369600B22335 /* HapticService.swift in Sources */, - F8341F90295C636C009C8EE6 /* Data+Exif.swift in Sources */, F89D6C4A297196FF001DA3D4 /* ImageViewer.swift in Sources */, F8A93D7E2965FD89001D8331 /* UserProfileView.swift in Sources */, F88C246E295C37B80006098B /* MainView.swift in Sources */, - F864F7A329BB9EC700B13921 /* Theme+ColorScheme.swift in Sources */, - F89AC00729A208CC00F4159F /* PlaceSelectorView.swift in Sources */, F8AFF7C429B25EF40087D083 /* ImagesGrid.swift in Sources */, - F86B721E296C458700EE59EC /* BlurredImage.swift in Sources */, - F8B9B349298D4AA2009CC69C /* Client+Timeline.swift in Sources */, - F8FA9919299FA35A007AB130 /* PhotoAttachment.swift in Sources */, - F8B9B34B298D4ACE009CC69C /* Client+Tags.swift in Sources */, F88C2478295C37BB0006098B /* Vernissage.xcdatamodeld in Sources */, - F8AD061329A565620042F111 /* String+Random.swift in Sources */, F8AFF7C129B259150087D083 /* HashtagsView.swift in Sources */, - F898DE7229728CB2004B4A6A /* CommentModel.swift in Sources */, F8DF38E429DD68820047F1AA /* ViewOffsetKey.swift in Sources */, F89A46DE296EABA20062125F /* StatusPlaceholderView.swift in Sources */, F88C2482295C3A4F0006098B /* StatusView.swift in Sources */, F866F6A329604161002E8F88 /* AccountDataHandler.swift in Sources */, - F8911A1A29DEA0F500770F44 /* MenuPosition.swift in Sources */, - F8996DEB2971D29D0043EEC6 /* View+Transition.swift in Sources */, - F876418B298AC1B80057D362 /* NoDataView.swift in Sources */, - F8E9392129C0DA7E002BB3B8 /* LazyImageState+ImageResponse.swift in Sources */, F89D6C4629718193001DA3D4 /* GeneralSectionView.swift in Sources */, F85D497F296416C800751DF7 /* CommentsSectionView.swift in Sources */, F866F6A529604194002E8F88 /* ApplicationSettingsHandler.swift in Sources */, - F89AC00929A20C5C00F4159F /* Client+Places.swift in Sources */, - F88ABD9229686F1C004EF61E /* MemoryCache.swift in Sources */, - F857F9FD297D8ED3002C109C /* ActionMenu.swift in Sources */, F8B0885E29942E31002AB40A /* ThirdPartyView.swift in Sources */, F8E6D03329CDD52500416CCA /* EditProfileView.swift in Sources */, + F858906B29E1CC7A00D4BDED /* UIApplication+Window.swift in Sources */, F876418D298AE5020057D362 /* PaginableStatusesView.swift in Sources */, F85D49852964301800751DF7 /* StatusData+Attachments.swift in Sources */, - F8B9B34D298D4AE4009CC69C /* Client+Notifications.swift in Sources */, F8764187298ABB520057D362 /* ViewState.swift in Sources */, - F864F79F29BB9E6A00B13921 /* TintColor+Color.swift in Sources */, - F8210DE72966E1D1001D9973 /* Color+Assets.swift in Sources */, F88ABD9429687CA4004EF61E /* ComposeView.swift in Sources */, F89CEB802984198600A1376F /* AttachmentData+HighestImage.swift in Sources */, - F87AEB942986C51B00434FB6 /* AppConstants.swift in Sources */, F86B7214296BFDCE00EE59EC /* UserProfileHeaderView.swift in Sources */, F85D497D29640D5900751DF7 /* InteractionRow.swift in Sources */, F86167C6297FE6CC004D1F67 /* AvatarShapesSectionView.swift in Sources */, F866F6A729604629002E8F88 /* SignInView.swift in Sources */, - F8C14392296AF0B3001FE31D /* String+Exif.swift in Sources */, - F85E1320297409CD006A051D /* ErrorsService.swift in Sources */, F88C246C295C37B80006098B /* VernissageApp.swift in Sources */, F8121CA8298A86D600B466C7 /* InstanceRowView.swift in Sources */, - F873F14C29BDB67300DE72D1 /* UIImage+Rounded.swift in Sources */, - F8864CEF29ACE90B0020C534 /* UIFont+Font.swift in Sources */, - F8CEEDFA29ABAFD200DBED66 /* ImageFileTranseferable.swift in Sources */, F8D5444329D4066C002225D6 /* AppDelegate.swift in Sources */, F802884F297AEED5000BDD51 /* DatabaseError.swift in Sources */, F86A4307299AA5E900DF7645 /* ThanksView.swift in Sources */, + F88BC51D29E0377B00CE6141 /* AccountData+AccountModel.swift in Sources */, F89B5CC229D01BF700549F2F /* InstanceView.swift in Sources */, F89F57B029D1C11200001EE3 /* RelationshipModel.swift in Sources */, F88AB05829B36B8200345EDE /* AccountsPhotoView.swift in Sources */, F85D4971296402DC00751DF7 /* AuthorizationService.swift in Sources */, - F89F57AE29D1B82700001EE3 /* TagWidget.swift in Sources */, - F8B9B356298D4C1E009CC69C /* Client+Instance.swift in Sources */, F88AB05329B3613900345EDE /* PhotoUrl.swift in Sources */, F88E4D56297EAD6E0057491A /* AppRouteur.swift in Sources */, - F88FAD32295F5029009B20C9 /* RemoteFileService.swift in Sources */, - F805DCEF29DBED96006A1FD9 /* Client+Report.swift in Sources */, F88FAD27295F400E009B20C9 /* NotificationsView.swift in Sources */, F86B7216296BFFDA00EE59EC /* UserProfileStatusesView.swift in Sources */, F897978F29684BCB00B22335 /* LoadingView.swift in Sources */, - F8B9B34F298D4B14009CC69C /* Client+Statuses.swift in Sources */, F89992C9296D6DC7005994BF /* CommentBodyView.swift in Sources */, - F8B9B347298D4A7C009CC69C /* Client+Trends.swift in Sources */, - F89F57AA29D1AE5D00001EE3 /* Client+Blocks.swift in Sources */, - F88FAD2D295F4AD7009B20C9 /* ApplicationState.swift in Sources */, - F88E4D54297EA7EE0057491A /* MarkdownFormattedText.swift in Sources */, F866F6A1296040A8002E8F88 /* ApplicationSettings+CoreDataProperties.swift in Sources */, - F8FA9920299FDDC3007AB130 /* TextInputField.swift in Sources */, F86A4303299A9AF500DF7645 /* TipsStore.swift in Sources */, - F8C5E56229892CC300ADF6A7 /* FirstAppear.swift in Sources */, F8DF38E629DDB98A0047F1AA /* SocialsSectionView.swift in Sources */, + F88BC53B29E06A5100CE6141 /* ImageContextMenu.swift in Sources */, F864F7A529BBA01D00B13921 /* CoreDataError.swift in Sources */, - F8864CEB29ACBAA80020C534 /* TextModel.swift in Sources */, - F8C14394296AF21B001FE31D /* Double+Round.swift in Sources */, F83CBEFB298298A1002972C8 /* ImageCarouselPicture.swift in Sources */, F89A46DC296EAACE0062125F /* SettingsView.swift in Sources */, F866F6AE29606367002E8F88 /* ApplicationViewMode.swift in Sources */, F85D4DFE29B78C8400345267 /* HashtagModel.swift in Sources */, F866F6AA29605AFA002E8F88 /* SceneDelegate.swift in Sources */, - F86167C8297FE781004D1F67 /* AvatarShape.swift in Sources */, - F85D4973296406E700751DF7 /* BottomRight.swift in Sources */, - F8E6D03529CE161B00416CCA /* UIImage+Jpeg.swift in Sources */, - F898DE702972868A004B4A6A /* String+Empty.swift in Sources */, - F86B7218296C27C100EE59EC /* ActionButton.swift in Sources */, - F8FA9917299F7DBD007AB130 /* Client+Media.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1348,6 +1134,11 @@ target = F864F75C29BB91B400B13921 /* VernissageWidgetExtension */; targetProxy = F864F76A29BB91B600B13921 /* PBXContainerItemProxy */; }; + F88BC50B29E02F3900CE6141 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F88BC50129E02F3900CE6141 /* VernissageShareExtension */; + targetProxy = F88BC50A29E02F3900CE6141 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -1372,7 +1163,7 @@ CODE_SIGN_ENTITLEMENTS = VernissageWidget/VernissageWidgetExtension.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 96; + CURRENT_PROJECT_VERSION = 102; DEVELOPMENT_TEAM = B2U9FEKYP8; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = VernissageWidget/Info.plist; @@ -1383,7 +1174,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.2.0; PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage.widget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -1400,7 +1191,7 @@ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_ENTITLEMENTS = VernissageWidget/VernissageWidgetExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 96; + CURRENT_PROJECT_VERSION = 102; DEVELOPMENT_TEAM = B2U9FEKYP8; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = VernissageWidget/Info.plist; @@ -1411,7 +1202,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.2.0; PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage.widget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -1421,6 +1212,61 @@ }; name = Release; }; + F88BC50D29E02F3900CE6141 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = VernissageShare/VernissageShareExtension.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 102; + DEVELOPMENT_TEAM = B2U9FEKYP8; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = VernissageShare/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = VernissageShareExtension; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.2.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage.share; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 1; + }; + name = Debug; + }; + F88BC50E29E02F3900CE6141 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = VernissageShare/VernissageShareExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 102; + DEVELOPMENT_TEAM = B2U9FEKYP8; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = VernissageShare/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = VernissageShareExtension; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.2.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage.share; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 1; + }; + name = Release; + }; F88C2479295C37BB0006098B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1548,7 +1394,7 @@ CODE_SIGN_ENTITLEMENTS = Vernissage/Vernissage.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 96; + CURRENT_PROJECT_VERSION = 102; DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\""; DEVELOPMENT_TEAM = B2U9FEKYP8; ENABLE_PREVIEWS = YES; @@ -1565,7 +1411,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.2.0; PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1588,7 +1434,7 @@ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CODE_SIGN_ENTITLEMENTS = Vernissage/Vernissage.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 96; + CURRENT_PROJECT_VERSION = 102; DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\""; DEVELOPMENT_TEAM = B2U9FEKYP8; ENABLE_PREVIEWS = YES; @@ -1605,7 +1451,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.2.0; PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -1629,6 +1475,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + F88BC50F29E02F3900CE6141 /* Build configuration list for PBXNativeTarget "VernissageShareExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F88BC50D29E02F3900CE6141 /* Debug */, + F88BC50E29E02F3900CE6141 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; F88C2463295C37B80006098B /* Build configuration list for PBXProject "Vernissage" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -1658,14 +1513,6 @@ minimumVersion = 12.0.0; }; }; - F85E132329741F05006A051D /* XCRemoteSwiftPackageReference "ActivityIndicatorView" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/exyte/ActivityIndicatorView.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.0.0; - }; - }; F88E4D4B297EA4290057491A /* XCRemoteSwiftPackageReference "EmojiText" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/divadretlaw/EmojiText"; @@ -1682,14 +1529,6 @@ minimumVersion = 6.0.0; }; }; - F8B1E64D2973F61400EE0D10 /* XCRemoteSwiftPackageReference "Drops" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/omaralbeik/Drops"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.6.0; - }; - }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -1708,19 +1547,46 @@ package = F8210DD32966BB7E001D9973 /* XCRemoteSwiftPackageReference "Nuke" */; productName = NukeUI; }; - F83E00EC29A2237C005D25A3 /* PixelfedKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelfedKit; - }; - F85E132429741F05006A051D /* ActivityIndicatorView */ = { - isa = XCSwiftPackageProductDependency; - package = F85E132329741F05006A051D /* XCRemoteSwiftPackageReference "ActivityIndicatorView" */; - productName = ActivityIndicatorView; - }; F864F77929BB94A800B13921 /* PixelfedKit */ = { isa = XCSwiftPackageProductDependency; productName = PixelfedKit; }; + F88BC51A29E0350300CE6141 /* ClientKit */ = { + isa = XCSwiftPackageProductDependency; + productName = ClientKit; + }; + F88BC51E29E03ED300CE6141 /* ClientKit */ = { + isa = XCSwiftPackageProductDependency; + productName = ClientKit; + }; + F88BC52629E0431D00CE6141 /* ServicesKit */ = { + isa = XCSwiftPackageProductDependency; + productName = ServicesKit; + }; + F88BC52929E046D700CE6141 /* WidgetsKit */ = { + isa = XCSwiftPackageProductDependency; + productName = WidgetsKit; + }; + F88BC52C29E04BB600CE6141 /* EnvironmentKit */ = { + isa = XCSwiftPackageProductDependency; + productName = EnvironmentKit; + }; + F88BC52E29E04C5F00CE6141 /* EnvironmentKit */ = { + isa = XCSwiftPackageProductDependency; + productName = EnvironmentKit; + }; + F88BC53129E0677000CE6141 /* EnvironmentKit */ = { + isa = XCSwiftPackageProductDependency; + productName = EnvironmentKit; + }; + F88BC53C29E06EAD00CE6141 /* ServicesKit */ = { + isa = XCSwiftPackageProductDependency; + productName = ServicesKit; + }; + F88BC53E29E06EB100CE6141 /* WidgetsKit */ = { + isa = XCSwiftPackageProductDependency; + productName = WidgetsKit; + }; F88E4D4C297EA4290057491A /* EmojiText */ = { isa = XCSwiftPackageProductDependency; package = F88E4D4B297EA4290057491A /* XCRemoteSwiftPackageReference "EmojiText" */; @@ -1731,11 +1597,6 @@ package = F89B5CBE29D019B600549F2F /* XCRemoteSwiftPackageReference "HTMLString" */; productName = HTMLString; }; - F8B1E64E2973F61400EE0D10 /* Drops */ = { - isa = XCSwiftPackageProductDependency; - package = F8B1E64D2973F61400EE0D10 /* XCRemoteSwiftPackageReference "Drops" */; - productName = Drops; - }; /* End XCSwiftPackageProductDependency section */ /* Begin XCVersionGroup section */ diff --git a/Vernissage/AppRouteur.swift b/Vernissage/AppRouteur.swift index 4b94a65..5af7764 100644 --- a/Vernissage/AppRouteur.swift +++ b/Vernissage/AppRouteur.swift @@ -6,6 +6,7 @@ import Foundation import SwiftUI +import WidgetsKit extension View { diff --git a/Vernissage/Assets.xcassets/DangerColor.colorset/Contents.json b/Vernissage/Assets.xcassets/DangerColor.colorset/Contents.json deleted file mode 100644 index db2b413..0000000 --- a/Vernissage/Assets.xcassets/DangerColor.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "68", - "green" : "87", - "red" : "255" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "68", - "green" : "87", - "red" : "255" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Vernissage/Assets.xcassets/ViewBackgroundColor.colorset/Contents.json b/Vernissage/Assets.xcassets/ViewBackgroundColor.colorset/Contents.json deleted file mode 100644 index b2a4183..0000000 --- a/Vernissage/Assets.xcassets/ViewBackgroundColor.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "40", - "green" : "40", - "red" : "40" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "247", - "green" : "247", - "red" : "247" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Vernissage/Assets.xcassets/lightGrayColor.colorset/Contents.json b/Vernissage/Assets.xcassets/lightGrayColor.colorset/Contents.json deleted file mode 100644 index f07e8ce..0000000 --- a/Vernissage/Assets.xcassets/lightGrayColor.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "160", - "green" : "160", - "red" : "160" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "160", - "green" : "160", - "red" : "160" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Vernissage/Assets.xcassets/mainTextColor.colorset/Contents.json b/Vernissage/Assets.xcassets/mainTextColor.colorset/Contents.json deleted file mode 100644 index 7445000..0000000 --- a/Vernissage/Assets.xcassets/mainTextColor.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "10", - "green" : "10", - "red" : "10" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "245", - "green" : "245", - "red" : "245" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Vernissage/EnvironmentObjects/TipsStore.swift b/Vernissage/EnvironmentObjects/TipsStore.swift index b3a6b1f..190a4c2 100644 --- a/Vernissage/EnvironmentObjects/TipsStore.swift +++ b/Vernissage/EnvironmentObjects/TipsStore.swift @@ -6,6 +6,7 @@ import Foundation import StoreKit +import ServicesKit @MainActor final class TipsStore: ObservableObject { diff --git a/Vernissage/Models/AccountModel.swift b/Vernissage/Models/AccountModel.swift deleted file mode 100644 index 674e235..0000000 --- a/Vernissage/Models/AccountModel.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// https://mczachurski.dev -// Copyright © 2023 Marcin Czachurski and the repository contributors. -// Licensed under the Apache License 2.0. -// - -import Foundation - -public class AccountModel: ObservableObject, Identifiable { - public let id: String - public let accessToken: String? - public let refreshToken: String? - public let acct: String - public let avatar: URL? - public let clientId: String - public let clientSecret: String - public let clientVapidKey: String - public let createdAt: String - public let displayName: String? - public let followersCount: Int32 - public let followingCount: Int32 - public let header: URL? - public let locked: Bool - public let note: String? - public let serverUrl: URL - public let statusesCount: Int32 - public let url: URL? - public let username: String - public let lastSeenStatusId: String? - - @Published public var avatarData: Data? - - init(accountData: AccountData) { - self.accessToken = accountData.accessToken - self.refreshToken = accountData.refreshToken - self.acct = accountData.acct - self.avatar = accountData.avatar - self.avatarData = accountData.avatarData - self.clientId = accountData.clientId - self.clientSecret = accountData.clientSecret - self.clientVapidKey = accountData.clientVapidKey - self.createdAt = accountData.createdAt - self.displayName = accountData.displayName - self.followersCount = accountData.followersCount - self.followingCount = accountData.followingCount - self.header = accountData.header - self.id = accountData.id - self.locked = accountData.locked - self.note = accountData.note - self.serverUrl = accountData.serverUrl - self.statusesCount = accountData.statusesCount - self.url = accountData.url - self.username = accountData.username - self.lastSeenStatusId = accountData.lastSeenStatusId - } -} - -extension AccountModel: Equatable { - public static func == (lhs: AccountModel, rhs: AccountModel) -> Bool { - lhs.id == rhs.id - } -} diff --git a/Vernissage/Models/ApplicationViewMode.swift b/Vernissage/Models/ApplicationViewMode.swift index ebafa8b..469ff9b 100644 --- a/Vernissage/Models/ApplicationViewMode.swift +++ b/Vernissage/Models/ApplicationViewMode.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // diff --git a/Vernissage/Models/PhotoAttachment.swift b/Vernissage/Models/PhotoAttachment.swift deleted file mode 100644 index 380a23d..0000000 --- a/Vernissage/Models/PhotoAttachment.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// https://mczachurski.dev -// Copyright © 2023 Marcin Czachurski and the repository contributors. -// Licensed under the Apache License 2.0. -// - -import Foundation -import PhotosUI -import SwiftUI -import PixelfedKit - -public class PhotoAttachment: ObservableObject, Identifiable, Equatable, Hashable { - public let id: String - public let photosPickerItem: PhotosPickerItem - - @Published public var photoData: Data? - @Published public var uploadedAttachment: UploadedAttachment? - @Published public var error: Error? - - init(photosPickerItem: PhotosPickerItem) { - self.id = UUID().uuidString - self.photosPickerItem = photosPickerItem - } - - public static func == (lhs: PhotoAttachment, rhs: PhotoAttachment) -> Bool { - lhs.id == rhs.id - } - - public func hash(into hasher: inout Hasher) { - return hasher.combine(self.id) - } -} - -extension [PhotoAttachment] { - public func hasUploadedPhotos() -> Bool { - return self.contains { photoAttachment in - photoAttachment.uploadedAttachment != nil - } - } - - public func getUploadedPhotoIds() -> [String] { - var ids: [String] = [] - - for item in self { - if let uploadedAttachment = item.uploadedAttachment { - ids.append(uploadedAttachment.id) - } - } - - return ids - } -} diff --git a/Vernissage/SceneDelegate.swift b/Vernissage/SceneDelegate.swift index c8684d8..d933456 100644 --- a/Vernissage/SceneDelegate.swift +++ b/Vernissage/SceneDelegate.swift @@ -1,12 +1,13 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // import SwiftUI import PixelfedKit import OAuthSwift +import EnvironmentKit class SceneDelegate: NSObject, UISceneDelegate { func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { diff --git a/Vernissage/Services/AppMetadataService.swift b/Vernissage/Services/AppMetadataService.swift index 22fefb1..be86079 100644 --- a/Vernissage/Services/AppMetadataService.swift +++ b/Vernissage/Services/AppMetadataService.swift @@ -6,6 +6,7 @@ import Foundation import PixelfedKit +import ServicesKit public class AppMetadataService { public static let shared = AppMetadataService() diff --git a/Vernissage/Services/AuthorizationService.swift b/Vernissage/Services/AuthorizationService.swift index b1fca67..2b2bb92 100644 --- a/Vernissage/Services/AuthorizationService.swift +++ b/Vernissage/Services/AuthorizationService.swift @@ -6,8 +6,11 @@ import Foundation import PixelfedKit +import ClientKit import CoreData import AuthenticationServices +import ServicesKit +import EnvironmentKit /// Srvice responsible for login user into the Pixelfed account. public class AuthorizationService { @@ -123,7 +126,7 @@ public class AuthorizationService { CoreDataHandler.shared.save(viewContext: backgroundContext) // Return account data. - let accountModel = AccountModel(accountData: accountData) + let accountModel = accountData.toAccountModel() result(accountModel) } @@ -243,7 +246,7 @@ public class AuthorizationService { // Save account data in database and in application state. CoreDataHandler.shared.save(viewContext: backgroundContext) - return AccountModel(accountData: dbAccount) + return dbAccount.toAccountModel() } private func getAccountData(account: Account, backgroundContext: NSManagedObjectContext) -> AccountData { diff --git a/Vernissage/Services/HomeTimelineService.swift b/Vernissage/Services/HomeTimelineService.swift index 2926537..9b3d5c5 100644 --- a/Vernissage/Services/HomeTimelineService.swift +++ b/Vernissage/Services/HomeTimelineService.swift @@ -7,6 +7,8 @@ import Foundation import CoreData import PixelfedKit +import ClientKit +import ServicesKit /// Service responsible for managing home timeline. public class HomeTimelineService { diff --git a/Vernissage/Services/RouterPath.swift b/Vernissage/Services/RouterPath.swift index 36ffb75..728bd56 100644 --- a/Vernissage/Services/RouterPath.swift +++ b/Vernissage/Services/RouterPath.swift @@ -7,6 +7,8 @@ import SwiftUI import Foundation import PixelfedKit +import ClientKit +import WidgetsKit enum RouteurDestinations: Hashable { case tag(hashTag: String) diff --git a/Vernissage/VernissageApp.swift b/Vernissage/VernissageApp.swift index 4d49681..a7c5606 100644 --- a/Vernissage/VernissageApp.swift +++ b/Vernissage/VernissageApp.swift @@ -1,12 +1,14 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // import SwiftUI import Nuke import NukeUI +import ClientKit +import EnvironmentKit @main struct VernissageApp: App { @@ -112,7 +114,7 @@ struct VernissageApp: App { } // Create model based on core data entity. - let accountModel = AccountModel(accountData: currentAccount) + let accountModel = currentAccount.toAccountModel() // Verify access token correctness. let authorizationSession = AuthorizationSession() @@ -149,35 +151,10 @@ struct VernissageApp: App { } private func loadUserPreferences() { - let defaultSettings = ApplicationSettingsHandler.shared.get() + ApplicationSettingsHandler.shared.update(applicationState: self.applicationState) - if let tintColor = TintColor(rawValue: Int(defaultSettings.tintColor)) { - self.applicationState.tintColor = tintColor - self.tintColor = tintColor.color() - } - - if let theme = Theme(rawValue: Int(defaultSettings.theme)) { - self.applicationState.theme = theme - self.theme = theme.colorScheme() - } - - if let avatarShape = AvatarShape(rawValue: Int(defaultSettings.avatarShape)) { - self.applicationState.avatarShape = avatarShape - } - - self.applicationState.activeIcon = defaultSettings.activeIcon - self.applicationState.showSensitive = defaultSettings.showSensitive - self.applicationState.showPhotoDescription = defaultSettings.showPhotoDescription - - if let menuPosition = MenuPosition(rawValue: Int(defaultSettings.menuPosition)) { - self.applicationState.menuPosition = menuPosition - } - - self.applicationState.hapticTabSelectionEnabled = defaultSettings.hapticTabSelectionEnabled - self.applicationState.hapticRefreshEnabled = defaultSettings.hapticRefreshEnabled - self.applicationState.hapticButtonPressEnabled = defaultSettings.hapticButtonPressEnabled - self.applicationState.hapticAnimationEnabled = defaultSettings.hapticAnimationEnabled - self.applicationState.hapticNotificationEnabled = defaultSettings.hapticNotificationEnabled + self.tintColor = self.applicationState.tintColor.color() + self.theme = self.applicationState.theme.colorScheme() } private func setImagePipelines() { diff --git a/Vernissage/ViewModifiers/ImageContextMenu.swift b/Vernissage/ViewModifiers/ImageContextMenu.swift index 50eeaad..413a7d8 100644 --- a/Vernissage/ViewModifiers/ImageContextMenu.swift +++ b/Vernissage/ViewModifiers/ImageContextMenu.swift @@ -6,6 +6,8 @@ import Foundation import SwiftUI +import ClientKit +import ServicesKit public extension View { func imageContextMenu(client: Client, statusModel: StatusModel) -> some View { diff --git a/Vernissage/Views/AccountsPhotoView.swift b/Vernissage/Views/AccountsPhotoView.swift index c01294f..d22c05e 100644 --- a/Vernissage/Views/AccountsPhotoView.swift +++ b/Vernissage/Views/AccountsPhotoView.swift @@ -6,7 +6,11 @@ import SwiftUI import PixelfedKit +import ClientKit import Foundation +import ServicesKit +import EnvironmentKit +import WidgetsKit struct AccountsPhotoView: View { public enum ListType: Hashable { diff --git a/Vernissage/Views/AccountsView.swift b/Vernissage/Views/AccountsView.swift index 317fd47..342d26f 100644 --- a/Vernissage/Views/AccountsView.swift +++ b/Vernissage/Views/AccountsView.swift @@ -6,7 +6,11 @@ import SwiftUI import PixelfedKit +import ClientKit import Foundation +import ServicesKit +import EnvironmentKit +import WidgetsKit struct AccountsView: View { public enum ListType: Hashable { diff --git a/Vernissage/Views/ComposeView/ComposeView.swift b/Vernissage/Views/ComposeView.swift similarity index 95% rename from Vernissage/Views/ComposeView/ComposeView.swift rename to Vernissage/Views/ComposeView.swift index 8beaf02..b7d65c6 100644 --- a/Vernissage/Views/ComposeView/ComposeView.swift +++ b/Vernissage/Views/ComposeView.swift @@ -7,7 +7,11 @@ import SwiftUI import PhotosUI import PixelfedKit +import ClientKit import UIKit +import ServicesKit +import EnvironmentKit +import WidgetsKit struct ComposeView: View { @EnvironmentObject var applicationState: ApplicationState @@ -98,7 +102,7 @@ struct ComposeView: View { ToolbarItem(placement: .cancellationAction) { Button(NSLocalizedString("compose.title.cancel", comment: "Cancel"), role: .cancel) { - dismiss() + self.close() } } } @@ -152,7 +156,7 @@ struct ComposeView: View { // User avatar and name. self.userAvatarView() - // Incofmation about status visibility. + // Information about status visibility. self.visibilityComboView() // Text area with new status. @@ -513,9 +517,7 @@ struct ComposeView: View { // Now we have to get from photos images as JPEG. for item in self.photosAttachment.filter({ $0.photoData == nil }) { - if let data = try await item.photosPickerItem.loadTransferable(type: Data.self) { - item.photoData = data - } + try await item.loadImage() } // Open again the keyboard. @@ -546,16 +548,20 @@ struct ComposeView: View { private func upload(_ photoAttachment: PhotoAttachment) async { do { - // We have to have binary data and image shouldn't be uploaded yet. - guard let photoData = photoAttachment.photoData, photoAttachment.uploadedAttachment == nil else { + // Image shouldn't be uploaded yet. + guard photoAttachment.uploadedAttachment == nil else { return } - guard let image = UIImage(data: photoData) else { + // We are sending orginal file (not file compressed from memory). + guard let imageFileTranseferable = photoAttachment.imageFileTranseferable, + let data = try? Data(contentsOf: imageFileTranseferable.url), + let uiImage = UIImage(data: data) else { return } - guard let data = image.getJpegData() else { + // Compresing to JPEG with extendedRGB color space. + guard let data = uiImage.getJpegData() else { return } @@ -571,6 +577,14 @@ struct ComposeView: View { } } + private func close() { + // Clean tmp folder from file transferred from Photos. + self.photosAttachment.removeTmpFiles() + + // Close the view. + dismiss() + } + private func publishStatus() async { do { let status = self.createStatus() @@ -581,7 +595,7 @@ struct ComposeView: View { let commentModel = CommentModel(status: statusModel, showDivider: false) self.applicationState.newComment = commentModel - dismiss() + self.close() } } catch { ErrorService.shared.handle(error, message: "compose.error.postingStatusFailed", showToastr: true) diff --git a/Vernissage/Views/EditProfileView.swift b/Vernissage/Views/EditProfileView.swift index 7199c6b..120f3d4 100644 --- a/Vernissage/Views/EditProfileView.swift +++ b/Vernissage/Views/EditProfileView.swift @@ -7,7 +7,11 @@ import PhotosUI import SwiftUI import PixelfedKit +import ClientKit import HTMLString +import ServicesKit +import WidgetsKit +import EnvironmentKit struct EditProfileView: View { @EnvironmentObject private var applicationState: ApplicationState diff --git a/Vernissage/Views/HashtagsView.swift b/Vernissage/Views/HashtagsView.swift index 41b4782..fdf71f5 100644 --- a/Vernissage/Views/HashtagsView.swift +++ b/Vernissage/Views/HashtagsView.swift @@ -6,7 +6,11 @@ import SwiftUI import PixelfedKit +import ClientKit import Foundation +import ServicesKit +import EnvironmentKit +import WidgetsKit struct HashtagsView: View { public enum ListType: Hashable { diff --git a/Vernissage/Views/HomeFeedView.swift b/Vernissage/Views/HomeFeedView.swift index 150a509..0bb63d2 100644 --- a/Vernissage/Views/HomeFeedView.swift +++ b/Vernissage/Views/HomeFeedView.swift @@ -1,10 +1,13 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // import SwiftUI +import ServicesKit +import EnvironmentKit +import WidgetsKit struct HomeFeedView: View { @Environment(\.managedObjectContext) private var viewContext diff --git a/Vernissage/Views/InstanceView.swift b/Vernissage/Views/InstanceView.swift index 32f5e53..5100e61 100644 --- a/Vernissage/Views/InstanceView.swift +++ b/Vernissage/Views/InstanceView.swift @@ -7,6 +7,10 @@ import SwiftUI import Foundation import PixelfedKit +import ClientKit +import ServicesKit +import EnvironmentKit +import WidgetsKit struct InstanceView: View { @EnvironmentObject private var applicationState: ApplicationState diff --git a/Vernissage/Views/MainView.swift b/Vernissage/Views/MainView.swift index 2412349..230e914 100644 --- a/Vernissage/Views/MainView.swift +++ b/Vernissage/Views/MainView.swift @@ -1,6 +1,6 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // @@ -8,6 +8,9 @@ import SwiftUI import UIKit import CoreData import PixelfedKit +import ClientKit +import ServicesKit +import EnvironmentKit struct MainView: View { @Environment(\.managedObjectContext) private var viewContext @@ -335,7 +338,7 @@ struct MainView: View { Task { // Verify access token correctness. let authorizationSession = AuthorizationSession() - let accountModel = AccountModel(accountData: account) + let accountModel = account.toAccountModel() await AuthorizationService.shared.verifyAccount(session: authorizationSession, accountModel: accountModel) { signedInAccountModel in guard let signedInAccountModel else { diff --git a/Vernissage/Views/NotificationsView/NotificationsView.swift b/Vernissage/Views/NotificationsView/NotificationsView.swift index 0727db8..602dade 100644 --- a/Vernissage/Views/NotificationsView/NotificationsView.swift +++ b/Vernissage/Views/NotificationsView/NotificationsView.swift @@ -6,6 +6,10 @@ import SwiftUI import PixelfedKit +import ClientKit +import ServicesKit +import EnvironmentKit +import WidgetsKit struct NotificationsView: View { @EnvironmentObject var applicationState: ApplicationState diff --git a/Vernissage/Views/NotificationsView/Subviews/NotificationRowView.swift b/Vernissage/Views/NotificationsView/Subviews/NotificationRowView.swift index 1342fde..d9ed5f4 100644 --- a/Vernissage/Views/NotificationsView/Subviews/NotificationRowView.swift +++ b/Vernissage/Views/NotificationsView/Subviews/NotificationRowView.swift @@ -6,7 +6,11 @@ import SwiftUI import PixelfedKit +import ClientKit import NukeUI +import ServicesKit +import EnvironmentKit +import WidgetsKit struct NotificationRowView: View { @EnvironmentObject var applicationState: ApplicationState @@ -52,9 +56,11 @@ struct NotificationRowView: View { Spacer() - Text(self.notification.createdAt.toRelative(.isoDateTimeMilliSec)) - .foregroundColor(.lightGrayColor) - .font(.footnote) + if let createdAt = self.notification.createdAt.toDate(.isoDateTimeMilliSec) { + RelativeTime(date: createdAt) + .foregroundColor(.lightGrayColor) + .font(.footnote) + } } Text(self.getTitle(), comment: "Notification type") diff --git a/Vernissage/Views/PaginableStatusesView.swift b/Vernissage/Views/PaginableStatusesView.swift index 0e43c81..4b99925 100644 --- a/Vernissage/Views/PaginableStatusesView.swift +++ b/Vernissage/Views/PaginableStatusesView.swift @@ -1,11 +1,15 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // import SwiftUI import PixelfedKit +import ClientKit +import ServicesKit +import EnvironmentKit +import WidgetsKit struct PaginableStatusesView: View { public enum ListType: Hashable { diff --git a/Vernissage/Views/ReportView.swift b/Vernissage/Views/ReportView.swift index 578fe2d..24be6dc 100644 --- a/Vernissage/Views/ReportView.swift +++ b/Vernissage/Views/ReportView.swift @@ -6,6 +6,9 @@ import SwiftUI import PixelfedKit +import ClientKit +import ServicesKit +import WidgetsKit struct ReportView: View { @EnvironmentObject private var client: Client diff --git a/Vernissage/Views/SettingsView/SettingsView.swift b/Vernissage/Views/SettingsView/SettingsView.swift index bf251fb..99a1007 100644 --- a/Vernissage/Views/SettingsView/SettingsView.swift +++ b/Vernissage/Views/SettingsView/SettingsView.swift @@ -5,6 +5,7 @@ // import SwiftUI +import EnvironmentKit struct SettingsView: View { @EnvironmentObject var applicationState: ApplicationState diff --git a/Vernissage/Views/SettingsView/Subviews/AccentsSectionView.swift b/Vernissage/Views/SettingsView/Subviews/AccentsSectionView.swift index 2155ef5..21df0b9 100644 --- a/Vernissage/Views/SettingsView/Subviews/AccentsSectionView.swift +++ b/Vernissage/Views/SettingsView/Subviews/AccentsSectionView.swift @@ -5,6 +5,7 @@ // import SwiftUI +import EnvironmentKit struct AccentsSectionView: View { @EnvironmentObject var applicationState: ApplicationState diff --git a/Vernissage/Views/SettingsView/Subviews/AccountsSectionView.swift b/Vernissage/Views/SettingsView/Subviews/AccountsSectionView.swift index be05b0a..0ba9cf2 100644 --- a/Vernissage/Views/SettingsView/Subviews/AccountsSectionView.swift +++ b/Vernissage/Views/SettingsView/Subviews/AccountsSectionView.swift @@ -5,6 +5,9 @@ // import SwiftUI +import ClientKit +import EnvironmentKit +import WidgetsKit struct AccountsSectionView: View { @EnvironmentObject var applicationState: ApplicationState @@ -41,7 +44,7 @@ struct AccountsSectionView: View { } .onAppear { self.dbAccounts = AccountDataHandler.shared.getAccountsData() - self.accounts = self.dbAccounts.map({ AccountModel(accountData: $0) }) + self.accounts = self.dbAccounts.map({ $0.toAccountModel() }) } } diff --git a/Vernissage/Views/SettingsView/Subviews/AvatarShapesSectionView.swift b/Vernissage/Views/SettingsView/Subviews/AvatarShapesSectionView.swift index ee9bf00..1257f85 100644 --- a/Vernissage/Views/SettingsView/Subviews/AvatarShapesSectionView.swift +++ b/Vernissage/Views/SettingsView/Subviews/AvatarShapesSectionView.swift @@ -5,6 +5,7 @@ // import SwiftUI +import EnvironmentKit struct AvatarShapesSectionView: View { @EnvironmentObject var applicationState: ApplicationState diff --git a/Vernissage/Views/SettingsView/Subviews/GeneralSectionView.swift b/Vernissage/Views/SettingsView/Subviews/GeneralSectionView.swift index e962294..1b0d61c 100644 --- a/Vernissage/Views/SettingsView/Subviews/GeneralSectionView.swift +++ b/Vernissage/Views/SettingsView/Subviews/GeneralSectionView.swift @@ -5,6 +5,7 @@ // import SwiftUI +import EnvironmentKit struct GeneralSectionView: View { @EnvironmentObject var applicationState: ApplicationState diff --git a/Vernissage/Views/SettingsView/Subviews/HapticsSectionView.swift b/Vernissage/Views/SettingsView/Subviews/HapticsSectionView.swift index d9610bb..82baeef 100644 --- a/Vernissage/Views/SettingsView/Subviews/HapticsSectionView.swift +++ b/Vernissage/Views/SettingsView/Subviews/HapticsSectionView.swift @@ -5,6 +5,7 @@ // import SwiftUI +import EnvironmentKit struct HapticsSectionView: View { @EnvironmentObject var applicationState: ApplicationState diff --git a/Vernissage/Views/SettingsView/Subviews/MediaSettingsView.swift b/Vernissage/Views/SettingsView/Subviews/MediaSettingsView.swift index 5a23b29..d45d894 100644 --- a/Vernissage/Views/SettingsView/Subviews/MediaSettingsView.swift +++ b/Vernissage/Views/SettingsView/Subviews/MediaSettingsView.swift @@ -5,6 +5,7 @@ // import SwiftUI +import EnvironmentKit struct MediaSettingsView: View { @EnvironmentObject var applicationState: ApplicationState diff --git a/Vernissage/Views/SettingsView/Subviews/SupportView.swift b/Vernissage/Views/SettingsView/Subviews/SupportView.swift index be5f301..969684d 100644 --- a/Vernissage/Views/SettingsView/Subviews/SupportView.swift +++ b/Vernissage/Views/SettingsView/Subviews/SupportView.swift @@ -6,6 +6,7 @@ import SwiftUI import StoreKit +import ServicesKit struct SupportView: View { @EnvironmentObject var tipsStore: TipsStore diff --git a/Vernissage/Views/SettingsView/Subviews/ThanksView.swift b/Vernissage/Views/SettingsView/Subviews/ThanksView.swift index 89d7613..523e9ab 100644 --- a/Vernissage/Views/SettingsView/Subviews/ThanksView.swift +++ b/Vernissage/Views/SettingsView/Subviews/ThanksView.swift @@ -5,6 +5,7 @@ // import SwiftUI +import ServicesKit struct ThanksView: View { @EnvironmentObject var routerPath: RouterPath diff --git a/Vernissage/Views/SignInView/SignInView.swift b/Vernissage/Views/SignInView/SignInView.swift index 89cf647..82a2253 100644 --- a/Vernissage/Views/SignInView/SignInView.swift +++ b/Vernissage/Views/SignInView/SignInView.swift @@ -1,12 +1,16 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // import SwiftUI import PixelfedKit +import ClientKit import AuthenticationServices +import ServicesKit +import EnvironmentKit +import WidgetsKit struct SignInView: View { @Environment(\.managedObjectContext) private var viewContext diff --git a/Vernissage/Views/SignInView/Subviews/InstanceRowView.swift b/Vernissage/Views/SignInView/Subviews/InstanceRowView.swift index 895644b..76f941b 100644 --- a/Vernissage/Views/SignInView/Subviews/InstanceRowView.swift +++ b/Vernissage/Views/SignInView/Subviews/InstanceRowView.swift @@ -7,6 +7,8 @@ import SwiftUI import PixelfedKit import NukeUI +import ServicesKit +import WidgetsKit struct InstanceRowView: View { @EnvironmentObject var routerPath: RouterPath diff --git a/Vernissage/Views/StatusView/StatusView.swift b/Vernissage/Views/StatusView/StatusView.swift index f649dd5..4bea120 100644 --- a/Vernissage/Views/StatusView/StatusView.swift +++ b/Vernissage/Views/StatusView/StatusView.swift @@ -1,12 +1,16 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // import SwiftUI import PixelfedKit +import ClientKit import AVFoundation +import ServicesKit +import WidgetsKit +import EnvironmentKit struct StatusView: View { struct TappedAttachment: Identifiable { @@ -134,8 +138,15 @@ struct StatusView: View { HStack { Text("status.title.uploaded", comment: "Uploaded") - Text(statusViewModel.createdAt.toRelative(.isoDateTimeMilliSec)) - .padding(.horizontal, -4) + + if let createdAt = statusViewModel.createdAt.toDate(.isoDateTimeMilliSec) { + RelativeTime(date: createdAt) + .padding(.horizontal, -4) + } else { + Text(statusViewModel.createdAt.toRelative(.isoDateTimeMilliSec)) + .padding(.horizontal, -4) + } + if let applicationName = statusViewModel.application?.name { Text(String(format: NSLocalizedString("status.title.via", comment: "via"), applicationName)) } diff --git a/Vernissage/Views/StatusView/Subviews/CommentBodyView.swift b/Vernissage/Views/StatusView/Subviews/CommentBodyView.swift index f827343..e4b88de 100644 --- a/Vernissage/Views/StatusView/Subviews/CommentBodyView.swift +++ b/Vernissage/Views/StatusView/Subviews/CommentBodyView.swift @@ -6,6 +6,9 @@ import SwiftUI import PixelfedKit +import ClientKit +import EnvironmentKit +import WidgetsKit struct CommentBodyView: View { @EnvironmentObject var applicationState: ApplicationState @@ -31,9 +34,11 @@ struct CommentBodyView: View { Spacer() - Text(self.statusViewModel.createdAt.toRelative(.isoDateTimeMilliSec)) - .foregroundColor(.lightGrayColor) - .font(.footnote) + if let createdAt = self.statusViewModel.createdAt.toDate(.isoDateTimeMilliSec) { + RelativeTime(date: createdAt) + .foregroundColor(.lightGrayColor) + .font(.footnote) + } } MarkdownFormattedText(self.statusViewModel.content.asMarkdown) diff --git a/Vernissage/Views/StatusView/Subviews/CommentsSectionView.swift b/Vernissage/Views/StatusView/Subviews/CommentsSectionView.swift index e3e7587..fa3f9b6 100644 --- a/Vernissage/Views/StatusView/Subviews/CommentsSectionView.swift +++ b/Vernissage/Views/StatusView/Subviews/CommentsSectionView.swift @@ -6,6 +6,10 @@ import SwiftUI import PixelfedKit +import ClientKit +import ServicesKit +import EnvironmentKit +import WidgetsKit struct CommentsSectionView: View { @Environment(\.colorScheme) var colorScheme diff --git a/Vernissage/Views/StatusView/Subviews/StatusPlaceholderView.swift b/Vernissage/Views/StatusView/Subviews/StatusPlaceholderView.swift index 882e996..545a76f 100644 --- a/Vernissage/Views/StatusView/Subviews/StatusPlaceholderView.swift +++ b/Vernissage/Views/StatusView/Subviews/StatusPlaceholderView.swift @@ -5,6 +5,7 @@ // import SwiftUI +import WidgetsKit struct StatusPlaceholderView: View { @State var imageHeight: Double diff --git a/Vernissage/Views/StatusesView.swift b/Vernissage/Views/StatusesView.swift index 464c75c..ebd8c96 100644 --- a/Vernissage/Views/StatusesView.swift +++ b/Vernissage/Views/StatusesView.swift @@ -1,11 +1,15 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // import SwiftUI import PixelfedKit +import ClientKit +import ServicesKit +import EnvironmentKit +import WidgetsKit struct StatusesView: View { public enum ListType: Hashable { diff --git a/Vernissage/Views/TrendStatusesView.swift b/Vernissage/Views/TrendStatusesView.swift index 4154655..ca041a7 100644 --- a/Vernissage/Views/TrendStatusesView.swift +++ b/Vernissage/Views/TrendStatusesView.swift @@ -1,11 +1,15 @@ // // https://mczachurski.dev -// Copyright © 2022 Marcin Czachurski and the repository contributors. +// Copyright © 2023 Marcin Czachurski and the repository contributors. // Licensed under the Apache License 2.0. // import SwiftUI import PixelfedKit +import ClientKit +import ServicesKit +import EnvironmentKit +import WidgetsKit struct TrendStatusesView: View { @EnvironmentObject private var applicationState: ApplicationState diff --git a/Vernissage/Views/UserProfileView/Subviews/UserProfileHeaderView.swift b/Vernissage/Views/UserProfileView/Subviews/UserProfileHeaderView.swift index 1156ae5..b869621 100644 --- a/Vernissage/Views/UserProfileView/Subviews/UserProfileHeaderView.swift +++ b/Vernissage/Views/UserProfileView/Subviews/UserProfileHeaderView.swift @@ -6,6 +6,10 @@ import SwiftUI import PixelfedKit +import ClientKit +import ServicesKit +import WidgetsKit +import EnvironmentKit struct UserProfileHeaderView: View { @EnvironmentObject private var applicationState: ApplicationState @@ -21,11 +25,11 @@ struct UserProfileHeaderView: View { Spacer() if self.relationship.muting == true { - TagWidget(value: "Muted", color: .accentColor, systemImage: "message.and.waveform.fill") + TagWidget(value: "userProfile.title.muted", color: .accentColor, systemImage: "message.and.waveform.fill") } if self.relationship.blocking == true { - TagWidget(value: "Blocked", color: .dangerColor, systemImage: "hand.raised.fill") + TagWidget(value: "userProfile.title.blocked", color: .dangerColor, systemImage: "hand.raised.fill") } } diff --git a/Vernissage/Views/UserProfileView/Subviews/UserProfileStatusesView.swift b/Vernissage/Views/UserProfileView/Subviews/UserProfileStatusesView.swift index 847e8d4..0f64749 100644 --- a/Vernissage/Views/UserProfileView/Subviews/UserProfileStatusesView.swift +++ b/Vernissage/Views/UserProfileView/Subviews/UserProfileStatusesView.swift @@ -6,6 +6,10 @@ import SwiftUI import PixelfedKit +import ClientKit +import ServicesKit +import EnvironmentKit +import WidgetsKit struct UserProfileStatusesView: View { @EnvironmentObject private var applicationState: ApplicationState diff --git a/Vernissage/Views/UserProfileView/UserProfileView.swift b/Vernissage/Views/UserProfileView/UserProfileView.swift index ddaeaf8..81b5bf9 100644 --- a/Vernissage/Views/UserProfileView/UserProfileView.swift +++ b/Vernissage/Views/UserProfileView/UserProfileView.swift @@ -6,6 +6,10 @@ import SwiftUI import PixelfedKit +import ClientKit +import ServicesKit +import EnvironmentKit +import WidgetsKit struct UserProfileView: View { @EnvironmentObject private var applicationState: ApplicationState diff --git a/Vernissage/Widgets/ImageCarouselPicture.swift b/Vernissage/Widgets/ImageCarouselPicture.swift index d70537a..38bfb18 100644 --- a/Vernissage/Widgets/ImageCarouselPicture.swift +++ b/Vernissage/Widgets/ImageCarouselPicture.swift @@ -5,6 +5,9 @@ // import SwiftUI +import ClientKit +import ServicesKit +import WidgetsKit struct ImageCarouselPicture: View { @ObservedObject public var attachment: AttachmentModel diff --git a/Vernissage/Widgets/ImageGrid.swift b/Vernissage/Widgets/ImageGrid.swift index 738f460..63acfcc 100644 --- a/Vernissage/Widgets/ImageGrid.swift +++ b/Vernissage/Widgets/ImageGrid.swift @@ -6,6 +6,8 @@ import SwiftUI import NukeUI +import EnvironmentKit +import WidgetsKit struct ImageGrid: View { @EnvironmentObject var applicationState: ApplicationState diff --git a/Vernissage/Widgets/ImageRow.swift b/Vernissage/Widgets/ImageRow.swift index c5ef041..09e832e 100644 --- a/Vernissage/Widgets/ImageRow.swift +++ b/Vernissage/Widgets/ImageRow.swift @@ -5,6 +5,7 @@ // import SwiftUI +import ServicesKit struct ImageRow: View { private let status: StatusData diff --git a/Vernissage/Widgets/ImageRowAsync.swift b/Vernissage/Widgets/ImageRowAsync.swift index aea8d4b..c4f7f5d 100644 --- a/Vernissage/Widgets/ImageRowAsync.swift +++ b/Vernissage/Widgets/ImageRowAsync.swift @@ -6,6 +6,8 @@ import SwiftUI import PixelfedKit +import ClientKit +import ServicesKit struct ImageRowAsync: View { private let statusViewModel: StatusModel diff --git a/Vernissage/Widgets/ImageRowItem.swift b/Vernissage/Widgets/ImageRowItem.swift index b57b296..803ea20 100644 --- a/Vernissage/Widgets/ImageRowItem.swift +++ b/Vernissage/Widgets/ImageRowItem.swift @@ -5,6 +5,10 @@ // import SwiftUI +import ClientKit +import ServicesKit +import EnvironmentKit +import WidgetsKit struct ImageRowItem: View { @EnvironmentObject var applicationState: ApplicationState diff --git a/Vernissage/Widgets/ImageRowItemAsync.swift b/Vernissage/Widgets/ImageRowItemAsync.swift index cf1e50c..6eeee11 100644 --- a/Vernissage/Widgets/ImageRowItemAsync.swift +++ b/Vernissage/Widgets/ImageRowItemAsync.swift @@ -6,7 +6,11 @@ import SwiftUI import PixelfedKit +import ClientKit import NukeUI +import ServicesKit +import EnvironmentKit +import WidgetsKit struct ImageRowItemAsync: View { @EnvironmentObject var applicationState: ApplicationState diff --git a/Vernissage/Widgets/ImageViewer.swift b/Vernissage/Widgets/ImageViewer.swift index a9e1948..14822cd 100644 --- a/Vernissage/Widgets/ImageViewer.swift +++ b/Vernissage/Widgets/ImageViewer.swift @@ -5,6 +5,8 @@ // import SwiftUI +import ClientKit +import ServicesKit struct ImageViewer: View { @Environment(\.dismiss) private var dismiss diff --git a/Vernissage/Widgets/ImagesCarousel.swift b/Vernissage/Widgets/ImagesCarousel.swift index 46c9e9a..4272b2a 100644 --- a/Vernissage/Widgets/ImagesCarousel.swift +++ b/Vernissage/Widgets/ImagesCarousel.swift @@ -6,6 +6,8 @@ import SwiftUI import PixelfedKit +import ClientKit +import ServicesKit struct ImagesCarousel: View { @State public var attachments: [AttachmentModel] diff --git a/Vernissage/Widgets/ImagesGrid.swift b/Vernissage/Widgets/ImagesGrid.swift index 1ab467e..6123892 100644 --- a/Vernissage/Widgets/ImagesGrid.swift +++ b/Vernissage/Widgets/ImagesGrid.swift @@ -6,7 +6,9 @@ import SwiftUI import PixelfedKit +import ClientKit import NukeUI +import ServicesKit struct ImagesGrid: View { public enum GridType: Hashable { diff --git a/Vernissage/Widgets/InteractionRow.swift b/Vernissage/Widgets/InteractionRow.swift index b20bdc1..2639906 100644 --- a/Vernissage/Widgets/InteractionRow.swift +++ b/Vernissage/Widgets/InteractionRow.swift @@ -7,6 +7,10 @@ import SwiftUI import PixelfedKit import Drops +import ClientKit +import ServicesKit +import EnvironmentKit +import WidgetsKit struct InteractionRow: View { typealias DeleteAction = () -> Void diff --git a/VernissageShare/ComposeView.swift b/VernissageShare/ComposeView.swift new file mode 100644 index 0000000..1c0220d --- /dev/null +++ b/VernissageShare/ComposeView.swift @@ -0,0 +1,593 @@ +// +// https://mczachurski.dev +// Copyright © 2023 Marcin Czachurski and the repository contributors. +// Licensed under the Apache License 2.0. +// + +import Foundation +import SwiftUI +import PhotosUI +import PixelfedKit +import ClientKit +import EnvironmentKit +import WidgetsKit +import ServicesKit + +struct ComposeView: View { + @EnvironmentObject var applicationState: ApplicationState + @EnvironmentObject var client: Client + + @StateObject private var textModel: TextModel + + @State private var isKeyboardPresented = false + @State private var isSensitive = false + @State private var spoilerText = "" + @State private var commentsDisabled = false + @State private var place: Place? + + @State private var photosAreAttached = false + @State private var publishDisabled = true + @State private var interactiveDismissDisabled = false + + @State private var photosAreUploading = false + @State private var photosPickerVisible = false + + @State private var attachments: [NSItemProvider] = [] + @State private var selectedItems: [PhotosPickerItem] = [] + @State private var photosAttachment: [PhotoAttachment] = [] + + @State private var visibility = Pixelfed.Statuses.Visibility.pub + @State private var visibilityText: LocalizedStringKey = "compose.title.everyone" + @State private var visibilityImage = "globe.europe.africa" + + @FocusState private var focusedField: FocusField? + enum FocusField: Hashable { + case unknown + case content + case spoilerText + } + + @State private var showSheet: SheetType? + enum SheetType: Identifiable { + case photoDetails(PhotoAttachment) + case placeSelector + + public var id: String { + switch self { + case .photoDetails: + return "photoDetails" + case .placeSelector: + return "placeSelector" + } + } + } + + private let keyboardFontImageSize = 20.0 + private let keyboardFontTextSize = 16.0 + private let autocompleteFontTextSize = 12.0 + + public init(attachments: [NSItemProvider]) { + self.attachments = attachments + _textModel = StateObject(wrappedValue: .init()) + } + + var body: some View { + NavigationView { + ZStack(alignment: .bottom) { + self.composeBody() + + if self.isKeyboardPresented { + VStack(alignment: .leading, spacing: 0) { + self.autocompleteToolbar() + self.keyboardToolbar() + } + .transition(.opacity) + } + } + .frame(alignment: .topLeading) + .toolbar { + ToolbarItem(placement: .primaryAction) { + Button { + Task { + await self.publishStatus() + } + } label: { + Text("compose.title.publish", comment: "Publish") + } + .disabled(self.publishDisabled) + .buttonStyle(.borderedProminent) + } + + ToolbarItem(placement: .cancellationAction) { + Button(NSLocalizedString("compose.title.cancel", comment: "Cancel"), role: .cancel) { + self.close() + } + } + } + .onAppear { + self.textModel.client = self.client + Task { + await self.loadPhotos() + } + } + .onChange(of: self.textModel.text) { _ in + self.refreshScreenState() + } + .onChange(of: self.selectedItems) { _ in + Task { + await self.loadPhotos() + } + } + .sheet(item: $showSheet, content: { sheetType in + switch sheetType { + case .photoDetails(let photoAttachment): + PhotoEditorView(photoAttachment: photoAttachment) + case .placeSelector: + PlaceSelectorView(place: $place) + } + }) + .onReceive(keyboardPublisher) { value in + withAnimation { + self.isKeyboardPresented = value + } + } + .photosPicker(isPresented: $photosPickerVisible, + selection: $selectedItems, + maxSelectionCount: 4, + matching: .images) + .navigationTitle("compose.navigationBar.title") + .navigationBarTitleDisplayMode(.inline) + } + .interactiveDismissDisabled(self.interactiveDismissDisabled) + } + + @ViewBuilder + private func composeBody() -> some View { + ScrollView { + VStack(alignment: .leading) { + // Red content warning. + self.contentWarningView() + + // Information that comments are disabled. + self.commentsDisabledView() + + // User avatar and name. + self.userAvatarView() + + // Information about status visibility. + self.visibilityComboView() + + // Text area with new status. + self.statusTextView() + + // Grid with images. + self.imagesGridView() + + Spacer() + } + } + } + + @ViewBuilder + private func imagesGridView() -> some View { + HStack(alignment: .center) { + LazyVGrid(columns: [GridItem(.adaptive(minimum: 80))]) { + ForEach(self.photosAttachment, id: \.id) { photoAttachment in + ImageUploadView(photoAttachment: photoAttachment) { + self.showSheet = .photoDetails(photoAttachment) + } delete: { + self.photosAttachment = self.photosAttachment.filter({ item in + item != photoAttachment + }) + + self.selectedItems = self.selectedItems.filter({ item in + item != photoAttachment.photosPickerItem + }) + + self.attachments = self.attachments.filter({ item in + item != photoAttachment.nsItemProvider + }) + + self.refreshScreenState() + } upload: { + Task { + photoAttachment.error = nil + await self.upload(photoAttachment) + self.refreshScreenState() + } + } + } + } + } + .padding(8) + } + + @ViewBuilder + private func statusTextView() -> some View { + TextView($textModel.text, getTextView: { textView in + self.textModel.textView = textView + }) + .placeholder(self.placeholder()) + .padding(.horizontal, 8) + .focused($focusedField, equals: .content) + .onFirstAppear { + self.focusedField = .content + } + } + + @ViewBuilder + private func userAvatarView() -> some View { + if let accountData = applicationState.account { + HStack { + UsernameRow( + accountId: accountData.id, + accountAvatar: accountData.avatar, + accountDisplayName: accountData.displayName, + accountUsername: accountData.username) + Spacer() + } + .padding(.horizontal, 8) + } + } + + @ViewBuilder + private func contentWarningView() -> some View { + if self.isSensitive { + TextField("compose.title.writeContentWarning", text: $spoilerText, axis: .vertical) + .padding(8) + .lineLimit(1...2) + .focused($focusedField, equals: .spoilerText) + .keyboardType(.default) + .background(Color.dangerColor.opacity(0.4)) + } + } + + @ViewBuilder + private func commentsDisabledView() -> some View { + if self.commentsDisabled { + HStack { + Spacer() + Text("compose.title.commentsWillBeDisabled") + .textCase(.uppercase) + .font(.caption2) + .foregroundColor(.dangerColor) + } + .padding(.horizontal, 8) + } + } + + @ViewBuilder + private func visibilityComboView() -> some View { + HStack { + Menu { + Button { + self.visibility = .pub + self.visibilityText = "compose.title.everyone" + self.visibilityImage = "globe.europe.africa" + } label: { + Label("compose.title.everyone", systemImage: "globe.europe.africa") + } + + Button { + self.visibility = .unlisted + self.visibilityText = "compose.title.unlisted" + self.visibilityImage = "lock.open" + } label: { + Label("compose.title.unlisted", systemImage: "lock.open") + } + + Button { + self.visibility = .priv + self.visibilityText = "compose.title.followers" + self.visibilityImage = "lock" + } label: { + Label("compose.title.followers", systemImage: "lock") + } + } label: { + HStack { + Label(self.visibilityText, systemImage: self.visibilityImage) + Image(systemName: "chevron.down") + } + .padding(.vertical, 4) + .padding(.horizontal, 8) + .overlay( + RoundedRectangle(cornerRadius: 8) + .stroke(Color.accentColor, lineWidth: 1) + ) + } + + Spacer() + + if let name = self.place?.name, let country = self.place?.country { + Group { + Image(systemName: "mappin.and.ellipse") + Text("\(name), \(country)") + } + .foregroundColor(.lightGrayColor) + .padding(.trailing, 8) + } + } + .font(.footnote) + .padding(.horizontal, 8) + } + + @ViewBuilder + private func autocompleteToolbar() -> some View { + if !textModel.mentionsSuggestions.isEmpty || !textModel.tagsSuggestions.isEmpty { + ScrollView(.horizontal, showsIndicators: false) { + LazyHStack { + if !textModel.mentionsSuggestions.isEmpty { + ForEach(textModel.mentionsSuggestions, id: \.id) { account in + Button { + textModel.selectMentionSuggestion(account: account) + } label: { + HStack(alignment: .center) { + UserAvatar(accountAvatar: account.avatar, size: .comment) + + VStack(alignment: .leading) { + Text(account.displayNameWithoutEmojis) + .foregroundColor(.mainTextColor) + Text("@\(account.acct)") + .foregroundColor(.lightGrayColor) + } + .padding(.leading, 8) + } + .font(.system(size: self.autocompleteFontTextSize)) + .padding(.trailing, 8) + } + Divider() + } + } else { + ForEach(textModel.tagsSuggestions, id: \.url) { tag in + Button { + textModel.selectHashtagSuggestion(tag: tag) + } label: { + Text("#\(tag.name)") + .font(.system(size: self.autocompleteFontTextSize)) + .foregroundColor(self.applicationState.tintColor.color()) + } + Divider() + } + } + } + .padding(.horizontal, 8) + } + .frame(height: 40) + .background(.ultraThinMaterial) + } + } + + @ViewBuilder + private func keyboardToolbar() -> some View { + VStack(spacing: 0) { + Divider() + HStack(alignment: .center, spacing: 22) { + + Button { + hideKeyboard() + self.focusedField = .unknown + self.photosPickerVisible = true + } label: { + Image(systemName: self.photosAreAttached ? "photo.fill.on.rectangle.fill" : "photo.on.rectangle") + } + + Button { + withAnimation(.easeInOut) { + self.isSensitive.toggle() + + if self.isSensitive { + self.focusedField = .spoilerText + } else { + self.focusedField = .content + } + } + } label: { + Image(systemName: self.isSensitive ? "exclamationmark.square.fill" : "exclamationmark.square") + } + + Button { + withAnimation(.easeInOut) { + self.commentsDisabled.toggle() + } + } label: { + Image(systemName: self.commentsDisabled ? "person.2.slash" : "person.2.fill") + } + + Button { + if self.place != nil { + withAnimation(.easeInOut) { + self.place = nil + } + } else { + self.showSheet = .placeSelector + } + } label: { + Image(systemName: self.place == nil ? "mappin.square" : "mappin.square.fill") + } + + Button { + self.textModel.insertAtCursorPosition(content: "#") + } label: { + Image(systemName: "number") + } + + Button { + self.textModel.insertAtCursorPosition(content: "@") + } label: { + Image(systemName: "at") + } + + Spacer() + + Text("\(self.applicationState.statusMaxCharacters - textModel.text.string.utf16.count)") + .foregroundColor(.lightGrayColor) + .font(.system(size: self.keyboardFontTextSize)) + } + .padding(8) + .font(.system(size: self.keyboardFontImageSize)) + } + .background(Color.keyboardToolbarColor) + } + + private func placeholder() -> LocalizedStringKey { + "compose.title.attachPhotoFull" + } + + private func isPublishButtonDisabled() -> Bool { + // Publish always disabled when there is not status text. + if self.textModel.text.string.isEmpty { + return true + } + + // When application is during uploading photos we cannot send new status. + if self.photosAreUploading == true { + return true + } + + // When status is not a comment, then photo is required. + if self.photosAttachment.hasUploadedPhotos() == false { + return true + } + + return false + } + + private func isInteractiveDismissDisabled() -> Bool { + if self.textModel.text.string.isEmpty == false { + return true + } + + if self.photosAreUploading == true { + return true + } + + if self.photosAttachment.hasUploadedPhotos() == true { + return true + } + + return false + } + + private func loadPhotos() async { + do { + self.photosAreUploading = true + self.publishDisabled = self.isPublishButtonDisabled() + self.interactiveDismissDisabled = self.isInteractiveDismissDisabled() + + // We have to create list with existing photos. + var temporaryPhotosAttachment: [PhotoAttachment] = [] + + // Add to collection photos selected on photo picker. + for item in self.selectedItems { + if let photoAttachment = self.photosAttachment.first(where: { $0.photosPickerItem == item }) { + temporaryPhotosAttachment.append(photoAttachment) + continue + } + + temporaryPhotosAttachment.append(PhotoAttachment(photosPickerItem: item)) + } + + // Add to collection photos from share sheet. + for item in self.attachments { + if let photoAttachment = self.photosAttachment.first(where: { $0.nsItemProvider == item }) { + temporaryPhotosAttachment.append(photoAttachment) + continue + } + + temporaryPhotosAttachment.append(PhotoAttachment(nsItemProvider: item)) + } + + // We can show new list on the screen. + self.photosAttachment = temporaryPhotosAttachment + + // Now we have to get from photos images as JPEG. + for item in self.photosAttachment.filter({ $0.photoData == nil }) { + try await item.loadImage() + } + + // Open again the keyboard. + self.focusedField = .content + + // Upload images which hasn't been uploaded yet. + await self.upload() + + // Change state of the screen. + self.photosAreUploading = false + self.refreshScreenState() + } catch { + ErrorService.shared.handle(error, message: "compose.error.loadingPhotosFailed", showToastr: true) + } + } + + private func refreshScreenState() { + self.photosAreAttached = self.photosAttachment.hasUploadedPhotos() + self.publishDisabled = self.isPublishButtonDisabled() + self.interactiveDismissDisabled = self.isInteractiveDismissDisabled() + } + + private func upload() async { + for photoAttachment in self.photosAttachment { + await self.upload(photoAttachment) + } + } + + private func upload(_ photoAttachment: PhotoAttachment) async { + do { + // Image shouldn't be uploaded yet. + guard photoAttachment.uploadedAttachment == nil else { + return + } + + // From extension we are sending already resized file. + guard let data = photoAttachment.photoData, + let uiImage = UIImage(data: data) else { + return + } + + // Compresing to JPEG with extendedRGB color space. + guard let data = uiImage.getJpegData() else { + return + } + + let fileIndex = String.randomString(length: 8) + if let mediaAttachment = try await self.client.media?.upload(data: data, + fileName: "file-\(fileIndex).jpg", + mimeType: "image/jpeg") { + photoAttachment.uploadedAttachment = mediaAttachment + } + } catch { + photoAttachment.error = error + ErrorService.shared.handle(error, message: "compose.error.postingPhotoFailed", showToastr: true) + } + } + + private func close() { + // Clean tmp folder from file transferred from Photos. + self.photosAttachment.removeTmpFiles() + + // Close the view. + NotificationCenter.default.post(name: NotificationsName.shareSheetClose, object: nil) + } + + private func publishStatus() async { + do { + let status = self.createStatus() + if try await self.client.statuses?.new(status: status) != nil { + self.close() + } + } catch { + ErrorService.shared.handle(error, message: "compose.error.postingStatusFailed", showToastr: true) + } + } + + private func createStatus() -> Pixelfed.Statuses.Components { + return Pixelfed.Statuses.Components(inReplyToId: nil, + text: self.textModel.text.string, + spoilerText: self.isSensitive ? self.spoilerText : String.empty(), + mediaIds: self.photosAttachment.getUploadedPhotoIds(), + visibility: self.visibility, + sensitive: self.isSensitive, + placeId: self.place?.id, + commentsDisabled: self.commentsDisabled) + } +} diff --git a/VernissageShare/Info.plist b/VernissageShare/Info.plist new file mode 100644 index 0000000..28e9785 --- /dev/null +++ b/VernissageShare/Info.plist @@ -0,0 +1,29 @@ + + + + + NSExtension + + NSExtensionAttributes + + NSExtensionActivationRule + + NSExtensionActivationSupportsImageWithMaxCount + 4 + NSExtensionActivationSupportsMovieWithMaxCount + 0 + NSExtensionActivationSupportsText + + NSExtensionActivationSupportsWebPageWithMaxCount + 0 + NSExtensionActivationSupportsWebURLWithMaxCount + 0 + + + NSExtensionPointIdentifier + com.apple.share-services + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).ShareViewController + + + diff --git a/VernissageShare/NotificationsName.swift b/VernissageShare/NotificationsName.swift new file mode 100644 index 0000000..cc89438 --- /dev/null +++ b/VernissageShare/NotificationsName.swift @@ -0,0 +1,11 @@ +// +// https://mczachurski.dev +// Copyright © 2023 Marcin Czachurski and the repository contributors. +// Licensed under the Apache License 2.0. +// + +import Foundation + +public enum NotificationsName { + public static let shareSheetClose = NSNotification.Name("shareSheetClose") +} diff --git a/VernissageShare/ShareViewController.swift b/VernissageShare/ShareViewController.swift new file mode 100644 index 0000000..cbf7660 --- /dev/null +++ b/VernissageShare/ShareViewController.swift @@ -0,0 +1,80 @@ +// +// https://mczachurski.dev +// Copyright © 2023 Marcin Czachurski and the repository contributors. +// Licensed under the Apache License 2.0. +// + +import SwiftUI +import UIKit +import Social +import ClientKit +import EnvironmentKit + +class ShareViewController: UIViewController { + override func viewDidLoad() { + super.viewDidLoad() + + guard let item = extensionContext?.inputItems.first as? NSExtensionItem else { + return + } + + guard let attachments = item.attachments else { + return + } + + // Create shared objects. + let applicationState = ApplicationState.shared + let client = Client.shared + + // Get curret signed in user. + guard let currentAccount = AccountDataHandler.shared.getCurrentAccountData() else { + return + } + + // Create Pixelfed client. + let accountModel = currentAccount.toAccountModel() + client.setAccount(account: accountModel) + + // Set application state (with default instance settings). + applicationState.changeApplicationState(accountModel: accountModel, + instance: nil, + lastSeenStatusId: accountModel.lastSeenStatusId) + + // Update application settings from database. + ApplicationSettingsHandler.shared.update(applicationState: applicationState) + + // Create view. + let view = ComposeView(attachments: attachments) + .environmentObject(applicationState) + .environmentObject(client) + .tint(applicationState.tintColor.color()) + + // Add view to current UIViewController. + let childView = UIHostingController(rootView: view) + addChild(childView) + + childView.view.frame = self.view.bounds + self.view.addSubview(childView.view) + childView.didMove(toParent: self) + childView.view.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + childView.view.topAnchor.constraint(equalTo: self.view.topAnchor), + childView.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor), + childView.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), + childView.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor) + ]) + + NotificationCenter.default.addObserver(forName: NotificationsName.shareSheetClose, object: nil, queue: nil) { _ in + self.close() + } + } + + func close() { + extensionContext?.completeRequest(returningItems: [], completionHandler: nil) + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + } +} diff --git a/VernissageShare/VernissageShareExtension.entitlements b/VernissageShare/VernissageShareExtension.entitlements new file mode 100644 index 0000000..bff12cc --- /dev/null +++ b/VernissageShare/VernissageShareExtension.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.dev.mczachurski.vernissage + + + diff --git a/VernissageWidget/Views/LargeWidgetView.swift b/VernissageWidget/Views/LargeWidgetView.swift index db77a6d..058750d 100644 --- a/VernissageWidget/Views/LargeWidgetView.swift +++ b/VernissageWidget/Views/LargeWidgetView.swift @@ -6,6 +6,7 @@ import SwiftUI import WidgetKit +import EnvironmentKit struct LargeWidgetView: View { var entry: Provider.Entry diff --git a/VernissageWidget/Views/MediumWidgetView.swift b/VernissageWidget/Views/MediumWidgetView.swift index 6e6c840..276c24d 100644 --- a/VernissageWidget/Views/MediumWidgetView.swift +++ b/VernissageWidget/Views/MediumWidgetView.swift @@ -6,6 +6,7 @@ import SwiftUI import WidgetKit +import EnvironmentKit struct MediumWidgetView: View { var entry: Provider.Entry diff --git a/VernissageWidget/Views/SmallWidgetView.swift b/VernissageWidget/Views/SmallWidgetView.swift index e2c008e..b686186 100644 --- a/VernissageWidget/Views/SmallWidgetView.swift +++ b/VernissageWidget/Views/SmallWidgetView.swift @@ -6,6 +6,7 @@ import SwiftUI import WidgetKit +import EnvironmentKit struct SmallWidgetView: View { var entry: Provider.Entry diff --git a/WidgetsKit/.gitignore b/WidgetsKit/.gitignore new file mode 100644 index 0000000..3b29812 --- /dev/null +++ b/WidgetsKit/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/WidgetsKit/Package.swift b/WidgetsKit/Package.swift new file mode 100644 index 0000000..aafdffd --- /dev/null +++ b/WidgetsKit/Package.swift @@ -0,0 +1,49 @@ +// swift-tools-version: 5.8 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "WidgetsKit", + platforms: [ + .iOS(.v16), + .macOS(.v12), + .watchOS(.v8) + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "WidgetsKit", + targets: ["WidgetsKit"]) + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + .package(url: "https://github.com/exyte/ActivityIndicatorView.git", .upToNextMajor(from: "1.0.0")), + .package(url: "https://github.com/divadretlaw/EmojiText", .upToNextMajor(from: "2.6.0")), + .package(url: "https://github.com/kean/Nuke", .upToNextMajor(from: "12.0.0")), + .package(name: "PixelfedKit", path: "../PixelfedKit"), + .package(name: "ClientKit", path: "../ClientKit"), + .package(name: "ServicesKit", path: "../ServicesKit"), + .package(name: "EnvironmentKit", path: "../EnvironmentKit") + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "WidgetsKit", + dependencies: [ + .product(name: "ActivityIndicatorView", package: "ActivityIndicatorView"), + .product(name: "Nuke", package: "Nuke"), + .product(name: "NukeUI", package: "Nuke"), + .product(name: "EmojiText", package: "EmojiText"), + .product(name: "PixelfedKit", package: "PixelfedKit"), + .product(name: "ClientKit", package: "ClientKit"), + .product(name: "ServicesKit", package: "ServicesKit"), + .product(name: "EnvironmentKit", package: "EnvironmentKit") + ] + ), + .testTarget( + name: "WidgetsKitTests", + dependencies: ["WidgetsKit"]) + ] +) diff --git a/WidgetsKit/Sources/WidgetsKit/Extensions/FileManager+Clean.swift b/WidgetsKit/Sources/WidgetsKit/Extensions/FileManager+Clean.swift new file mode 100644 index 0000000..5baf54b --- /dev/null +++ b/WidgetsKit/Sources/WidgetsKit/Extensions/FileManager+Clean.swift @@ -0,0 +1,29 @@ +// +// https://mczachurski.dev +// Copyright © 2023 Marcin Czachurski and the repository contributors. +// Licensed under the Apache License 2.0. +// + +import Foundation +import SwiftUI +import ServicesKit + +public extension FileManager { + func clearTmpDirectory() { + do { + let temporaryDirectory = FileManager.default.temporaryDirectory + let contentsOfDirectory = try contentsOfDirectory(atPath: temporaryDirectory.path) + + for file in contentsOfDirectory { + let fileUrl = temporaryDirectory.appendingPathComponent(file) + do { + try removeItem(atPath: fileUrl.path) + } catch { + ErrorService.shared.handle(error, message: "Error during deleting file: '\(fileUrl.path)' from tmp directory.") + } + } + } catch { + ErrorService.shared.handle(error, message: "Error during getting tmp directory contents.") + } + } +} diff --git a/Vernissage/Extensions/LazyImageState+ImageResponse.swift b/WidgetsKit/Sources/WidgetsKit/Extensions/LazyImageState+ImageResponse.swift similarity index 81% rename from Vernissage/Extensions/LazyImageState+ImageResponse.swift rename to WidgetsKit/Sources/WidgetsKit/Extensions/LazyImageState+ImageResponse.swift index 5999e08..0c445f0 100644 --- a/Vernissage/Extensions/LazyImageState+ImageResponse.swift +++ b/WidgetsKit/Sources/WidgetsKit/Extensions/LazyImageState+ImageResponse.swift @@ -8,8 +8,8 @@ import Foundation import Nuke import NukeUI -extension LazyImageState { - public var imageResponse: ImageResponse? { +public extension LazyImageState { + var imageResponse: ImageResponse? { if case .success(let imageResponse) = result { return imageResponse } diff --git a/WidgetsKit/Sources/WidgetsKit/Extensions/NSItemProvider+Transferable.swift b/WidgetsKit/Sources/WidgetsKit/Extensions/NSItemProvider+Transferable.swift new file mode 100644 index 0000000..fbfb03b --- /dev/null +++ b/WidgetsKit/Sources/WidgetsKit/Extensions/NSItemProvider+Transferable.swift @@ -0,0 +1,23 @@ +// +// https://mczachurski.dev +// Copyright © 2023 Marcin Czachurski and the repository contributors. +// Licensed under the Apache License 2.0. +// + +import Foundation +import SwiftUI + +public extension NSItemProvider { + func createImageFileTranseferable() async throws -> ImageFileTranseferable? { + return try await withCheckedThrowingContinuation { continuation in + _ = self.loadTransferable(type: ImageFileTranseferable.self) { result in + switch result { + case let .success(success): + continuation.resume(with: .success(success)) + case .failure: + continuation.resume(with: .success(nil)) + } + } + } + } +} diff --git a/WidgetsKit/Sources/WidgetsKit/Extensions/PhotosPickerItem+Transferable.swift b/WidgetsKit/Sources/WidgetsKit/Extensions/PhotosPickerItem+Transferable.swift new file mode 100644 index 0000000..71f19e6 --- /dev/null +++ b/WidgetsKit/Sources/WidgetsKit/Extensions/PhotosPickerItem+Transferable.swift @@ -0,0 +1,24 @@ +// +// https://mczachurski.dev +// Copyright © 2023 Marcin Czachurski and the repository contributors. +// Licensed under the Apache License 2.0. +// + +import Foundation +import SwiftUI +import PhotosUI + +public extension PhotosPickerItem { + func createImageFileTranseferable() async throws -> ImageFileTranseferable? { + return try await withCheckedThrowingContinuation { continuation in + _ = self.loadTransferable(type: ImageFileTranseferable.self) { result in + switch result { + case let .success(success): + continuation.resume(with: .success(success)) + case .failure: + continuation.resume(with: .success(nil)) + } + } + } + } +} diff --git a/Vernissage/Extensions/String+Date.swift b/WidgetsKit/Sources/WidgetsKit/Extensions/String+Date.swift similarity index 98% rename from Vernissage/Extensions/String+Date.swift rename to WidgetsKit/Sources/WidgetsKit/Extensions/String+Date.swift index 8e52729..af1eba9 100644 --- a/Vernissage/Extensions/String+Date.swift +++ b/WidgetsKit/Sources/WidgetsKit/Extensions/String+Date.swift @@ -6,8 +6,8 @@ import Foundation -extension String { - public enum DateFormatType { +public extension String { + enum DateFormatType { /// The ISO8601 formatted year "yyyy" i.e. 1997 case isoYear diff --git a/Vernissage/Extensions/String+Empty.swift b/WidgetsKit/Sources/WidgetsKit/Extensions/String+Empty.swift similarity index 89% rename from Vernissage/Extensions/String+Empty.swift rename to WidgetsKit/Sources/WidgetsKit/Extensions/String+Empty.swift index dcfca2f..9783dcb 100644 --- a/Vernissage/Extensions/String+Empty.swift +++ b/WidgetsKit/Sources/WidgetsKit/Extensions/String+Empty.swift @@ -6,7 +6,7 @@ import Foundation -extension String { +public extension String { static func empty() -> String { return "" } diff --git a/Vernissage/Extensions/String+Random.swift b/WidgetsKit/Sources/WidgetsKit/Extensions/String+Random.swift similarity index 93% rename from Vernissage/Extensions/String+Random.swift rename to WidgetsKit/Sources/WidgetsKit/Extensions/String+Random.swift index f6494c7..7eb6b29 100644 --- a/Vernissage/Extensions/String+Random.swift +++ b/WidgetsKit/Sources/WidgetsKit/Extensions/String+Random.swift @@ -6,7 +6,7 @@ import Foundation -extension String { +public extension String { static func randomString(length: Int) -> String { let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" return String((0..= 6 else { return nil } let sizeFlag = String(blurHash[0]).decode83() diff --git a/Vernissage/Extensions/UIImage+Jpeg.swift b/WidgetsKit/Sources/WidgetsKit/Extensions/UIImage+Jpeg.swift similarity index 95% rename from Vernissage/Extensions/UIImage+Jpeg.swift rename to WidgetsKit/Sources/WidgetsKit/Extensions/UIImage+Jpeg.swift index a78ffb8..22c44a1 100644 --- a/Vernissage/Extensions/UIImage+Jpeg.swift +++ b/WidgetsKit/Sources/WidgetsKit/Extensions/UIImage+Jpeg.swift @@ -6,8 +6,9 @@ import SwiftUI -extension UIImage { - public func getJpegData() -> Data? { +public extension UIImage { + func getJpegData() -> Data? { + #if targetEnvironment(simulator) // For testing purposes. let converted = self.convertToExtendedSRGBJpeg() @@ -31,7 +32,7 @@ extension UIImage { } } - public func convertToExtendedSRGBJpeg() -> Data? { + func convertToExtendedSRGBJpeg() -> Data? { guard let sourceImage = CIImage(image: self, options: [.applyOrientationProperty: true]) else { return self.jpegData(compressionQuality: 0.9) } diff --git a/Vernissage/Extensions/UIImage+Rounded.swift b/WidgetsKit/Sources/WidgetsKit/Extensions/UIImage+Rounded.swift similarity index 94% rename from Vernissage/Extensions/UIImage+Rounded.swift rename to WidgetsKit/Sources/WidgetsKit/Extensions/UIImage+Rounded.swift index a0e2849..0e9b473 100644 --- a/Vernissage/Extensions/UIImage+Rounded.swift +++ b/WidgetsKit/Sources/WidgetsKit/Extensions/UIImage+Rounded.swift @@ -6,8 +6,9 @@ import Foundation import SwiftUI +import EnvironmentKit -extension UIImage { +public extension UIImage { func roundedAvatar(avatarShape: AvatarShape) -> UIImage { let imageView: UIImageView = UIImageView(image: self) let layer = imageView.layer diff --git a/Vernissage/Extensions/UIImage+Size.swift b/WidgetsKit/Sources/WidgetsKit/Extensions/UIImage+Size.swift similarity index 96% rename from Vernissage/Extensions/UIImage+Size.swift rename to WidgetsKit/Sources/WidgetsKit/Extensions/UIImage+Size.swift index 26c6dd5..71c1d13 100644 --- a/Vernissage/Extensions/UIImage+Size.swift +++ b/WidgetsKit/Sources/WidgetsKit/Extensions/UIImage+Size.swift @@ -6,7 +6,7 @@ import UIKit -extension UIImage.Orientation { +public extension UIImage.Orientation { var exifOrientation: Int32 { switch self { case .up: return 1 @@ -22,7 +22,7 @@ extension UIImage.Orientation { } } -extension UIImage { +public extension UIImage { func resized(to targetSize: CGSize) -> UIImage { guard let sourceImage = CIImage(image: self, options: [.applyOrientationProperty: true]) else { return self diff --git a/Vernissage/Extensions/View+Keyboard.swift b/WidgetsKit/Sources/WidgetsKit/Extensions/View+Keyboard.swift similarity index 96% rename from Vernissage/Extensions/View+Keyboard.swift rename to WidgetsKit/Sources/WidgetsKit/Extensions/View+Keyboard.swift index 31ebae8..71bb222 100644 --- a/Vernissage/Extensions/View+Keyboard.swift +++ b/WidgetsKit/Sources/WidgetsKit/Extensions/View+Keyboard.swift @@ -7,7 +7,7 @@ import SwiftUI import Combine -extension View { +public extension View { var keyboardPublisher: AnyPublisher { Publishers .Merge( diff --git a/Vernissage/Extensions/View+Transition.swift b/WidgetsKit/Sources/WidgetsKit/Extensions/View+Transition.swift similarity index 95% rename from Vernissage/Extensions/View+Transition.swift rename to WidgetsKit/Sources/WidgetsKit/Extensions/View+Transition.swift index aaf73ae..6b3fe57 100644 --- a/Vernissage/Extensions/View+Transition.swift +++ b/WidgetsKit/Sources/WidgetsKit/Extensions/View+Transition.swift @@ -6,7 +6,7 @@ import SwiftUI -extension View { +public extension View { func withoutAnimation(action: @escaping () -> Void) { var transaction = Transaction() transaction.disablesAnimations = true diff --git a/Vernissage/Models/ImageFileTranseferable.swift b/WidgetsKit/Sources/WidgetsKit/Models/ImageFileTranseferable.swift similarity index 90% rename from Vernissage/Models/ImageFileTranseferable.swift rename to WidgetsKit/Sources/WidgetsKit/Models/ImageFileTranseferable.swift index 1fa41ff..cd578fc 100644 --- a/Vernissage/Models/ImageFileTranseferable.swift +++ b/WidgetsKit/Sources/WidgetsKit/Models/ImageFileTranseferable.swift @@ -4,12 +4,11 @@ // Licensed under the Apache License 2.0. // -import UIKit import SwiftUI +import Foundation public struct ImageFileTranseferable: Transferable { - let url: URL - lazy var data: Data? = try? Data(contentsOf: url) + public let url: URL public static var transferRepresentation: some TransferRepresentation { FileRepresentation(contentType: .image) { image in diff --git a/WidgetsKit/Sources/WidgetsKit/Models/PhotoAttachment.swift b/WidgetsKit/Sources/WidgetsKit/Models/PhotoAttachment.swift new file mode 100644 index 0000000..6b09e2c --- /dev/null +++ b/WidgetsKit/Sources/WidgetsKit/Models/PhotoAttachment.swift @@ -0,0 +1,98 @@ +// +// https://mczachurski.dev +// Copyright © 2023 Marcin Czachurski and the repository contributors. +// Licensed under the Apache License 2.0. +// + +import Foundation +import PhotosUI +import SwiftUI +import PixelfedKit +import ServicesKit + +public class PhotoAttachment: ObservableObject, Identifiable, Equatable, Hashable { + public let id: String + + /// Information about image from photos picker. + public let photosPickerItem: PhotosPickerItem? + + /// Information about image from share extension. + public let nsItemProvider: NSItemProvider? + + /// Variable used for presentation layer. + @Published public var photoData: Data? + + /// Property which stores orginal image file copied from Photos to tmp folder. + @Published public var imageFileTranseferable: ImageFileTranseferable? + + /// Property stores information after upload to Pixelfed. + @Published public var uploadedAttachment: UploadedAttachment? + + /// Error from Pixelfed. + @Published public var error: Error? + + public init(photosPickerItem: PhotosPickerItem? = nil, nsItemProvider: NSItemProvider? = nil) { + self.id = UUID().uuidString + + self.photosPickerItem = photosPickerItem + self.nsItemProvider = nsItemProvider + } + + public static func == (lhs: PhotoAttachment, rhs: PhotoAttachment) -> Bool { + lhs.id == rhs.id + } + + public func hash(into hasher: inout Hasher) { + return hasher.combine(self.id) + } +} + +public extension PhotoAttachment { + + @MainActor + func loadImage() async throws { + if let pickerItem = self.photosPickerItem, + let transferable = try await pickerItem.createImageFileTranseferable() { + self.imageFileTranseferable = transferable + self.photoData = await ImageCompressService.shared.compressImageFrom(url: transferable.url) + } + + if let itemProvider = self.nsItemProvider, + let transferable = try await itemProvider.createImageFileTranseferable() { + self.imageFileTranseferable = transferable + self.photoData = await ImageCompressService.shared.compressImageFrom(url: transferable.url) + } + } +} + +public extension [PhotoAttachment] { + func hasUploadedPhotos() -> Bool { + return self.contains { photoAttachment in + photoAttachment.uploadedAttachment != nil + } + } + + func getUploadedPhotoIds() -> [String] { + var ids: [String] = [] + + for item in self { + if let uploadedAttachment = item.uploadedAttachment { + ids.append(uploadedAttachment.id) + } + } + + return ids + } + + func removeTmpFiles() { + for file in self { + if let fileUrl = file.imageFileTranseferable?.url { + do { + try FileManager.default.removeItem(at: fileUrl) + } catch { + ErrorService.shared.handle(error, message: "Error during removing transferred image from tmp directory.") + } + } + } + } +} diff --git a/Vernissage/Widgets/TextView/TextModel.swift b/WidgetsKit/Sources/WidgetsKit/TextView/TextModel.swift similarity index 90% rename from Vernissage/Widgets/TextView/TextModel.swift rename to WidgetsKit/Sources/WidgetsKit/TextView/TextModel.swift index 379a788..b69c9de 100644 --- a/Vernissage/Widgets/TextView/TextModel.swift +++ b/WidgetsKit/Sources/WidgetsKit/TextView/TextModel.swift @@ -7,13 +7,16 @@ import Foundation import SwiftUI import PixelfedKit +import ServicesKit +import ClientKit +import EnvironmentKit @MainActor public class TextModel: NSObject, ObservableObject { - var client: Client? - var textView: UITextView? + public var client: Client? + public var textView: UITextView? - var selectedRange: NSRange { + public var selectedRange: NSRange { get { guard let textView else { return .init(location: 0, length: 0) @@ -26,7 +29,7 @@ public class TextModel: NSObject, ObservableObject { } } - var markedTextRange: UITextRange? { + public var markedTextRange: UITextRange? { guard let textView else { return nil } @@ -34,10 +37,10 @@ public class TextModel: NSObject, ObservableObject { return textView.markedTextRange } - @Published var mentionsSuggestions: [Account] = [] - @Published var tagsSuggestions: [Tag] = [] + @Published public var mentionsSuggestions: [Account] = [] + @Published public var tagsSuggestions: [Tag] = [] - @Published var text = NSMutableAttributedString(string: "") { + @Published public var text = NSMutableAttributedString(string: "") { didSet { let range = selectedRange processText() @@ -69,7 +72,7 @@ public class TextModel: NSObject, ObservableObject { guard markedTextRange == nil else { return } text.addAttributes([.foregroundColor: UIColor(Color.label), - .font: UIFont.preferredFont(from: .body), + .font: UIFont.preferredFont(forTextStyle: .body), .backgroundColor: UIColor.clear, .underlineColor: UIColor.clear], range: NSRange(location: 0, length: text.string.utf16.count)) @@ -166,19 +169,19 @@ public class TextModel: NSObject, ObservableObject { currentSuggestionRange = nil } - func selectMentionSuggestion(account: Account) { + public func selectMentionSuggestion(account: Account) { if let range = currentSuggestionRange { replaceTextWith(text: "@\(account.acct) ", inRange: range) } } - func selectHashtagSuggestion(tag: Tag) { + public func selectHashtagSuggestion(tag: Tag) { if let range = currentSuggestionRange { replaceTextWith(text: "#\(tag.name) ", inRange: range) } } - func replaceTextWith(text: String, inRange: NSRange) { + public func replaceTextWith(text: String, inRange: NSRange) { let string = self.text string.mutableString.deleteCharacters(in: inRange) string.mutableString.insert(text, at: inRange.location) diff --git a/Vernissage/Widgets/TextView/TextView.swift b/WidgetsKit/Sources/WidgetsKit/TextView/TextView.swift similarity index 98% rename from Vernissage/Widgets/TextView/TextView.swift rename to WidgetsKit/Sources/WidgetsKit/TextView/TextView.swift index 03f905b..d67fdc6 100644 --- a/Vernissage/Widgets/TextView/TextView.swift +++ b/WidgetsKit/Sources/WidgetsKit/TextView/TextView.swift @@ -130,7 +130,7 @@ extension TextView.Representable { textView.delegate = self - textView.font = UIFont.preferredFont(from: .body) + textView.font = UIFont.preferredFont(forTextStyle: .body) textView.adjustsFontForContentSizeCategory = true textView.autocapitalizationType = .sentences textView.autocorrectionType = .yes diff --git a/Vernissage/ViewModifiers/ClearButton.swift b/WidgetsKit/Sources/WidgetsKit/ViewModifiers/ClearButton.swift similarity index 100% rename from Vernissage/ViewModifiers/ClearButton.swift rename to WidgetsKit/Sources/WidgetsKit/ViewModifiers/ClearButton.swift diff --git a/Vernissage/ViewModifiers/FirstAppear.swift b/WidgetsKit/Sources/WidgetsKit/ViewModifiers/FirstAppear.swift similarity index 100% rename from Vernissage/ViewModifiers/FirstAppear.swift rename to WidgetsKit/Sources/WidgetsKit/ViewModifiers/FirstAppear.swift diff --git a/Vernissage/ViewModifiers/NavigationMenu.swift b/WidgetsKit/Sources/WidgetsKit/ViewModifiers/NavigationMenu.swift similarity index 89% rename from Vernissage/ViewModifiers/NavigationMenu.swift rename to WidgetsKit/Sources/WidgetsKit/ViewModifiers/NavigationMenu.swift index 241345e..ff8af3f 100644 --- a/Vernissage/ViewModifiers/NavigationMenu.swift +++ b/WidgetsKit/Sources/WidgetsKit/ViewModifiers/NavigationMenu.swift @@ -6,6 +6,7 @@ import Foundation import SwiftUI +import EnvironmentKit public extension View { func navigationMenu(menuPosition: Binding, @@ -39,12 +40,14 @@ private struct NavigationMenu: ViewModifier where MenuItems: View { Spacer() self.menuContent() - .padding(.trailing, 20) + .padding(.trailing, 30) + .padding(.bottom, 10) } if self.menuPosition == .bottomLeft { self.menuContent() - .padding(.leading, 20) + .padding(.leading, 30) + .padding(.bottom, 10) Spacer() } diff --git a/Vernissage/Views/ComposeView/Subviews/ImageUploadView.swift b/WidgetsKit/Sources/WidgetsKit/Views/ImageUploadView.swift similarity index 96% rename from Vernissage/Views/ComposeView/Subviews/ImageUploadView.swift rename to WidgetsKit/Sources/WidgetsKit/Views/ImageUploadView.swift index dcfd20a..f45a53f 100644 --- a/Vernissage/Views/ComposeView/Subviews/ImageUploadView.swift +++ b/WidgetsKit/Sources/WidgetsKit/Views/ImageUploadView.swift @@ -5,9 +5,9 @@ // import SwiftUI +import ServicesKit -struct ImageUploadView: View { - @EnvironmentObject public var routerPath: RouterPath +public struct ImageUploadView: View { @ObservedObject public var photoAttachment: PhotoAttachment private let delete: () -> Void @@ -21,7 +21,7 @@ struct ImageUploadView: View { self.upload = upload } - var body: some View { + public var body: some View { if photoAttachment.error != nil { Menu { Button { diff --git a/Vernissage/Views/PhotoEditorView.swift b/WidgetsKit/Sources/WidgetsKit/Views/PhotoEditorView.swift similarity index 94% rename from Vernissage/Views/PhotoEditorView.swift rename to WidgetsKit/Sources/WidgetsKit/Views/PhotoEditorView.swift index bf866c1..3220629 100644 --- a/Vernissage/Views/PhotoEditorView.swift +++ b/WidgetsKit/Sources/WidgetsKit/Views/PhotoEditorView.swift @@ -5,15 +5,21 @@ // import SwiftUI +import ClientKit +import ServicesKit -struct PhotoEditorView: View { +public struct PhotoEditorView: View { @EnvironmentObject var client: Client @Environment(\.dismiss) private var dismiss @State private var description: String = String.empty() @ObservedObject public var photoAttachment: PhotoAttachment - var body: some View { + public init(photoAttachment: PhotoAttachment) { + self.photoAttachment = photoAttachment + } + + public var body: some View { NavigationView { VStack(alignment: .leading) { if let data = photoAttachment.photoData, let uiImage = UIImage(data: data) { diff --git a/Vernissage/Views/PlaceSelectorView.swift b/WidgetsKit/Sources/WidgetsKit/Views/PlaceSelectorView.swift similarity index 95% rename from Vernissage/Views/PlaceSelectorView.swift rename to WidgetsKit/Sources/WidgetsKit/Views/PlaceSelectorView.swift index d823788..bdb3f4c 100644 --- a/Vernissage/Views/PlaceSelectorView.swift +++ b/WidgetsKit/Sources/WidgetsKit/Views/PlaceSelectorView.swift @@ -6,8 +6,11 @@ import SwiftUI import PixelfedKit +import ClientKit +import ServicesKit +import EnvironmentKit -struct PlaceSelectorView: View { +public struct PlaceSelectorView: View { @EnvironmentObject var applicationState: ApplicationState @EnvironmentObject var client: Client @Environment(\.dismiss) private var dismiss @@ -24,7 +27,11 @@ struct PlaceSelectorView: View { case search } - var body: some View { + public init(place: Binding) { + self._place = place + } + + public var body: some View { NavigationView { VStack(alignment: .leading) { List { diff --git a/Vernissage/Widgets/ActionButton.swift b/WidgetsKit/Sources/WidgetsKit/Widgets/ActionButton.swift similarity index 92% rename from Vernissage/Widgets/ActionButton.swift rename to WidgetsKit/Sources/WidgetsKit/Widgets/ActionButton.swift index 945bdd9..79ed64f 100644 --- a/Vernissage/Widgets/ActionButton.swift +++ b/WidgetsKit/Sources/WidgetsKit/Widgets/ActionButton.swift @@ -5,8 +5,9 @@ // import SwiftUI +import ServicesKit -struct ActionButton