Merge pull request #24 from VernissageApp/develop

Merge version 1.2.0 into main
This commit is contained in:
Marcin Czachurski 2023-04-09 21:15:53 +02:00 committed by GitHub
commit 4a4b6735fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
261 changed files with 2473 additions and 1042 deletions

9
ClientKit/.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

36
ClientKit/Package.swift Normal file
View File

@ -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"])
]
)

View File

@ -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)
}
}

View File

@ -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()
}

View File

@ -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)
}
}

View File

@ -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)
}
}
}

View File

@ -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)

View File

@ -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
}
}

View File

@ -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.
//

View File

@ -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
}

View File

@ -6,7 +6,7 @@
import Foundation
extension String {
public extension String {
func calculateExifNumber() -> String? {
guard self.contains("/") else {
return self

View File

@ -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
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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!")
}
}

View File

@ -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
}
}

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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

View File

@ -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()

9
EnvironmentKit/.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

View File

@ -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"])
]
)

View File

@ -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

View File

@ -7,7 +7,7 @@
import Foundation
import SwiftUI
extension AvatarShape {
public extension AvatarShape {
func shape() -> some Shape {
switch self {
case .circle:

View File

@ -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)
}

View File

@ -6,7 +6,7 @@
import SwiftUI
extension Color {
public extension Color {
// MARK: - Text Colors
static let lightText = Color(UIColor.lightText)

View File

@ -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

View File

@ -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()
}
}

View File

@ -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!")
}
}

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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"])

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.")
}
}
}

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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)
}
}
}

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.";

View File

@ -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.";

View File

@ -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.";

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

Some files were not shown because too many files have changed in this diff Show More