feat: display custom emoji for timeline post
This commit is contained in:
parent
8409331dd8
commit
faeb8d99ef
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="18154" systemVersion="20D75" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="18154" systemVersion="20E232" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||||
<entity name="Application" representedClassName=".Application" syncable="YES">
|
<entity name="Application" representedClassName=".Application" syncable="YES">
|
||||||
<attribute name="identifier" optional="YES" attributeType="UUID" usesScalarValueType="NO"/>
|
<attribute name="identifier" optional="YES" attributeType="UUID" usesScalarValueType="NO"/>
|
||||||
<attribute name="name" attributeType="String"/>
|
<attribute name="name" attributeType="String"/>
|
||||||
|
@ -45,7 +45,6 @@
|
||||||
<attribute name="staticURL" attributeType="String"/>
|
<attribute name="staticURL" attributeType="String"/>
|
||||||
<attribute name="url" attributeType="String"/>
|
<attribute name="url" attributeType="String"/>
|
||||||
<attribute name="visibleInPicker" attributeType="Boolean" usesScalarValueType="YES"/>
|
<attribute name="visibleInPicker" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||||
<relationship name="status" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Status" inverseName="emojis" inverseEntity="Status"/>
|
|
||||||
</entity>
|
</entity>
|
||||||
<entity name="History" representedClassName=".History" syncable="YES">
|
<entity name="History" representedClassName=".History" syncable="YES">
|
||||||
<attribute name="accounts" optional="YES" attributeType="String"/>
|
<attribute name="accounts" optional="YES" attributeType="String"/>
|
||||||
|
@ -102,6 +101,7 @@
|
||||||
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
|
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
|
||||||
<attribute name="displayName" attributeType="String"/>
|
<attribute name="displayName" attributeType="String"/>
|
||||||
<attribute name="domain" attributeType="String"/>
|
<attribute name="domain" attributeType="String"/>
|
||||||
|
<attribute name="emojisData" optional="YES" attributeType="Binary"/>
|
||||||
<attribute name="followersCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
<attribute name="followersCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
<attribute name="followingCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
<attribute name="followingCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
<attribute name="header" attributeType="String"/>
|
<attribute name="header" attributeType="String"/>
|
||||||
|
@ -197,6 +197,7 @@
|
||||||
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
|
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
|
||||||
<attribute name="deletedAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
<attribute name="deletedAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||||
<attribute name="domain" attributeType="String"/>
|
<attribute name="domain" attributeType="String"/>
|
||||||
|
<attribute name="emojisData" optional="YES" attributeType="Binary"/>
|
||||||
<attribute name="favouritesCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
<attribute name="favouritesCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
<attribute name="id" attributeType="String"/>
|
<attribute name="id" attributeType="String"/>
|
||||||
<attribute name="identifier" attributeType="String"/>
|
<attribute name="identifier" attributeType="String"/>
|
||||||
|
@ -216,7 +217,6 @@
|
||||||
<relationship name="application" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Application" inverseName="status" inverseEntity="Application"/>
|
<relationship name="application" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Application" inverseName="status" inverseEntity="Application"/>
|
||||||
<relationship name="author" maxCount="1" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="statuses" inverseEntity="MastodonUser"/>
|
<relationship name="author" maxCount="1" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="statuses" inverseEntity="MastodonUser"/>
|
||||||
<relationship name="bookmarkedBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="bookmarked" inverseEntity="MastodonUser"/>
|
<relationship name="bookmarkedBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="bookmarked" inverseEntity="MastodonUser"/>
|
||||||
<relationship name="emojis" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Emoji" inverseName="status" inverseEntity="Emoji"/>
|
|
||||||
<relationship name="favouritedBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="favourite" inverseEntity="MastodonUser"/>
|
<relationship name="favouritedBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="favourite" inverseEntity="MastodonUser"/>
|
||||||
<relationship name="homeTimelineIndexes" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="HomeTimelineIndex" inverseName="status" inverseEntity="HomeTimelineIndex"/>
|
<relationship name="homeTimelineIndexes" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="HomeTimelineIndex" inverseName="status" inverseEntity="HomeTimelineIndex"/>
|
||||||
<relationship name="mediaAttachments" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Attachment" inverseName="status" inverseEntity="Attachment"/>
|
<relationship name="mediaAttachments" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Attachment" inverseName="status" inverseEntity="Attachment"/>
|
||||||
|
@ -267,12 +267,12 @@
|
||||||
<element name="Application" positionX="0" positionY="0" width="128" height="104"/>
|
<element name="Application" positionX="0" positionY="0" width="128" height="104"/>
|
||||||
<element name="Attachment" positionX="0" positionY="0" width="128" height="254"/>
|
<element name="Attachment" positionX="0" positionY="0" width="128" height="254"/>
|
||||||
<element name="DomainBlock" positionX="45" positionY="162" width="128" height="89"/>
|
<element name="DomainBlock" positionX="45" positionY="162" width="128" height="89"/>
|
||||||
<element name="Emoji" positionX="0" positionY="0" width="128" height="149"/>
|
<element name="Emoji" positionX="0" positionY="0" width="128" height="134"/>
|
||||||
<element name="History" positionX="0" positionY="0" width="128" height="119"/>
|
<element name="History" positionX="0" positionY="0" width="128" height="119"/>
|
||||||
<element name="HomeTimelineIndex" positionX="0" positionY="0" width="128" height="134"/>
|
<element name="HomeTimelineIndex" positionX="0" positionY="0" width="128" height="134"/>
|
||||||
<element name="MastodonAuthentication" positionX="0" positionY="0" width="128" height="209"/>
|
<element name="MastodonAuthentication" positionX="0" positionY="0" width="128" height="209"/>
|
||||||
<element name="MastodonNotification" positionX="9" positionY="162" width="128" height="164"/>
|
<element name="MastodonNotification" positionX="9" positionY="162" width="128" height="164"/>
|
||||||
<element name="MastodonUser" positionX="0" positionY="0" width="128" height="659"/>
|
<element name="MastodonUser" positionX="0" positionY="0" width="128" height="689"/>
|
||||||
<element name="Mention" positionX="0" positionY="0" width="128" height="149"/>
|
<element name="Mention" positionX="0" positionY="0" width="128" height="149"/>
|
||||||
<element name="Poll" positionX="0" positionY="0" width="128" height="194"/>
|
<element name="Poll" positionX="0" positionY="0" width="128" height="194"/>
|
||||||
<element name="PollOption" positionX="0" positionY="0" width="128" height="134"/>
|
<element name="PollOption" positionX="0" positionY="0" width="128" height="134"/>
|
||||||
|
|
|
@ -25,6 +25,9 @@ final public class MastodonUser: NSManagedObject {
|
||||||
@NSManaged public private(set) var headerStatic: String?
|
@NSManaged public private(set) var headerStatic: String?
|
||||||
@NSManaged public private(set) var note: String?
|
@NSManaged public private(set) var note: String?
|
||||||
@NSManaged public private(set) var url: String?
|
@NSManaged public private(set) var url: String?
|
||||||
|
|
||||||
|
@NSManaged public private(set) var emojisData: Data?
|
||||||
|
|
||||||
@NSManaged public private(set) var statusesCount: NSNumber
|
@NSManaged public private(set) var statusesCount: NSNumber
|
||||||
@NSManaged public private(set) var followingCount: NSNumber
|
@NSManaged public private(set) var followingCount: NSNumber
|
||||||
@NSManaged public private(set) var followersCount: NSNumber
|
@NSManaged public private(set) var followersCount: NSNumber
|
||||||
|
@ -88,6 +91,8 @@ extension MastodonUser {
|
||||||
user.headerStatic = property.headerStatic
|
user.headerStatic = property.headerStatic
|
||||||
user.note = property.note
|
user.note = property.note
|
||||||
user.url = property.url
|
user.url = property.url
|
||||||
|
user.emojisData = property.emojisData
|
||||||
|
|
||||||
user.statusesCount = NSNumber(value: property.statusesCount)
|
user.statusesCount = NSNumber(value: property.statusesCount)
|
||||||
user.followingCount = NSNumber(value: property.followingCount)
|
user.followingCount = NSNumber(value: property.followingCount)
|
||||||
user.followersCount = NSNumber(value: property.followersCount)
|
user.followersCount = NSNumber(value: property.followersCount)
|
||||||
|
@ -151,6 +156,11 @@ extension MastodonUser {
|
||||||
self.url = url
|
self.url = url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public func update(emojisData: Data?) {
|
||||||
|
if self.emojisData != emojisData {
|
||||||
|
self.emojisData = emojisData
|
||||||
|
}
|
||||||
|
}
|
||||||
public func update(statusesCount: Int) {
|
public func update(statusesCount: Int) {
|
||||||
if self.statusesCount.intValue != statusesCount {
|
if self.statusesCount.intValue != statusesCount {
|
||||||
self.statusesCount = NSNumber(value: statusesCount)
|
self.statusesCount = NSNumber(value: statusesCount)
|
||||||
|
@ -270,6 +280,7 @@ extension MastodonUser {
|
||||||
public let headerStatic: String?
|
public let headerStatic: String?
|
||||||
public let note: String?
|
public let note: String?
|
||||||
public let url: String?
|
public let url: String?
|
||||||
|
public let emojisData: Data?
|
||||||
public let statusesCount: Int
|
public let statusesCount: Int
|
||||||
public let followingCount: Int
|
public let followingCount: Int
|
||||||
public let followersCount: Int
|
public let followersCount: Int
|
||||||
|
@ -292,6 +303,7 @@ extension MastodonUser {
|
||||||
headerStatic: String?,
|
headerStatic: String?,
|
||||||
note: String?,
|
note: String?,
|
||||||
url: String?,
|
url: String?,
|
||||||
|
emojisData: Data?,
|
||||||
statusesCount: Int,
|
statusesCount: Int,
|
||||||
followingCount: Int,
|
followingCount: Int,
|
||||||
followersCount: Int,
|
followersCount: Int,
|
||||||
|
@ -313,6 +325,7 @@ extension MastodonUser {
|
||||||
self.headerStatic = headerStatic
|
self.headerStatic = headerStatic
|
||||||
self.note = note
|
self.note = note
|
||||||
self.url = url
|
self.url = url
|
||||||
|
self.emojisData = emojisData
|
||||||
self.statusesCount = statusesCount
|
self.statusesCount = statusesCount
|
||||||
self.followingCount = followingCount
|
self.followingCount = followingCount
|
||||||
self.followersCount = followersCount
|
self.followersCount = followersCount
|
||||||
|
|
|
@ -24,6 +24,8 @@ public final class Status: NSManagedObject {
|
||||||
@NSManaged public private(set) var spoilerText: String?
|
@NSManaged public private(set) var spoilerText: String?
|
||||||
@NSManaged public private(set) var application: Application?
|
@NSManaged public private(set) var application: Application?
|
||||||
|
|
||||||
|
@NSManaged public private(set) var emojisData: Data?
|
||||||
|
|
||||||
// Informational
|
// Informational
|
||||||
@NSManaged public private(set) var reblogsCount: NSNumber
|
@NSManaged public private(set) var reblogsCount: NSNumber
|
||||||
@NSManaged public private(set) var favouritesCount: NSNumber
|
@NSManaged public private(set) var favouritesCount: NSNumber
|
||||||
|
@ -54,7 +56,6 @@ public final class Status: NSManagedObject {
|
||||||
// one-to-many relationship
|
// one-to-many relationship
|
||||||
@NSManaged public private(set) var reblogFrom: Set<Status>?
|
@NSManaged public private(set) var reblogFrom: Set<Status>?
|
||||||
@NSManaged public private(set) var mentions: Set<Mention>?
|
@NSManaged public private(set) var mentions: Set<Mention>?
|
||||||
@NSManaged public private(set) var emojis: Set<Emoji>?
|
|
||||||
@NSManaged public private(set) var tags: Set<Tag>?
|
@NSManaged public private(set) var tags: Set<Tag>?
|
||||||
@NSManaged public private(set) var homeTimelineIndexes: Set<HomeTimelineIndex>?
|
@NSManaged public private(set) var homeTimelineIndexes: Set<HomeTimelineIndex>?
|
||||||
@NSManaged public private(set) var mediaAttachments: Set<Attachment>?
|
@NSManaged public private(set) var mediaAttachments: Set<Attachment>?
|
||||||
|
@ -77,7 +78,6 @@ extension Status {
|
||||||
replyTo: Status?,
|
replyTo: Status?,
|
||||||
poll: Poll?,
|
poll: Poll?,
|
||||||
mentions: [Mention]?,
|
mentions: [Mention]?,
|
||||||
emojis: [Emoji]?,
|
|
||||||
tags: [Tag]?,
|
tags: [Tag]?,
|
||||||
mediaAttachments: [Attachment]?,
|
mediaAttachments: [Attachment]?,
|
||||||
favouritedBy: MastodonUser?,
|
favouritedBy: MastodonUser?,
|
||||||
|
@ -101,6 +101,8 @@ extension Status {
|
||||||
status.spoilerText = property.spoilerText
|
status.spoilerText = property.spoilerText
|
||||||
status.application = application
|
status.application = application
|
||||||
|
|
||||||
|
status.emojisData = property.emojisData
|
||||||
|
|
||||||
status.reblogsCount = property.reblogsCount
|
status.reblogsCount = property.reblogsCount
|
||||||
status.favouritesCount = property.favouritesCount
|
status.favouritesCount = property.favouritesCount
|
||||||
status.repliesCount = property.repliesCount
|
status.repliesCount = property.repliesCount
|
||||||
|
@ -121,9 +123,6 @@ extension Status {
|
||||||
if let mentions = mentions {
|
if let mentions = mentions {
|
||||||
status.mutableSetValue(forKey: #keyPath(Status.mentions)).addObjects(from: mentions)
|
status.mutableSetValue(forKey: #keyPath(Status.mentions)).addObjects(from: mentions)
|
||||||
}
|
}
|
||||||
if let emojis = emojis {
|
|
||||||
status.mutableSetValue(forKey: #keyPath(Status.emojis)).addObjects(from: emojis)
|
|
||||||
}
|
|
||||||
if let tags = tags {
|
if let tags = tags {
|
||||||
status.mutableSetValue(forKey: #keyPath(Status.tags)).addObjects(from: tags)
|
status.mutableSetValue(forKey: #keyPath(Status.tags)).addObjects(from: tags)
|
||||||
}
|
}
|
||||||
|
@ -148,6 +147,12 @@ extension Status {
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func update(emojisData: Data?) {
|
||||||
|
if self.emojisData != emojisData {
|
||||||
|
self.emojisData = emojisData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func update(reblogsCount: NSNumber) {
|
public func update(reblogsCount: NSNumber) {
|
||||||
if self.reblogsCount.intValue != reblogsCount.intValue {
|
if self.reblogsCount.intValue != reblogsCount.intValue {
|
||||||
self.reblogsCount = reblogsCount
|
self.reblogsCount = reblogsCount
|
||||||
|
@ -248,6 +253,8 @@ extension Status {
|
||||||
public let sensitive: Bool
|
public let sensitive: Bool
|
||||||
public let spoilerText: String?
|
public let spoilerText: String?
|
||||||
|
|
||||||
|
public let emojisData: Data?
|
||||||
|
|
||||||
public let reblogsCount: NSNumber
|
public let reblogsCount: NSNumber
|
||||||
public let favouritesCount: NSNumber
|
public let favouritesCount: NSNumber
|
||||||
public let repliesCount: NSNumber?
|
public let repliesCount: NSNumber?
|
||||||
|
@ -269,6 +276,7 @@ extension Status {
|
||||||
visibility: String?,
|
visibility: String?,
|
||||||
sensitive: Bool,
|
sensitive: Bool,
|
||||||
spoilerText: String?,
|
spoilerText: String?,
|
||||||
|
emojisData: Data?,
|
||||||
reblogsCount: NSNumber,
|
reblogsCount: NSNumber,
|
||||||
favouritesCount: NSNumber,
|
favouritesCount: NSNumber,
|
||||||
repliesCount: NSNumber?,
|
repliesCount: NSNumber?,
|
||||||
|
@ -288,6 +296,7 @@ extension Status {
|
||||||
self.visibility = visibility
|
self.visibility = visibility
|
||||||
self.sensitive = sensitive
|
self.sensitive = sensitive
|
||||||
self.spoilerText = spoilerText
|
self.spoilerText = spoilerText
|
||||||
|
self.emojisData = emojisData
|
||||||
self.reblogsCount = reblogsCount
|
self.reblogsCount = reblogsCount
|
||||||
self.favouritesCount = favouritesCount
|
self.favouritesCount = favouritesCount
|
||||||
self.repliesCount = repliesCount
|
self.repliesCount = repliesCount
|
||||||
|
|
|
@ -400,6 +400,7 @@
|
||||||
DBAE3F9E2616E308004B8251 /* APIService+Mute.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAE3F9D2616E308004B8251 /* APIService+Mute.swift */; };
|
DBAE3F9E2616E308004B8251 /* APIService+Mute.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAE3F9D2616E308004B8251 /* APIService+Mute.swift */; };
|
||||||
DBAE3FA92617106E004B8251 /* MastodonMetricFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAE3FA82617106E004B8251 /* MastodonMetricFormatter.swift */; };
|
DBAE3FA92617106E004B8251 /* MastodonMetricFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAE3FA82617106E004B8251 /* MastodonMetricFormatter.swift */; };
|
||||||
DBAE3FAF26172FC0004B8251 /* RemoteProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAE3FAE26172FC0004B8251 /* RemoteProfileViewModel.swift */; };
|
DBAE3FAF26172FC0004B8251 /* RemoteProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAE3FAE26172FC0004B8251 /* RemoteProfileViewModel.swift */; };
|
||||||
|
DBAFB7352645463500371D5F /* Emojis.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAFB7342645463500371D5F /* Emojis.swift */; };
|
||||||
DBB525082611EAC0002F1F29 /* Tabman in Frameworks */ = {isa = PBXBuildFile; productRef = DBB525072611EAC0002F1F29 /* Tabman */; };
|
DBB525082611EAC0002F1F29 /* Tabman in Frameworks */ = {isa = PBXBuildFile; productRef = DBB525072611EAC0002F1F29 /* Tabman */; };
|
||||||
DBB5250E2611EBAF002F1F29 /* ProfileSegmentedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB5250D2611EBAF002F1F29 /* ProfileSegmentedViewController.swift */; };
|
DBB5250E2611EBAF002F1F29 /* ProfileSegmentedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB5250D2611EBAF002F1F29 /* ProfileSegmentedViewController.swift */; };
|
||||||
DBB525212611EBD6002F1F29 /* ProfilePagingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB525202611EBD6002F1F29 /* ProfilePagingViewController.swift */; };
|
DBB525212611EBD6002F1F29 /* ProfilePagingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB525202611EBD6002F1F29 /* ProfilePagingViewController.swift */; };
|
||||||
|
@ -962,6 +963,7 @@
|
||||||
DBAE3F9D2616E308004B8251 /* APIService+Mute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Mute.swift"; sourceTree = "<group>"; };
|
DBAE3F9D2616E308004B8251 /* APIService+Mute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Mute.swift"; sourceTree = "<group>"; };
|
||||||
DBAE3FA82617106E004B8251 /* MastodonMetricFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonMetricFormatter.swift; sourceTree = "<group>"; };
|
DBAE3FA82617106E004B8251 /* MastodonMetricFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonMetricFormatter.swift; sourceTree = "<group>"; };
|
||||||
DBAE3FAE26172FC0004B8251 /* RemoteProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteProfileViewModel.swift; sourceTree = "<group>"; };
|
DBAE3FAE26172FC0004B8251 /* RemoteProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteProfileViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
DBAFB7342645463500371D5F /* Emojis.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Emojis.swift; sourceTree = "<group>"; };
|
||||||
DBB5250D2611EBAF002F1F29 /* ProfileSegmentedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSegmentedViewController.swift; sourceTree = "<group>"; };
|
DBB5250D2611EBAF002F1F29 /* ProfileSegmentedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSegmentedViewController.swift; sourceTree = "<group>"; };
|
||||||
DBB525202611EBD6002F1F29 /* ProfilePagingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePagingViewController.swift; sourceTree = "<group>"; };
|
DBB525202611EBD6002F1F29 /* ProfilePagingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePagingViewController.swift; sourceTree = "<group>"; };
|
||||||
DBB5252F2611EBF3002F1F29 /* ProfilePagingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePagingViewModel.swift; sourceTree = "<group>"; };
|
DBB5252F2611EBF3002F1F29 /* ProfilePagingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePagingViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1594,6 +1596,7 @@
|
||||||
DB6D9F6E2635807F008423CD /* Setting.swift */,
|
DB6D9F6E2635807F008423CD /* Setting.swift */,
|
||||||
DB6D9F4826353FD6008423CD /* Subscription.swift */,
|
DB6D9F4826353FD6008423CD /* Subscription.swift */,
|
||||||
DB6D9F4F2635761F008423CD /* SubscriptionAlerts.swift */,
|
DB6D9F4F2635761F008423CD /* SubscriptionAlerts.swift */,
|
||||||
|
DBAFB7342645463500371D5F /* Emojis.swift */,
|
||||||
);
|
);
|
||||||
path = CoreDataStack;
|
path = CoreDataStack;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -3199,6 +3202,7 @@
|
||||||
DB6180ED26391C6C0018D199 /* TransitioningMath.swift in Sources */,
|
DB6180ED26391C6C0018D199 /* TransitioningMath.swift in Sources */,
|
||||||
2D6DE40026141DF600A63F6A /* SearchViewModel.swift in Sources */,
|
2D6DE40026141DF600A63F6A /* SearchViewModel.swift in Sources */,
|
||||||
DB51D172262832380062B7A1 /* BlurHashDecode.swift in Sources */,
|
DB51D172262832380062B7A1 /* BlurHashDecode.swift in Sources */,
|
||||||
|
DBAFB7352645463500371D5F /* Emojis.swift in Sources */,
|
||||||
DBCC3B89261454BA0045B23D /* CGImage.swift in Sources */,
|
DBCC3B89261454BA0045B23D /* CGImage.swift in Sources */,
|
||||||
DBCCC71E25F73297007E1AB6 /* APIService+Reblog.swift in Sources */,
|
DBCCC71E25F73297007E1AB6 /* APIService+Reblog.swift in Sources */,
|
||||||
DB789A2B25F9F7AB0071ACA0 /* ComposeRepliedToStatusContentCollectionViewCell.swift in Sources */,
|
DB789A2B25F9F7AB0071ACA0 /* ComposeRepliedToStatusContentCollectionViewCell.swift in Sources */,
|
||||||
|
@ -3913,8 +3917,8 @@
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/TwidereProject/ActiveLabel.swift";
|
repositoryURL = "https://github.com/TwidereProject/ActiveLabel.swift";
|
||||||
requirement = {
|
requirement = {
|
||||||
kind = upToNextMajorVersion;
|
kind = exactVersion;
|
||||||
minimumVersion = 4.0.0;
|
version = 5.0.1;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */ = {
|
2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */ = {
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
"repositoryURL": "https://github.com/TwidereProject/ActiveLabel.swift",
|
"repositoryURL": "https://github.com/TwidereProject/ActiveLabel.swift",
|
||||||
"state": {
|
"state": {
|
||||||
"branch": null,
|
"branch": null,
|
||||||
"revision": "d6cf96e0ca4f2269021bcf8f11381ab57897f84a",
|
"revision": "40e104063d825d1125ef4b8eeb6460eba8a57483",
|
||||||
"version": "4.0.0"
|
"version": "5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -68,7 +68,8 @@ extension ComposeStatusSection {
|
||||||
}()
|
}()
|
||||||
cell.statusView.usernameLabel.text = "@" + (status.reblog ?? status).author.acct
|
cell.statusView.usernameLabel.text = "@" + (status.reblog ?? status).author.acct
|
||||||
// set text
|
// set text
|
||||||
cell.statusView.activeTextLabel.configure(content: status.content)
|
//status.emoji
|
||||||
|
cell.statusView.activeTextLabel.configure(content: status.content, emojiDict: [:])
|
||||||
// set date
|
// set date
|
||||||
cell.statusView.dateLabel.text = status.createdAt.shortTimeAgoSinceNow
|
cell.statusView.dateLabel.text = status.createdAt.shortTimeAgoSinceNow
|
||||||
|
|
||||||
|
|
|
@ -158,10 +158,11 @@ extension StatusSection {
|
||||||
.store(in: &cell.disposeBag)
|
.store(in: &cell.disposeBag)
|
||||||
|
|
||||||
// set name username
|
// set name username
|
||||||
cell.statusView.nameLabel.text = {
|
let nameText: String = {
|
||||||
let author = (status.reblog ?? status).author
|
let author = (status.reblog ?? status).author
|
||||||
return author.displayName.isEmpty ? author.username : author.displayName
|
return author.displayName.isEmpty ? author.username : author.displayName
|
||||||
}()
|
}()
|
||||||
|
cell.statusView.nameLabel.configure(content: nameText, emojiDict: (status.reblog ?? status).author.emojiDict)
|
||||||
cell.statusView.usernameLabel.text = "@" + (status.reblog ?? status).author.acct
|
cell.statusView.usernameLabel.text = "@" + (status.reblog ?? status).author.acct
|
||||||
// set avatar
|
// set avatar
|
||||||
if let reblog = status.reblog {
|
if let reblog = status.reblog {
|
||||||
|
@ -176,7 +177,10 @@ extension StatusSection {
|
||||||
}
|
}
|
||||||
|
|
||||||
// set text
|
// set text
|
||||||
cell.statusView.activeTextLabel.configure(content: (status.reblog ?? status).content)
|
cell.statusView.activeTextLabel.configure(
|
||||||
|
content: (status.reblog ?? status).content,
|
||||||
|
emojiDict: (status.reblog ?? status).emojiDict
|
||||||
|
)
|
||||||
|
|
||||||
// prepare media attachments
|
// prepare media attachments
|
||||||
let mediaAttachments = Array((status.reblog ?? status).mediaAttachments ?? []).sorted { $0.index.compare($1.index) == .orderedAscending }
|
let mediaAttachments = Array((status.reblog ?? status).mediaAttachments ?? []).sorted { $0.index.compare($1.index) == .orderedAscending }
|
||||||
|
@ -569,15 +573,16 @@ extension StatusSection {
|
||||||
if status.reblog != nil {
|
if status.reblog != nil {
|
||||||
cell.statusView.headerContainerView.isHidden = false
|
cell.statusView.headerContainerView.isHidden = false
|
||||||
cell.statusView.headerIconLabel.attributedText = StatusView.iconAttributedString(image: StatusView.reblogIconImage)
|
cell.statusView.headerIconLabel.attributedText = StatusView.iconAttributedString(image: StatusView.reblogIconImage)
|
||||||
cell.statusView.headerInfoLabel.text = {
|
let headerText: String = {
|
||||||
let author = status.author
|
let author = status.author
|
||||||
let name = author.displayName.isEmpty ? author.username : author.displayName
|
let name = author.displayName.isEmpty ? author.username : author.displayName
|
||||||
return L10n.Common.Controls.Status.userReblogged(name)
|
return L10n.Common.Controls.Status.userReblogged(name)
|
||||||
}()
|
}()
|
||||||
|
cell.statusView.headerInfoLabel.configure(content: headerText, emojiDict: status.author.emojiDict)
|
||||||
} else if status.inReplyToID != nil {
|
} else if status.inReplyToID != nil {
|
||||||
cell.statusView.headerContainerView.isHidden = false
|
cell.statusView.headerContainerView.isHidden = false
|
||||||
cell.statusView.headerIconLabel.attributedText = StatusView.iconAttributedString(image: StatusView.replyIconImage)
|
cell.statusView.headerIconLabel.attributedText = StatusView.iconAttributedString(image: StatusView.replyIconImage)
|
||||||
cell.statusView.headerInfoLabel.text = {
|
let headerText: String = {
|
||||||
guard let replyTo = status.replyTo else {
|
guard let replyTo = status.replyTo else {
|
||||||
return L10n.Common.Controls.Status.userRepliedTo("-")
|
return L10n.Common.Controls.Status.userRepliedTo("-")
|
||||||
}
|
}
|
||||||
|
@ -585,6 +590,7 @@ extension StatusSection {
|
||||||
let name = author.displayName.isEmpty ? author.username : author.displayName
|
let name = author.displayName.isEmpty ? author.username : author.displayName
|
||||||
return L10n.Common.Controls.Status.userRepliedTo(name)
|
return L10n.Common.Controls.Status.userRepliedTo(name)
|
||||||
}()
|
}()
|
||||||
|
cell.statusView.headerInfoLabel.configure(content: headerText, emojiDict: status.replyTo?.author.emojiDict ?? [:])
|
||||||
} else {
|
} else {
|
||||||
cell.statusView.headerContainerView.isHidden = true
|
cell.statusView.headerContainerView.isHidden = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ extension ActiveLabel {
|
||||||
|
|
||||||
enum Style {
|
enum Style {
|
||||||
case `default`
|
case `default`
|
||||||
|
case statusHeader
|
||||||
|
case statusName
|
||||||
case profileField
|
case profileField
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +27,7 @@ extension ActiveLabel {
|
||||||
mentionColor = Asset.Colors.Label.highlight.color
|
mentionColor = Asset.Colors.Label.highlight.color
|
||||||
hashtagColor = Asset.Colors.Label.highlight.color
|
hashtagColor = Asset.Colors.Label.highlight.color
|
||||||
URLColor = Asset.Colors.Label.highlight.color
|
URLColor = Asset.Colors.Label.highlight.color
|
||||||
|
emojiPlaceholderColor = .systemFill
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
||||||
#endif
|
#endif
|
||||||
|
@ -33,6 +36,14 @@ extension ActiveLabel {
|
||||||
case .default:
|
case .default:
|
||||||
font = .preferredFont(forTextStyle: .body)
|
font = .preferredFont(forTextStyle: .body)
|
||||||
textColor = Asset.Colors.Label.primary.color
|
textColor = Asset.Colors.Label.primary.color
|
||||||
|
case .statusHeader:
|
||||||
|
font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .medium))
|
||||||
|
textColor = Asset.Colors.Label.secondary.color
|
||||||
|
numberOfLines = 1
|
||||||
|
case .statusName:
|
||||||
|
font = .systemFont(ofSize: 17, weight: .semibold)
|
||||||
|
textColor = Asset.Colors.Label.primary.color
|
||||||
|
numberOfLines = 1
|
||||||
case .profileField:
|
case .profileField:
|
||||||
font = .preferredFont(forTextStyle: .body)
|
font = .preferredFont(forTextStyle: .body)
|
||||||
textColor = Asset.Colors.Label.primary.color
|
textColor = Asset.Colors.Label.primary.color
|
||||||
|
@ -44,9 +55,10 @@ extension ActiveLabel {
|
||||||
|
|
||||||
extension ActiveLabel {
|
extension ActiveLabel {
|
||||||
/// status content
|
/// status content
|
||||||
func configure(content: String) {
|
func configure(content: String, emojiDict: MastodonStatusContent.EmojiDict) {
|
||||||
activeEntities.removeAll()
|
activeEntities.removeAll()
|
||||||
if let parseResult = try? MastodonStatusContent.parse(status: content) {
|
|
||||||
|
if let parseResult = try? MastodonStatusContent.parse(content: content, emojiDict: emojiDict) {
|
||||||
text = parseResult.trimmed
|
text = parseResult.trimmed
|
||||||
activeEntities = parseResult.activeEntities
|
activeEntities = parseResult.activeEntities
|
||||||
} else {
|
} else {
|
||||||
|
@ -55,8 +67,8 @@ extension ActiveLabel {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// account note
|
/// account note
|
||||||
func configure(note: String) {
|
func configure(note: String, emojiDict: MastodonStatusContent.EmojiDict) {
|
||||||
configure(content: note)
|
configure(content: note, emojiDict: emojiDict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
//
|
||||||
|
// Emojis.swift
|
||||||
|
// Mastodon
|
||||||
|
//
|
||||||
|
// Created by MainasuK Cirno on 2021-5-7.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import MastodonSDK
|
||||||
|
|
||||||
|
protocol EmojiContinaer {
|
||||||
|
var emojisData: Data? { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
extension EmojiContinaer {
|
||||||
|
|
||||||
|
static func encode(emojis: [Mastodon.Entity.Emoji]) -> Data? {
|
||||||
|
return try? JSONEncoder().encode(emojis)
|
||||||
|
}
|
||||||
|
|
||||||
|
var emojis: [Mastodon.Entity.Emoji]? {
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
return emojisData.flatMap { try? decoder.decode([Mastodon.Entity.Emoji].self, from: $0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
var emojiDict: MastodonStatusContent.EmojiDict {
|
||||||
|
var dict = MastodonStatusContent.EmojiDict()
|
||||||
|
for emoji in emojis ?? [] {
|
||||||
|
guard let url = URL(string: emoji.url) else { continue }
|
||||||
|
dict[emoji.shortcode] = url
|
||||||
|
}
|
||||||
|
return dict
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ extension MastodonUser.Property {
|
||||||
headerStatic: entity.headerStatic,
|
headerStatic: entity.headerStatic,
|
||||||
note: entity.note,
|
note: entity.note,
|
||||||
url: entity.url,
|
url: entity.url,
|
||||||
|
emojisData: entity.emojis.flatMap { Status.encode(emojis: $0) },
|
||||||
statusesCount: entity.statusesCount,
|
statusesCount: entity.statusesCount,
|
||||||
followingCount: entity.followingCount,
|
followingCount: entity.followingCount,
|
||||||
followersCount: entity.followersCount,
|
followersCount: entity.followersCount,
|
||||||
|
@ -98,3 +99,5 @@ extension MastodonUser {
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension MastodonUser: EmojiContinaer { }
|
||||||
|
|
|
@ -20,6 +20,7 @@ extension Status.Property {
|
||||||
visibility: entity.visibility?.rawValue,
|
visibility: entity.visibility?.rawValue,
|
||||||
sensitive: entity.sensitive ?? false,
|
sensitive: entity.sensitive ?? false,
|
||||||
spoilerText: entity.spoilerText,
|
spoilerText: entity.spoilerText,
|
||||||
|
emojisData: entity.emojis.flatMap { Status.encode(emojis: $0) },
|
||||||
reblogsCount: NSNumber(value: entity.reblogsCount),
|
reblogsCount: NSNumber(value: entity.reblogsCount),
|
||||||
favouritesCount: NSNumber(value: entity.favouritesCount),
|
favouritesCount: NSNumber(value: entity.favouritesCount),
|
||||||
repliesCount: entity.repliesCount.flatMap { NSNumber(value: $0) },
|
repliesCount: entity.repliesCount.flatMap { NSNumber(value: $0) },
|
||||||
|
@ -86,3 +87,5 @@ extension Status {
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Status: EmojiContinaer { }
|
||||||
|
|
|
@ -11,9 +11,21 @@ import ActiveLabel
|
||||||
|
|
||||||
enum MastodonStatusContent {
|
enum MastodonStatusContent {
|
||||||
|
|
||||||
static func parse(status: String) throws -> MastodonStatusContent.ParseResult {
|
typealias EmojiShortcode = String
|
||||||
let status = status.replacingOccurrences(of: "<br/>", with: "\n")
|
typealias EmojiDict = [EmojiShortcode: URL]
|
||||||
let rootNode = try Node.parse(document: status)
|
|
||||||
|
static func parse(content: String, emojiDict: EmojiDict) throws -> MastodonStatusContent.ParseResult {
|
||||||
|
let document: String = {
|
||||||
|
var content = content
|
||||||
|
content = content.replacingOccurrences(of: "<br/>", with: "\n")
|
||||||
|
for (shortcode, url) in emojiDict {
|
||||||
|
let emojiNode = "<span class=\"emoji\" href=\"\(url.absoluteString)\">\(shortcode)</span>"
|
||||||
|
let pattern = ":\(shortcode):"
|
||||||
|
content = content.replacingOccurrences(of: pattern, with: emojiNode)
|
||||||
|
}
|
||||||
|
return content
|
||||||
|
}()
|
||||||
|
let rootNode = try Node.parse(document: document)
|
||||||
let text = String(rootNode.text)
|
let text = String(rootNode.text)
|
||||||
|
|
||||||
var activeEntities: [ActiveEntity] = []
|
var activeEntities: [ActiveEntity] = []
|
||||||
|
@ -25,7 +37,7 @@ enum MastodonStatusContent {
|
||||||
case .url:
|
case .url:
|
||||||
guard let href = entity.href else { continue }
|
guard let href = entity.href else { continue }
|
||||||
let text = String(entity.text)
|
let text = String(entity.text)
|
||||||
activeEntities.append(ActiveEntity(range: range, type: .url(text, trimmed: entity.hrefEllipsis ?? text, url: href)))
|
activeEntities.append(ActiveEntity(range: range, type: .url(text, trimmed: entity.hrefEllipsis ?? text, url: href, userInfo: nil)))
|
||||||
case .hashtag:
|
case .hashtag:
|
||||||
var userInfo: [AnyHashable: Any] = [:]
|
var userInfo: [AnyHashable: Any] = [:]
|
||||||
entity.href.flatMap { href in
|
entity.href.flatMap { href in
|
||||||
|
@ -40,30 +52,47 @@ enum MastodonStatusContent {
|
||||||
}
|
}
|
||||||
let mention = String(entity.text).deletingPrefix("@")
|
let mention = String(entity.text).deletingPrefix("@")
|
||||||
activeEntities.append(ActiveEntity(range: range, type: .mention(mention, userInfo: userInfo)))
|
activeEntities.append(ActiveEntity(range: range, type: .mention(mention, userInfo: userInfo)))
|
||||||
default:
|
case .emoji:
|
||||||
|
var userInfo: [AnyHashable: Any] = [:]
|
||||||
|
guard let href = entity.href else { continue }
|
||||||
|
userInfo["href"] = href
|
||||||
|
let emoji = String(entity.text)
|
||||||
|
activeEntities.append(ActiveEntity(range: range, type: .emoji(emoji, url: href, userInfo: userInfo)))
|
||||||
|
case .none:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var trimmed = text
|
var trimmed = text
|
||||||
for activeEntity in activeEntities {
|
for activeEntity in activeEntities {
|
||||||
guard case .url = activeEntity.type else { continue }
|
MastodonStatusContent.trimEntity(toot: &trimmed, activeEntity: activeEntity, activeEntities: activeEntities)
|
||||||
MastodonStatusContent.trimEntity(status: &trimmed, activeEntity: activeEntity, activeEntities: activeEntities)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ParseResult(
|
return ParseResult(
|
||||||
document: status,
|
document: document,
|
||||||
original: text,
|
original: text,
|
||||||
trimmed: trimmed,
|
trimmed: trimmed,
|
||||||
activeEntities: validate(text: trimmed, activeEntities: activeEntities) ? activeEntities : []
|
activeEntities: activeEntities
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func trimEntity(status: inout String, activeEntity: ActiveEntity, activeEntities: [ActiveEntity]) {
|
static func trimEntity(toot: inout String, activeEntity: ActiveEntity, activeEntities: [ActiveEntity]) {
|
||||||
guard case let .url(text, trimmed, _, _) = activeEntity.type else { return }
|
let text: String
|
||||||
|
let trimmed: String
|
||||||
|
switch activeEntity.type {
|
||||||
|
case .url(let _text, let _trimmed, _, _):
|
||||||
|
text = _text
|
||||||
|
trimmed = _trimmed
|
||||||
|
case .emoji(let _text, _, _):
|
||||||
|
text = _text
|
||||||
|
trimmed = " "
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
guard let index = activeEntities.firstIndex(where: { $0.range == activeEntity.range }) else { return }
|
guard let index = activeEntities.firstIndex(where: { $0.range == activeEntity.range }) else { return }
|
||||||
guard let range = Range(activeEntity.range, in: status) else { return }
|
guard let range = Range(activeEntity.range, in: toot) else { return }
|
||||||
status.replaceSubrange(range, with: trimmed)
|
toot.replaceSubrange(range, with: trimmed)
|
||||||
|
|
||||||
let offset = trimmed.count - text.count
|
let offset = trimmed.count - text.count
|
||||||
activeEntity.range.length += offset
|
activeEntity.range.length += offset
|
||||||
|
@ -74,19 +103,6 @@ enum MastodonStatusContent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func validate(text: String, activeEntities: [ActiveEntity]) -> Bool {
|
|
||||||
for activeEntity in activeEntities {
|
|
||||||
let count = text.utf16.count
|
|
||||||
let endIndex = activeEntity.range.location + activeEntity.range.length
|
|
||||||
guard endIndex <= count else {
|
|
||||||
assertionFailure("Please file issue")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension String {
|
extension String {
|
||||||
|
@ -106,6 +122,7 @@ extension MastodonStatusContent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extension MastodonStatusContent {
|
extension MastodonStatusContent {
|
||||||
|
|
||||||
class Node {
|
class Node {
|
||||||
|
@ -154,6 +171,10 @@ extension MastodonStatusContent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _classNames.contains("emoji") {
|
||||||
|
return .emoji
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}()
|
}()
|
||||||
self.level = level
|
self.level = level
|
||||||
|
@ -257,6 +278,7 @@ extension MastodonStatusContent.Node {
|
||||||
case url
|
case url
|
||||||
case mention
|
case mention
|
||||||
case hashtag
|
case hashtag
|
||||||
|
case emoji
|
||||||
}
|
}
|
||||||
|
|
||||||
static func entities(in node: MastodonStatusContent.Node) -> [MastodonStatusContent.Node] {
|
static func entities(in node: MastodonStatusContent.Node) -> [MastodonStatusContent.Node] {
|
||||||
|
|
|
@ -175,7 +175,7 @@ extension ProfileHeaderViewController {
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] isEditing, note, editingNote in
|
.sink { [weak self] isEditing, note, editingNote in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.profileHeaderView.bioActiveLabel.configure(note: note ?? "")
|
self.profileHeaderView.bioActiveLabel.configure(note: note ?? "", emojiDict: [:]) // FIXME: custom emoji
|
||||||
self.profileHeaderView.bioTextEditorView.text = editingNote ?? ""
|
self.profileHeaderView.bioTextEditorView.text = editingNote ?? ""
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
|
@ -20,7 +20,7 @@ final class ProfileFieldView: UIView {
|
||||||
|
|
||||||
let valueActiveLabel: ActiveLabel = {
|
let valueActiveLabel: ActiveLabel = {
|
||||||
let label = ActiveLabel(style: .profileField)
|
let label = ActiveLabel(style: .profileField)
|
||||||
label.configure(content: "value")
|
label.configure(content: "value", emojiDict: [:])
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ class SettingsViewController: UIViewController, NeedsDependency {
|
||||||
|
|
||||||
let label = ActiveLabel(style: .default)
|
let label = ActiveLabel(style: .default)
|
||||||
label.textAlignment = .center
|
label.textAlignment = .center
|
||||||
label.configure(content: "Mastodon is open source software. You can contribute or report issues on GitHub at <a href=\"https://github.com/tootsuite/mastodon\">tootsuite/mastodon</a> (v3.3.0).")
|
label.configure(content: "Mastodon is open source software. You can contribute or report issues on GitHub at <a href=\"https://github.com/tootsuite/mastodon\">tootsuite/mastodon</a> (v3.3.0).", emojiDict: [:])
|
||||||
label.delegate = self
|
label.delegate = self
|
||||||
|
|
||||||
view.addArrangedSubview(label)
|
view.addArrangedSubview(label)
|
||||||
|
|
|
@ -11,7 +11,7 @@ import AVKit
|
||||||
import ActiveLabel
|
import ActiveLabel
|
||||||
import AlamofireImage
|
import AlamofireImage
|
||||||
|
|
||||||
protocol StatusViewDelegate: class {
|
protocol StatusViewDelegate: AnyObject {
|
||||||
func statusView(_ statusView: StatusView, headerInfoLabelDidPressed label: UILabel)
|
func statusView(_ statusView: StatusView, headerInfoLabelDidPressed label: UILabel)
|
||||||
func statusView(_ statusView: StatusView, avatarButtonDidPressed button: UIButton)
|
func statusView(_ statusView: StatusView, avatarButtonDidPressed button: UIButton)
|
||||||
func statusView(_ statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton)
|
func statusView(_ statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton)
|
||||||
|
@ -69,10 +69,8 @@ final class StatusView: UIView {
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
let headerInfoLabel: UILabel = {
|
let headerInfoLabel: ActiveLabel = {
|
||||||
let label = UILabel()
|
let label = ActiveLabel(style: .statusHeader)
|
||||||
label.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .medium))
|
|
||||||
label.textColor = Asset.Colors.Label.secondary.color
|
|
||||||
label.text = "Bob reblogged"
|
label.text = "Bob reblogged"
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
@ -87,10 +85,8 @@ final class StatusView: UIView {
|
||||||
}()
|
}()
|
||||||
let avatarStackedContainerButton: AvatarStackContainerButton = AvatarStackContainerButton()
|
let avatarStackedContainerButton: AvatarStackContainerButton = AvatarStackContainerButton()
|
||||||
|
|
||||||
let nameLabel: UILabel = {
|
let nameLabel: ActiveLabel = {
|
||||||
let label = UILabel()
|
let label = ActiveLabel(style: .statusName)
|
||||||
label.font = .systemFont(ofSize: 17, weight: .semibold)
|
|
||||||
label.textColor = Asset.Colors.Label.primary.color
|
|
||||||
label.text = "Alice"
|
label.text = "Alice"
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -89,9 +89,6 @@ extension APIService.CoreData {
|
||||||
let metions = entity.mentions?.enumerated().compactMap { index, mention -> Mention in
|
let metions = entity.mentions?.enumerated().compactMap { index, mention -> Mention in
|
||||||
Mention.insert(into: managedObjectContext, property: Mention.Property(id: mention.id, username: mention.username, acct: mention.acct, url: mention.url), index: index)
|
Mention.insert(into: managedObjectContext, property: Mention.Property(id: mention.id, username: mention.username, acct: mention.acct, url: mention.url), index: index)
|
||||||
}
|
}
|
||||||
let emojis = entity.emojis?.compactMap { emoji -> Emoji in
|
|
||||||
Emoji.insert(into: managedObjectContext, property: Emoji.Property(shortcode: emoji.shortcode, url: emoji.url, staticURL: emoji.staticURL, visibleInPicker: emoji.visibleInPicker, category: emoji.category))
|
|
||||||
}
|
|
||||||
let tags = entity.tags?.compactMap { tag -> Tag in
|
let tags = entity.tags?.compactMap { tag -> Tag in
|
||||||
let histories = tag.history?.compactMap { history -> History in
|
let histories = tag.history?.compactMap { history -> History in
|
||||||
History.insert(into: managedObjectContext, property: History.Property(day: history.day, uses: history.uses, accounts: history.accounts))
|
History.insert(into: managedObjectContext, property: History.Property(day: history.day, uses: history.uses, accounts: history.accounts))
|
||||||
|
@ -121,7 +118,6 @@ extension APIService.CoreData {
|
||||||
replyTo: replyTo,
|
replyTo: replyTo,
|
||||||
poll: poll,
|
poll: poll,
|
||||||
mentions: metions,
|
mentions: metions,
|
||||||
emojis: emojis,
|
|
||||||
tags: tags,
|
tags: tags,
|
||||||
mediaAttachments: mediaAttachments,
|
mediaAttachments: mediaAttachments,
|
||||||
favouritedBy: (entity.favourited ?? false) ? requestMastodonUser : nil,
|
favouritedBy: (entity.favourited ?? false) ? requestMastodonUser : nil,
|
||||||
|
|
Loading…
Reference in New Issue