status content display

This commit is contained in:
sunxiaojian 2021-01-29 16:47:32 +08:00
parent cb690ffa4e
commit 24ca4644de
12 changed files with 144 additions and 8 deletions

View File

@ -10,6 +10,7 @@
<entity name="MastodonUser" representedClassName=".MastodonUser" syncable="YES">
<attribute name="acct" attributeType="String"/>
<attribute name="avatar" optional="YES" attributeType="String"/>
<attribute name="avatarStatic" optional="YES" attributeType="String"/>
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="displayName" optional="YES" attributeType="String"/>
<attribute name="domain" attributeType="String"/>
@ -32,7 +33,7 @@
</entity>
<elements>
<element name="HomeTimelineIndex" positionX="0" positionY="0" width="128" height="104"/>
<element name="MastodonUser" positionX="0" positionY="0" width="128" height="179"/>
<element name="MastodonUser" positionX="0" positionY="0" width="128" height="194"/>
<element name="Toot" positionX="0" positionY="0" width="128" height="164"/>
</elements>
</model>

View File

@ -18,6 +18,9 @@ final public class MastodonUser: NSManagedObject {
@NSManaged public private(set) var acct: String
@NSManaged public private(set) var username: String
@NSManaged public private(set) var displayName: String?
@NSManaged public private(set) var avatar: String
@NSManaged public private(set) var avatarStatic: String
@NSManaged public private(set) var createdAt: Date
@NSManaged public private(set) var updatedAt: Date
@ -42,6 +45,8 @@ extension MastodonUser {
user.acct = property.acct
user.username = property.username
user.displayName = property.displayName
user.avatar = property.avatar
user.avatarStatic = property.avatarStatic
user.createdAt = property.createdAt
user.updatedAt = property.networkDate
@ -60,6 +65,8 @@ extension MastodonUser {
public let acct: String
public let username: String
public let displayName: String?
public let avatar: String
public let avatarStatic: String
public let createdAt: Date
public let networkDate: Date
@ -70,6 +77,8 @@ extension MastodonUser {
acct: String,
username: String,
displayName: String?,
avatar:String,
avatarStatic:String,
createdAt: Date,
networkDate: Date
) {
@ -81,6 +90,8 @@ extension MastodonUser {
self.displayName = displayName.flatMap { displayName in
return displayName.isEmpty ? nil : displayName
}
self.avatar = avatar
self.avatarStatic = avatarStatic
self.createdAt = createdAt
self.networkDate = networkDate
}

View File

@ -22,6 +22,8 @@
2D76319F25C1521200929FB9 /* TimelineSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D76319E25C1521200929FB9 /* TimelineSection.swift */; };
2D7631A825C1535600929FB9 /* TimelinePostTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D7631A725C1535600929FB9 /* TimelinePostTableViewCell.swift */; };
2D7631B325C159F700929FB9 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D7631B225C159F700929FB9 /* Item.swift */; };
2D9BB87B25C3FEF200678AB6 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D9BB87A25C3FEF200678AB6 /* String.swift */; };
2DF123A725C3B0210020F248 /* ActiveLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DF123A625C3B0210020F248 /* ActiveLabel.swift */; };
3533495136D843E85211E3E2 /* Pods_Mastodon_MastodonUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1B4523A7981F1044DE89C21 /* Pods_Mastodon_MastodonUITests.framework */; };
5D526FE225BE9AC400460CB9 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 5D526FE125BE9AC400460CB9 /* MastodonSDK */; };
5E44BF88AD33646E64727BCF /* Pods_MastodonTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD92E0F10BDE4FE7C4B999F2 /* Pods_MastodonTests.framework */; };
@ -129,6 +131,8 @@
2D76319E25C1521200929FB9 /* TimelineSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineSection.swift; sourceTree = "<group>"; };
2D7631A725C1535600929FB9 /* TimelinePostTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinePostTableViewCell.swift; sourceTree = "<group>"; };
2D7631B225C159F700929FB9 /* Item.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Item.swift; sourceTree = "<group>"; };
2D9BB87A25C3FEF200678AB6 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
2DF123A625C3B0210020F248 /* ActiveLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveLabel.swift; sourceTree = "<group>"; };
2E1F6A67FDF9771D3E064FDC /* Pods-Mastodon.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.debug.xcconfig"; sourceTree = "<group>"; };
459EA4F43058CAB47719E963 /* Pods-Mastodon-MastodonUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.debug.xcconfig"; sourceTree = "<group>"; };
602D783BEC22881EBAD84419 /* Pods_Mastodon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@ -532,6 +536,8 @@
DB8AF55C25C138B7002E6C99 /* UIViewController.swift */,
2D46975D25C2A54100CF4AA9 /* NSLayoutConstraint.swift */,
2D46976325C2A71500CF4AA9 /* UIIamge.swift */,
2DF123A625C3B0210020F248 /* ActiveLabel.swift */,
2D9BB87A25C3FEF200678AB6 /* String.swift */,
);
path = Extension;
sourceTree = "<group>";
@ -664,6 +670,7 @@
TargetAttributes = {
DB427DD125BAA00100D1B89D = {
CreatedOnToolsVersion = 12.4;
LastSwiftMigration = 1220;
};
DB427DE725BAA00100D1B89D = {
CreatedOnToolsVersion = 12.4;
@ -879,9 +886,11 @@
2D7631B325C159F700929FB9 /* Item.swift in Sources */,
2D61335E25C1894B00CAE157 /* APIService.swift in Sources */,
DB8AF53025C13561002E6C99 /* AppContext.swift in Sources */,
2D9BB87B25C3FEF200678AB6 /* String.swift in Sources */,
2D152A8C25C295CC009AA50C /* TimelinePostView.swift in Sources */,
2D61335825C188A000CAE157 /* APIService+Persist+Timeline.swift in Sources */,
DB8AF52F25C13561002E6C99 /* DocumentStore.swift in Sources */,
2DF123A725C3B0210020F248 /* ActiveLabel.swift in Sources */,
2D76316B25C14D4C00929FB9 /* PublicTimelineViewModel.swift in Sources */,
2D46975E25C2A54100CF4AA9 /* NSLayoutConstraint.swift in Sources */,
2D46976425C2A71500CF4AA9 /* UIIamge.swift in Sources */,
@ -1126,6 +1135,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 7LFDZ96332;
@ -1137,6 +1147,7 @@
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.Mastodon;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
@ -1148,6 +1159,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 7LFDZ96332;

View File

@ -47,7 +47,8 @@ extension TimelineSection {
) {
cell.timelinePostView.nameLabel.text = toot.author.displayName
cell.timelinePostView.usernameLabel.text = toot.author.username
cell.timelinePostView.avatarImageView.af.setImage(withURL: URL(string: toot.author.avatar)!)
cell.timelinePostView.activeTextLabel.config(content: toot.content)
}
}

View File

@ -0,0 +1,48 @@
//
// ActiveLabel.swift
// Mastodon
//
// Created by sxiaojian on 2021/1/29.
//
import UIKit
import Foundation
import ActiveLabel
extension ActiveLabel {
enum Style {
case `default`
case timelineHeaderView
}
convenience init(style: Style) {
self.init()
switch style {
case .default:
// urlMaximumLength = 30
font = .preferredFont(forTextStyle: .body)
textColor = UIColor.label.withAlphaComponent(0.8)
case .timelineHeaderView:
font = .preferredFont(forTextStyle: .footnote)
textColor = .secondaryLabel
}
numberOfLines = 0
mentionColor = UIColor.yellow
hashtagColor = UIColor.blue
URLColor = UIColor.red
text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
}
}
extension ActiveLabel {
func config(content:String) {
let html = content.replacingOccurrences(of: "</p><p>", with: "<br /><br />").replacingOccurrences(of: "<p>", with: "").replacingOccurrences(of: "</p>", with: "")
text = html.toPlainText()
}
}

View File

@ -0,0 +1,39 @@
//
// String.swift
// Mastodon
//
// Created by sxiaojian on 2021/1/29.
//
import Foundation
extension String {
public func pregReplace(pattern: String, with: String, options: NSRegularExpression.Options = []) -> String {
// swiftlint:disable force_try
let regex = try! NSRegularExpression(pattern: pattern, options: options)
return regex.stringByReplacingMatches(in: self, options: [], range: NSRange(location: 0, length: nsLength), withTemplate: with)
}
}
extension String {
public var nsLength: Int {
let string_NS = self as NSString
return string_NS.length
}
}
extension String {
func toPlainText() -> String {
return self.pregReplace(pattern: "<br.+?>", with: "\n")
.replacingOccurrences(of: "</p><p>", with: "\n\n")
.pregReplace(pattern: "<.+?>", with: "")
.replacingOccurrences(of: "&lt;", with: "<")
.replacingOccurrences(of: "&gt;", with: ">")
.replacingOccurrences(of: "&apos;", with: "'")
.replacingOccurrences(of: "&quot;", with: "\"")
.replacingOccurrences(of: "&amp;", with: "&")
}
}
extension String {
func string(in nsrange: NSRange) -> String? {
guard let range = Range(nsrange, in: self) else { return nil }
return String(self[range])
}
}

View File

@ -22,6 +22,6 @@ extension HomeViewController {
title = "Home"
view.backgroundColor = .systemBackground
}
}

