diff --git a/PixelfedKit/Package.swift b/PixelfedKit/Package.swift index e97c3a7..51906d4 100644 --- a/PixelfedKit/Package.swift +++ b/PixelfedKit/Package.swift @@ -19,17 +19,15 @@ let package = Package( dependencies: [ // Dependencies declare other packages that this package depends on. // .package(url: /* package url */, from: "1.0.0"), - .package( - url: "https://github.com/OAuthSwift/OAuthSwift.git", - .upToNextMajor(from: "2.2.0") - ) + .package(url: "https://github.com/OAuthSwift/OAuthSwift.git", .upToNextMajor(from: "2.2.0")), + .package(url: "https://gitlab.com/mflint/HTML2Markdown", .upToNextMajor(from: "1.0.0")) ], 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: "PixelfedKit", - dependencies: ["OAuthSwift"]), + dependencies: ["OAuthSwift", "HTML2Markdown"]), .testTarget( name: "PixelfedKitTests", dependencies: ["PixelfedKit"]), diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Account.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Account.swift index baeb870..2801993 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Account.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Account.swift @@ -22,7 +22,7 @@ public struct Account: Codable { public let displayName: String? /// The profile’s bio or description. - public let note: String? + public let note: Html? /// The location of the user’s profile page. public let url: URL? diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Html.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Html.swift new file mode 100644 index 0000000..5372932 --- /dev/null +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Html.swift @@ -0,0 +1,46 @@ +// +// https://mczachurski.dev +// Copyright © 2023 Marcin Czachurski and the repository contributors. +// Licensed under the MIT License. +// + +import Foundation +import HTML2Markdown + +public struct Html: Codable { + public var htmlValue: String = "" + public var asMarkdown: String = "" + + init(_ htmlValue: String) { + do { + self.htmlValue = htmlValue + self.asMarkdown = try self.parseToMarkdown(html: htmlValue) + } catch { + self.htmlValue = "" + self.asMarkdown = "" + } + } + + public init(from decoder: Decoder) { + do { + let container = try decoder.singleValueContainer() + self.htmlValue = try container.decode(String.self) + self.asMarkdown = try self.parseToMarkdown(html: htmlValue) + } catch { + self.htmlValue = "" + self.asMarkdown = "" + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(htmlValue) + } + + private func parseToMarkdown(html: String) throws -> String { + let dom = try HTMLParser().parse(html: html) + return dom.toMarkdown() + // Add space between hashtags and mentions that follow each other + .replacingOccurrences(of: ")[", with: ") [") + } +} diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Instance.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Instance.swift index 404b6a1..5c011e7 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Instance.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Instance.swift @@ -75,7 +75,7 @@ public struct Instance: Codable { self.title = try? container.decodeIfPresent(String.self, forKey: .title) self.sourceUrl = try? container.decodeIfPresent(URL.self, forKey: .sourceUrl) self.shortDescription = try? container.decodeIfPresent(String.self, forKey: .shortDescription) - self.description = try? container.decodeIfPresent(String.self, forKey: .description) + self.description = try? container.decodeIfPresent(Html.self, forKey: .description) self.thumbnail = try? container.decodeIfPresent(URL.self, forKey: .thumbnail) self.languages = try? container.decodeIfPresent([String].self, forKey: .languages) self.configuration = try? container.decodeIfPresent(Configuration.self, forKey: .configuration) diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Status.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Status.swift index 894fe47..463f452 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Status.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Status.swift @@ -158,7 +158,7 @@ public class Status: Codable { self.uri = try container.decode(String.self, forKey: .uri) self.url = try? container.decode(URL.self, forKey: .url) self.account = try container.decode(Account.self, forKey: .account) - self.content = try container.decode(Html.self, forKey: .content) + self.content = (try? container.decode(Html.self, forKey: .content)) ?? Html("") self.createdAt = try container.decode(String.self, forKey: .createdAt) self.inReplyToId = try? container.decode(EntityId.self, forKey: .inReplyToId) self.inReplyToAccount = try? container.decode(EntityId.self, forKey: .inReplyToAccount) diff --git a/PixelfedKit/Sources/PixelfedKit/Entities/Types.swift b/PixelfedKit/Sources/PixelfedKit/Entities/Types.swift index 7951071..91310e1 100644 --- a/PixelfedKit/Sources/PixelfedKit/Entities/Types.swift +++ b/PixelfedKit/Sources/PixelfedKit/Entities/Types.swift @@ -7,7 +7,6 @@ import Foundation public typealias EntityId = String -public typealias Html = String public typealias SearchQuery = String public typealias ClientId = String diff --git a/Vernissage.xcodeproj/project.pbxproj b/Vernissage.xcodeproj/project.pbxproj index 4aa74ef..cf04d47 100644 --- a/Vernissage.xcodeproj/project.pbxproj +++ b/Vernissage.xcodeproj/project.pbxproj @@ -91,8 +91,6 @@ 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 */; }; - F88E4D50297EA5230057491A /* HTML2Markdown in Frameworks */ = {isa = PBXBuildFile; productRef = F88E4D4F297EA5230057491A /* HTML2Markdown */; }; - F88E4D52297EA6DA0057491A /* String+Markdown.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88E4D51297EA6DA0057491A /* String+Markdown.swift */; }; 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 */; }; @@ -234,7 +232,6 @@ 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 = ""; }; - F88E4D51297EA6DA0057491A /* String+Markdown.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Markdown.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 = ""; }; @@ -307,7 +304,6 @@ F8210DD92966BB7E001D9973 /* NukeUI in Frameworks */, F85E132529741F05006A051D /* ActivityIndicatorView in Frameworks */, F8B1E64F2973F61400EE0D10 /* Drops in Frameworks */, - F88E4D50297EA5230057491A /* HTML2Markdown in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -380,7 +376,6 @@ F8341F8F295C636C009C8EE6 /* Data+Exif.swift */, F85D49862964334100751DF7 /* String+Date.swift */, F8C14391296AF0B3001FE31D /* String+Exif.swift */, - F88E4D51297EA6DA0057491A /* String+Markdown.swift */, F898DE6F2972868A004B4A6A /* String+Empty.swift */, F8AD061229A565620042F111 /* String+Random.swift */, F8210DE42966E160001D9973 /* Color+SystemColors.swift */, @@ -713,7 +708,6 @@ F8B1E64E2973F61400EE0D10 /* Drops */, F85E132429741F05006A051D /* ActivityIndicatorView */, F88E4D4C297EA4290057491A /* EmojiText */, - F88E4D4F297EA5230057491A /* HTML2Markdown */, F83E00EC29A2237C005D25A3 /* PixelfedKit */, ); productName = Vernissage; @@ -749,7 +743,6 @@ F8B1E64D2973F61400EE0D10 /* XCRemoteSwiftPackageReference "Drops" */, F85E132329741F05006A051D /* XCRemoteSwiftPackageReference "ActivityIndicatorView" */, F88E4D4B297EA4290057491A /* XCRemoteSwiftPackageReference "EmojiText" */, - F88E4D4E297EA5230057491A /* XCRemoteSwiftPackageReference "HTML2Markdown" */, ); productRefGroup = F88C2469295C37B80006098B /* Products */; projectDirPath = ""; @@ -850,7 +843,6 @@ F8B9B34B298D4ACE009CC69C /* Client+Tags.swift in Sources */, F88C2478295C37BB0006098B /* Vernissage.xcdatamodeld in Sources */, F8AD061329A565620042F111 /* String+Random.swift in Sources */, - F88E4D52297EA6DA0057491A /* String+Markdown.swift in Sources */, F898DE7229728CB2004B4A6A /* CommentModel.swift in Sources */, F89A46DE296EABA20062125F /* StatusPlaceholderView.swift in Sources */, F88C2482295C3A4F0006098B /* StatusView.swift in Sources */, @@ -1150,14 +1142,6 @@ minimumVersion = 1.3.0; }; }; - F88E4D4E297EA5230057491A /* XCRemoteSwiftPackageReference "HTML2Markdown" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://gitlab.com/mflint/HTML2Markdown"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.0.0; - }; - }; F8B1E64D2973F61400EE0D10 /* XCRemoteSwiftPackageReference "Drops" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/omaralbeik/Drops"; @@ -1198,11 +1182,6 @@ package = F88E4D4B297EA4290057491A /* XCRemoteSwiftPackageReference "EmojiText" */; productName = EmojiText; }; - F88E4D4F297EA5230057491A /* HTML2Markdown */ = { - isa = XCSwiftPackageProductDependency; - package = F88E4D4E297EA5230057491A /* XCRemoteSwiftPackageReference "HTML2Markdown" */; - productName = HTML2Markdown; - }; F8B1E64E2973F61400EE0D10 /* Drops */ = { isa = XCSwiftPackageProductDependency; package = F8B1E64D2973F61400EE0D10 /* XCRemoteSwiftPackageReference "Drops" */; diff --git a/Vernissage/CoreData/StatusData+Status.swift b/Vernissage/CoreData/StatusData+Status.swift index 0d7838f..e7d6ee0 100644 --- a/Vernissage/CoreData/StatusData+Status.swift +++ b/Vernissage/CoreData/StatusData+Status.swift @@ -27,7 +27,7 @@ extension StatusData { self.applicationName = status.application?.name self.applicationWebsite = status.application?.website self.bookmarked = status.bookmarked - self.content = status.content + self.content = status.content.htmlValue self.favourited = status.favourited self.favouritesCount = Int32(status.favouritesCount) self.inReplyToAccount = status.inReplyToAccount diff --git a/Vernissage/Extensions/String+Markdown.swift b/Vernissage/Extensions/String+Markdown.swift deleted file mode 100644 index fb4d1aa..0000000 --- a/Vernissage/Extensions/String+Markdown.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// https://mczachurski.dev -// Copyright © 2023 Marcin Czachurski and the repository contributors. -// Licensed under the MIT License. -// - -import Foundation -import HTML2Markdown - -extension String { - public var asMarkdown: String { - do { - let dom = try HTMLParser().parse(html: self) - return dom.toMarkdown() - // Add space between hashtags and mentions that follow each other - .replacingOccurrences(of: ")[", with: ") [") - } catch { - return self - } - } -} diff --git a/Vernissage/Services/AuthorizationService.swift b/Vernissage/Services/AuthorizationService.swift index 0b8a126..ea7ab34 100644 --- a/Vernissage/Services/AuthorizationService.swift +++ b/Vernissage/Services/AuthorizationService.swift @@ -81,7 +81,7 @@ public class AuthorizationService { accountData.username = account.username accountData.acct = account.acct accountData.displayName = account.displayNameWithoutEmojis - accountData.note = account.note + accountData.note = account.note?.htmlValue accountData.url = account.url accountData.avatar = account.avatar accountData.header = account.header @@ -207,7 +207,7 @@ public class AuthorizationService { dbAccount.username = account.username dbAccount.acct = account.acct dbAccount.displayName = account.displayNameWithoutEmojis - dbAccount.note = account.note + dbAccount.note = account.note?.htmlValue dbAccount.url = account.url dbAccount.avatar = account.avatar dbAccount.header = account.header diff --git a/Vernissage/Views/UserProfileView/Subviews/UserProfileHeaderView.swift b/Vernissage/Views/UserProfileView/Subviews/UserProfileHeaderView.swift index e045006..c121b97 100644 --- a/Vernissage/Views/UserProfileView/Subviews/UserProfileHeaderView.swift +++ b/Vernissage/Views/UserProfileView/Subviews/UserProfileHeaderView.swift @@ -73,7 +73,7 @@ struct UserProfileHeaderView: View { } } - if let note = account.note, !note.isEmpty { + if let note = account.note, !note.asMarkdown.isEmpty { MarkdownFormattedText(note.asMarkdown, withFontSize: 14, andWidth: Int(UIScreen.main.bounds.width) - 16) .environment(\.openURL, OpenURLAction { url in routerPath.handle(url: url)