View File

@ -7,6 +7,7 @@
import UIKit
import AVKit
import ActiveLabel
final class TimelinePostView: UIView {
@ -41,6 +42,7 @@ final class TimelinePostView: UIView {
let mainContainerStackView = UIStackView()
let activeTextLabel = ActiveLabel(style: .default)
override init(frame: CGRect) {
super.init(frame: frame)
@ -107,6 +109,15 @@ extension TimelinePostView {
usernameLabel.setContentCompressionResistancePriority(.defaultHigh - 1, for: .horizontal)
dateLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
dateLabel.setContentCompressionResistancePriority(.required - 2, for: .horizontal)
// main container: [text | image / video | quote | geo]
tweetContainerStackView.addArrangedSubview(mainContainerStackView)
mainContainerStackView.axis = .vertical
mainContainerStackView.spacing = 8
activeTextLabel.translatesAutoresizingMaskIntoConstraints = false
mainContainerStackView.addArrangedSubview(activeTextLabel)
activeTextLabel.setContentCompressionResistancePriority(.required - 2, for: .vertical)
}

View File

@ -25,7 +25,7 @@ extension APIService.Persist {
return managedObjectContext.performChanges {
let toots = response.value
let _ = toots.map {
let userProperty = MastodonUser.Property(id: $0.account.id, domain: domain, acct: $0.account.acct, username: $0.account.username, displayName: $0.account.displayName, createdAt: $0.createdAt, networkDate: $0.createdAt)
let userProperty = MastodonUser.Property(id: $0.account.id, domain: domain, acct: $0.account.acct, username: $0.account.username, displayName: $0.account.displayName,avatar: $0.account.avatar,avatarStatic: $0.account.avatarStatic, createdAt: $0.createdAt, networkDate: $0.createdAt)
let author = MastodonUser.insert(into: managedObjectContext, property: userProperty)
let tootProperty = Toot.Property(id: $0.id, domain: domain, content: $0.content, createdAt: $0.createdAt, networkDate: $0.createdAt)
Toot.insert(into: managedObjectContext, property: tootProperty, author: author)

View File

@ -34,9 +34,9 @@ extension Mastodon.Entity {
public let displayName: String
public let note: String
public let avatar: String
public let avatarStatic: String?
public let avatarStatic: String
public let header: String
public let headerStatic: String?
public let headerStatic: String
public let locked: Bool
public let emojis: [Emoji]?
public let discoverable: Bool?

View File

@ -9,7 +9,7 @@ target 'Mastodon' do
# misc
pod 'SwiftGen', '~> 6.4.0'
pod 'DateToolsSwift', '~> 5.0.0'
pod 'ActiveLabel', git: 'https://github.com/ReticentJohn/ActiveLabel.swift.git', branch: 'master'
target 'MastodonTests' do
inherit! :search_paths
# Pods for testing

View File

@ -1,8 +1,10 @@
PODS:
- ActiveLabel (1.1.0)
- DateToolsSwift (5.0.0)
- SwiftGen (6.4.0)
DEPENDENCIES:
- ActiveLabel (from `https://github.com/ReticentJohn/ActiveLabel.swift.git`, branch `master`)
- DateToolsSwift (~> 5.0.0)
- SwiftGen (~> 6.4.0)
@ -11,10 +13,21 @@ SPEC REPOS:
- DateToolsSwift
- SwiftGen
EXTERNAL SOURCES:
ActiveLabel:
:branch: master
:git: https://github.com/ReticentJohn/ActiveLabel.swift.git
CHECKOUT OPTIONS:
ActiveLabel:
:commit: 01dd31cbbd1b3fec33b0c024b011e6b932794eff
:git: https://github.com/ReticentJohn/ActiveLabel.swift.git
SPEC CHECKSUMS:
ActiveLabel: 5e3f4de79a1952d4604b845a0610d4776e4b82b3
DateToolsSwift: 4207ada6ad615d8dc076323d27037c94916dbfa6
SwiftGen: 67860cc7c3cfc2ed25b9b74cfd55495fc89f9108
PODFILE CHECKSUM: 5a58ccfd113912468e008313e1c91ed51b7cba20
PODFILE CHECKSUM: 7fd5233d3180e2f7f67c96a28abbc20c6eddac93
COCOAPODS: 1.10.1